Issue ROO-954: Support for transmitting stack traces for sever exceptions. Review at http://gwt-code-reviews.appspot.com/886801 Review by: amitmanjhi@google.com git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8808 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java b/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java index d9e3b79..90e781f 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java
@@ -102,7 +102,9 @@ public void handleResponseText(String responseText) { JsonResults results = JsonResults.fromResults(responseText); if (results.getException() != null) { - receiver.onFailure(new ServerFailure(results.getException())); + ServerFailureRecord cause = results.getException(); + receiver.onFailure(new ServerFailure( + cause.getMessage(), cause.getType(), cause.getTrace())); return; } processRelated(results.getRelated());
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/JsonResults.java b/user/src/com/google/gwt/requestfactory/client/impl/JsonResults.java index 74be2c5..a39db1e 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/JsonResults.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/JsonResults.java
@@ -32,7 +32,7 @@ protected JsonResults() { } - public final native String getException() /*-{ + public final native ServerFailureRecord getException() /*-{ return this.exception || null; }-*/;
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ServerFailureRecord.java b/user/src/com/google/gwt/requestfactory/client/impl/ServerFailureRecord.java new file mode 100644 index 0000000..1042c35 --- /dev/null +++ b/user/src/com/google/gwt/requestfactory/client/impl/ServerFailureRecord.java
@@ -0,0 +1,39 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.requestfactory.client.impl; + +import com.google.gwt.core.client.JavaScriptObject; + +/** + * Contains details of a server error. + */ +public final class ServerFailureRecord extends JavaScriptObject { + + protected ServerFailureRecord() { + } + + public native String getMessage() /*-{ + return this.message || ""; + }-*/; + + public native String getTrace() /*-{ + return this.trace || ""; + }-*/; + + public native String getType() /*-{ + return this.type || ""; + }-*/; +}
diff --git a/user/src/com/google/gwt/requestfactory/server/DefaultExceptionHandler.java b/user/src/com/google/gwt/requestfactory/server/DefaultExceptionHandler.java new file mode 100644 index 0000000..344b622 --- /dev/null +++ b/user/src/com/google/gwt/requestfactory/server/DefaultExceptionHandler.java
@@ -0,0 +1,30 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.requestfactory.server; + +import com.google.gwt.requestfactory.shared.ServerFailure; + +/** + * Default implementation for handling exceptions thrown while + * processing a request. Suppresses stack traces and the exception + * class name. + */ +public class DefaultExceptionHandler implements ExceptionHandler { + public ServerFailure createServerFailure(Throwable throwable) { + return new ServerFailure("Server Error: " + throwable.getMessage(), null, + null); + } +} \ No newline at end of file
diff --git a/user/src/com/google/gwt/requestfactory/server/ExceptionHandler.java b/user/src/com/google/gwt/requestfactory/server/ExceptionHandler.java new file mode 100644 index 0000000..9225a95 --- /dev/null +++ b/user/src/com/google/gwt/requestfactory/server/ExceptionHandler.java
@@ -0,0 +1,31 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.requestfactory.server; + +import com.google.gwt.requestfactory.shared.ServerFailure; + +/** + * Handles an exception produced while processing a request. + */ +public interface ExceptionHandler { + /** + * Generates a {@link ServerFailure} based on the information + * contained in the received {@code exception}. + * + * @see DefaultExceptionHandler + */ + ServerFailure createServerFailure(Throwable throwable); +}
diff --git a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java index 5d1e767..30d5e6c 100644 --- a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java +++ b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
@@ -18,6 +18,7 @@ import com.google.gwt.requestfactory.shared.EntityProxy; import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.ProxyFor; +import com.google.gwt.requestfactory.shared.ServerFailure; import com.google.gwt.requestfactory.shared.WriteOperation; import com.google.gwt.requestfactory.shared.impl.Property; import com.google.gwt.requestfactory.shared.impl.RequestData; @@ -131,6 +132,8 @@ private OperationRegistry operationRegistry; + private ExceptionHandler exceptionHandler; + /* * <li>Request comes in. Construct the involvedKeys, dvsDataMap and * beforeDataMap, using DVS and parameters. @@ -166,13 +169,12 @@ Logger.getLogger(this.getClass().getName()).finest("Outgoing response " + response); return response; + } catch (InvocationTargetException e) { + JSONObject exceptionResponse = buildExceptionResponse(e.getCause()); + throw new RequestProcessingException("Unexpected exception", e, + exceptionResponse.toString()); } catch (Exception e) { - JSONObject exceptionResponse = new JSONObject(); - try { - exceptionResponse.put("exception", "Server error"); - } catch (JSONException jsonException) { - throw new IllegalStateException(jsonException); - } + JSONObject exceptionResponse = buildExceptionResponse(e); throw new RequestProcessingException("Unexpected exception", e, exceptionResponse.toString()); } @@ -759,6 +761,10 @@ return envelop; } + public void setExceptionHandler(ExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + public void setOperationRegistry(OperationRegistry operationRegistry) { this.operationRegistry = operationRegistry; } @@ -819,6 +825,32 @@ propertyContext)); } + private JSONObject buildExceptionResponse(Throwable throwable) { + JSONObject exceptionResponse = new JSONObject(); + ServerFailure failure = exceptionHandler.createServerFailure(throwable); + try { + JSONObject exceptionMessage = new JSONObject(); + + String message = failure.getMessage(); + String exceptionType = failure.getExceptionType(); + String stackTraceString = failure.getStackTraceString(); + + if (message != null && message.length() != 0) { + exceptionMessage.put("message", message); + } + if (exceptionType != null && exceptionType.length() != 0) { + exceptionMessage.put("type", exceptionType); + } + if (stackTraceString != null && stackTraceString.length() != 0) { + exceptionMessage.put("trace", stackTraceString); + } + exceptionResponse.put("exception", exceptionMessage); + } catch (JSONException jsonException) { + throw new IllegalStateException(jsonException); + } + return exceptionResponse; + } + @SuppressWarnings("unchecked") private Class<? extends EntityProxy> castToRecordClass(Class<?> propertyType) { return (Class<? extends EntityProxy>) propertyType;
diff --git a/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java b/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java index f3592f6..eef67b8 100644 --- a/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java +++ b/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
@@ -75,6 +75,20 @@ return perThreadResponse.get(); } + private final ExceptionHandler exceptionHandler; + + public RequestFactoryServlet() { + this(new DefaultExceptionHandler()); + } + + /** + * Use this constructor in subclasses to provide a custom + * {@link ExceptionHandler}. + */ + public RequestFactoryServlet(ExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { @@ -102,6 +116,7 @@ RequestProcessor<String> requestProcessor = new JsonRequestProcessor(); requestProcessor.setOperationRegistry(new ReflectionBasedOperationRegistry( new DefaultSecurityProvider())); + requestProcessor.setExceptionHandler(exceptionHandler); response.setHeader("Content-Type", RequestFactory.JSON_CONTENT_TYPE_UTF8); writer.print(requestProcessor.decodeAndInvokeRequest(jsonRequestString));
diff --git a/user/src/com/google/gwt/requestfactory/server/RequestProcessor.java b/user/src/com/google/gwt/requestfactory/server/RequestProcessor.java index d408f15..93dd64e 100644 --- a/user/src/com/google/gwt/requestfactory/server/RequestProcessor.java +++ b/user/src/com/google/gwt/requestfactory/server/RequestProcessor.java
@@ -28,6 +28,15 @@ T decodeAndInvokeRequest(T encodedRequest) throws RequestProcessingException; /** + * Sets the ExceptionHandler to use to convert exceptions caused by + * method invocations into failure messages sent back to the client. + * + * @param exceptionHandler an implementation, such as + * {@code DefaultExceptionHandler} + */ + void setExceptionHandler(ExceptionHandler exceptionHandler); + + /** * Sets the OperationRegistry to be used for looking up invocation metadata. * * @param registry an implementation, such as
diff --git a/user/src/com/google/gwt/requestfactory/shared/Receiver.java b/user/src/com/google/gwt/requestfactory/shared/Receiver.java index 3f1ad48..957d49c 100644 --- a/user/src/com/google/gwt/requestfactory/shared/Receiver.java +++ b/user/src/com/google/gwt/requestfactory/shared/Receiver.java
@@ -33,7 +33,13 @@ * RuntimeException with the provided error message. */ public void onFailure(ServerFailure error) { - throw new RuntimeException(error.getMessage()); + String exceptionType = error.getExceptionType(); + String message = error.getMessage(); + throw new RuntimeException(exceptionType + + ((exceptionType.length() != 0 && message.length() != 0) ? ": " : "") + + error.getMessage() + + ((exceptionType.length() != 0 || message.length() != 0) ? ": " : "") + + error.getStackTraceString()); } /** @@ -43,13 +49,14 @@ /** * Called if an object sent to the server could not be validated. The default - * implementation calls {@link #onFailure()} if <code>errors</code> is not - * empty. + * implementation calls {@link #onFailure(ServerFailure)} if <code>errors + * </code> is not empty. */ public void onViolation(Set<Violation> errors) { if (!errors.isEmpty()) { onFailure(new ServerFailure( - "The call failed on the server due to a ConstraintViolation")); + "The call failed on the server due to a ConstraintViolation", + "", "")); } } }
diff --git a/user/src/com/google/gwt/requestfactory/shared/ServerFailure.java b/user/src/com/google/gwt/requestfactory/shared/ServerFailure.java index 67eef63..3175f30 100644 --- a/user/src/com/google/gwt/requestfactory/shared/ServerFailure.java +++ b/user/src/com/google/gwt/requestfactory/shared/ServerFailure.java
@@ -20,19 +20,32 @@ */ public class ServerFailure { private final String message; + private final String stackTraceString; + private final String exceptionType; /** * Constructs a ServerFailure with a null message. */ public ServerFailure() { - this(null); + this(null, null, null); } - public ServerFailure(String message) { + public ServerFailure(String message, String exceptionType, + String stackTraceString) { this.message = message; + this.exceptionType = exceptionType; + this.stackTraceString = stackTraceString; + } + + public String getExceptionType() { + return exceptionType; } public String getMessage() { return message; } + + public String getStackTraceString() { + return stackTraceString; + } }
diff --git a/user/test/com/google/gwt/requestfactory/RequestFactoryExceptionHandlerTest.gwt.xml b/user/test/com/google/gwt/requestfactory/RequestFactoryExceptionHandlerTest.gwt.xml new file mode 100644 index 0000000..39c7db2 --- /dev/null +++ b/user/test/com/google/gwt/requestfactory/RequestFactoryExceptionHandlerTest.gwt.xml
@@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.0.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.0.1/distro-source/core/src/gwt-module.dtd"> +<!-- + Copyright 2010 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); you may not + use this file except in compliance with the License. You may obtain a copy of + the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + License for the specific language governing permissions and limitations under + the License. +--> +<module> + <inherits name='com.google.gwt.requestfactory.RequestFactory'/> + <!-- use this old inefficient JSON library just for the time being, replace soon --> + <inherits name='com.google.gwt.junit.JUnit'/> + <inherits name='com.google.gwt.json.JSON'/> + <servlet path='/gwtRequest' + class='com.google.gwt.requestfactory.server.RequestFactoryExceptionHandlerServlet' /> +</module>
diff --git a/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java b/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java index 124550f..c04d1f4 100644 --- a/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java +++ b/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
@@ -18,6 +18,7 @@ import com.google.gwt.junit.tools.GWTTestSuite; import com.google.gwt.requestfactory.client.EditorTest; import com.google.gwt.requestfactory.client.FindServiceTest; +import com.google.gwt.requestfactory.client.RequestFactoryExceptionHandlerTest; import com.google.gwt.requestfactory.client.RequestFactoryTest; import com.google.gwt.requestfactory.client.impl.DeltaValueStoreJsonImplTest; import com.google.gwt.requestfactory.client.impl.ProxyJsoImplTest; @@ -37,6 +38,7 @@ suite.addTestSuite(ValueStoreJsonImplTest.class); suite.addTestSuite(DeltaValueStoreJsonImplTest.class); suite.addTestSuite(RequestFactoryTest.class); + suite.addTestSuite(RequestFactoryExceptionHandlerTest.class); suite.addTestSuite(FindServiceTest.class); return suite; }
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryExceptionHandlerTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryExceptionHandlerTest.java new file mode 100644 index 0000000..e3ba01e --- /dev/null +++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryExceptionHandlerTest.java
@@ -0,0 +1,71 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.requestfactory.client; + +import com.google.gwt.requestfactory.shared.Receiver; +import com.google.gwt.requestfactory.shared.RequestObject; +import com.google.gwt.requestfactory.shared.ServerFailure; +import com.google.gwt.requestfactory.shared.SimpleFooProxy; +import com.google.gwt.requestfactory.shared.SyncResult; +import com.google.gwt.requestfactory.shared.Violation; + +import java.util.Set; + +/** + * Tests that {@code RequestFactoryServlet} when using a custom + * ExceptionHandler. + */ +public class RequestFactoryExceptionHandlerTest extends RequestFactoryTest { + + @Override + public String getModuleName() { + return "com.google.gwt.requestfactory.RequestFactoryExceptionHandlerTest"; + } + + @Override + public void testServerFailure() { + delayTestFinish(5000); + + SimpleFooProxy rayFoo = req.create(SimpleFooProxy.class); + final RequestObject<SimpleFooProxy> persistRay = req.simpleFooRequest().persistAndReturnSelf( + rayFoo); + rayFoo = persistRay.edit(rayFoo); + // 42 is the crash causing magic number + rayFoo.setPleaseCrash(42); + + persistRay.fire(new Receiver<SimpleFooProxy>() { + @Override + public void onFailure(ServerFailure error) { + assertEquals("test message", error.getMessage()); + assertEquals("java.lang.UnsupportedOperationException", + error.getExceptionType()); + assertFalse(error.getStackTraceString().isEmpty()); + finishTestAndReset(); + } + + @Override + public void onViolation(Set<Violation> errors) { + fail("Failure expected but onViolation() was called"); + } + + public void onSuccess(SimpleFooProxy response, + Set<SyncResult> syncResult) { + fail("Failure expected but onSuccess() was called"); + } + }); + } + +}
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java index 13755ec..b40edef 100644 --- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java +++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
@@ -20,6 +20,7 @@ import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.Receiver; import com.google.gwt.requestfactory.shared.RequestObject; +import com.google.gwt.requestfactory.shared.ServerFailure; import com.google.gwt.requestfactory.shared.SimpleBarProxy; import com.google.gwt.requestfactory.shared.SimpleFooProxy; import com.google.gwt.requestfactory.shared.SyncResult; @@ -460,6 +461,37 @@ }); } + public void testServerFailure() { + delayTestFinish(5000); + + SimpleFooProxy rayFoo = req.create(SimpleFooProxy.class); + final RequestObject<SimpleFooProxy> persistRay = req.simpleFooRequest().persistAndReturnSelf( + rayFoo); + rayFoo = persistRay.edit(rayFoo); + // 42 is the crash causing magic number + rayFoo.setPleaseCrash(42); + + persistRay.fire(new Receiver<SimpleFooProxy>() { + @Override + public void onFailure(ServerFailure error) { + assertEquals("Server Error: test message", error.getMessage()); + assertEquals("", error.getExceptionType()); + assertEquals("", error.getStackTraceString()); + finishTestAndReset(); + } + + @Override + public void onViolation(Set<Violation> errors) { + fail("Failure expected but onViolation() was called"); + } + + public void onSuccess(SimpleFooProxy response, + Set<SyncResult> syncResult) { + fail("Failure expected but onSuccess() was called"); + } + }); + } + public void testStableId() { delayTestFinish(5000);
diff --git a/user/test/com/google/gwt/requestfactory/client/impl/SimpleFooProxyProperties.java b/user/test/com/google/gwt/requestfactory/client/impl/SimpleFooProxyProperties.java index cbd9ee1..07ba06b 100644 --- a/user/test/com/google/gwt/requestfactory/client/impl/SimpleFooProxyProperties.java +++ b/user/test/com/google/gwt/requestfactory/client/impl/SimpleFooProxyProperties.java
@@ -68,4 +68,6 @@ static final Property<SimpleFooProxy> fooField = new Property<SimpleFooProxy>( "fooField", SimpleFooProxy.class); + + static final Property<Integer> pleaseCrash = new Property<Integer>("pleaseCrash", Integer.class); } \ No newline at end of file
diff --git a/user/test/com/google/gwt/requestfactory/server/RequestFactoryExceptionHandlerServlet.java b/user/test/com/google/gwt/requestfactory/server/RequestFactoryExceptionHandlerServlet.java new file mode 100644 index 0000000..689e0d0 --- /dev/null +++ b/user/test/com/google/gwt/requestfactory/server/RequestFactoryExceptionHandlerServlet.java
@@ -0,0 +1,34 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.requestfactory.server; + +import com.google.gwt.requestfactory.shared.ServerFailure; + +/** + * A RequestFactoryServlet that forwards all exception information. + */ +public class RequestFactoryExceptionHandlerServlet + extends RequestFactoryServlet { + public RequestFactoryExceptionHandlerServlet() { + super(new ExceptionHandler() { + @Override + public ServerFailure createServerFailure(Throwable throwable) { + return new ServerFailure(throwable.getMessage(), + throwable.getClass().getName(), "my stack trace"); + } + }); + } +}
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java index 4b25282..f8fdf2c 100644 --- a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java +++ b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
@@ -125,6 +125,7 @@ private Boolean boolField; private Boolean otherBoolField; + private Integer pleaseCrashField; private SimpleBar barField; private SimpleFoo fooField; @@ -143,6 +144,7 @@ boolField = true; nullField = null; barNullField = null; + pleaseCrashField = 0; } public Long countSimpleFooWithUserNameSideEffect() { @@ -243,6 +245,10 @@ return password; } + public Integer getPleaseCrash() { + return pleaseCrashField; + } + /** * @return the shortField */ @@ -360,6 +366,13 @@ this.otherBoolField = otherBoolField; } + public void setPleaseCrash(Integer crashIf42) { + if (crashIf42 == 42) { + throw new UnsupportedOperationException("test message"); + } + pleaseCrashField = crashIf42; + } + public void setPassword(String password) { this.password = password; }
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleFooProxy.java b/user/test/com/google/gwt/requestfactory/shared/SimpleFooProxy.java index 6a22760..1a8e839 100644 --- a/user/test/com/google/gwt/requestfactory/shared/SimpleFooProxy.java +++ b/user/test/com/google/gwt/requestfactory/shared/SimpleFooProxy.java
@@ -59,6 +59,8 @@ Boolean getOtherBoolField(); + Integer getPleaseCrash(); + String getPassword(); Short getShortField(); @@ -97,6 +99,8 @@ void setPassword(String password); + void setPleaseCrash(Integer dummy); + void setShortField(Short s); void setUserName(String userName);