Adding more unit tests to RequestFactoryTest. Refactoring SimpleFoo to use a HashMap to store records instead of a singleton.
Review at http://gwt-code-reviews.appspot.com/931802
Review by: rjrjr@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8909 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ClientRequestHelper.java b/user/src/com/google/gwt/requestfactory/client/impl/ClientRequestHelper.java
index 0a1305e..dcd532a 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/ClientRequestHelper.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/ClientRequestHelper.java
@@ -43,7 +43,7 @@
// TODO(jgw): Find a better way to do this. Occasionally a js-wrapped
// string ends up in 'value', which breaks the json2.js implementation
// of JSON.stringify().
- this[key] = String(value);
+ this[key] = (value == null) ? null : String(value);
}-*/;
private native String toJsonString()/*-{
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java
index 4685f7b..fc277b4 100644
--- a/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java
+++ b/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -96,7 +96,7 @@
* <p>
* If the ProxyImpl is mutable, any EntityProxies reachable from the return
* value will have already been made mutable.
- *
+ *
* @param <V> the type of the property's value
* @param property the property to fetch
* @return the value
@@ -131,13 +131,6 @@
return jso.<V> get(propertyName, propertyType);
}
- public boolean hasChanged() {
- if (deltaValueStore == null) {
- return false;
- }
- return deltaValueStore.isChanged();
- }
-
@Override
public int hashCode() {
return stableId().hashCode() * 13
diff --git a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
index 654f9ba..f50787d 100644
--- a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
+++ b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -196,11 +196,11 @@
/*
* <li>Request comes in. Construct the involvedKeys, dvsDataMap and
* beforeDataMap, using DVS and parameters.
- *
+ *
* <li>Apply the DVS and construct the afterDvsDataMqp.
- *
+ *
* <li>Invoke the method noted in the operation.
- *
+ *
* <li>Find the changes that need to be sent back.
*/
private final Map<EntityKey, Object> cachedEntityLookup = new HashMap<EntityKey, Object>();
@@ -243,6 +243,9 @@
String parameterValue) throws SecurityException, JSONException,
IllegalAccessException, InvocationTargetException, NoSuchMethodException,
InstantiationException {
+ if (parameterValue == null) {
+ return null;
+ }
Class<?> parameterType = null;
if (genericParameterType instanceof Class<?>) {
parameterType = (Class<?>) genericParameterType;
@@ -258,17 +261,15 @@
if (collection != null) {
JSONArray array = new JSONArray(parameterValue);
for (int i = 0; i < array.length(); i++) {
+ String value = array.isNull(i) ? null : array.getString(i);
collection.add(decodeParameterValue(
- pType.getActualTypeArguments()[0], array.getString(i)));
+ pType.getActualTypeArguments()[0], value));
}
return collection;
}
}
}
}
- if (parameterValue == null) {
- return null;
- }
if (String.class == parameterType) {
return parameterValue;
}
@@ -328,7 +329,7 @@
/*
* TODO: 1. Don't resolve in this step, just get EntityKey. May need to
* use DVS.
- *
+ *
* 2. Merge the following and the object resolution code in getEntityKey.
* 3. Update the involvedKeys set.
*/
@@ -342,6 +343,8 @@
entityKey, dvsData.jsonObject, dvsData.writeOperation);
return entityData.entityInstance;
} else {
+ // TODO(rjrjr): This results in a ConcurrentModificationException.
+ // involvedKeys loops in constructAfterDvsDataMapAfterCallingSetters.
involvedKeys.add(entityKey);
return getEntityInstance(entityKey);
}
@@ -354,6 +357,8 @@
throw new IllegalArgumentException("Unknown service, unable to decode "
+ parameterValue);
}
+ // TODO(rjrjr): This results in a ConcurrentModificationException.
+ // involvedKeys loops in constructAfterDvsDataMapAfterCallingSetters.
involvedKeys.add(entityKey);
return getEntityInstance(entityKey);
}
@@ -434,7 +439,7 @@
/**
* Generate an ID for a new record. The default behavior is to return null and
* let the data store generate the ID automatically.
- *
+ *
* @param key the key of the record field
* @return the ID of the new record, or null to auto generate
*/
@@ -579,7 +584,7 @@
/**
* Converts the returnValue of a 'get' method to a JSONArray.
- *
+ *
* @param resultList object returned by a 'get' method, must be of type
* List<?>
* @param entityKeyClass the class type of the contained value
@@ -641,7 +646,7 @@
/**
* Returns methodName corresponding to the propertyName that can be invoked on
* an entity.
- *
+ *
* Example: "userName" returns prefix + "UserName". "version" returns prefix +
* "Version"
*/
@@ -702,7 +707,8 @@
while (keys.hasNext()) {
String key = keys.next().toString();
if (key.startsWith(PARAM_TOKEN)) {
- parameterMap.put(key, jsonObject.getString(key));
+ String value = jsonObject.isNull(key) ? null : jsonObject.getString(key);
+ parameterMap.put(key, value);
}
}
return parameterMap;
@@ -779,7 +785,7 @@
/**
* Returns the property value, in the specified type, from the request object.
* The value is put in the DataStore.
- *
+ *
* @throws InstantiationException
* @throws NoSuchMethodException
* @throws InvocationTargetException
@@ -1026,7 +1032,7 @@
relatedObjects.put(keyRef, null);
Object jsonObject = getJsonObject(returnValue, propertyType,
propertyContext);
- if (jsonObject != JSONObject.NULL) {
+ if (jsonObject != JSONObject.NULL) {
// put real value
relatedObjects.put(keyRef, (JSONObject) jsonObject);
}
@@ -1097,7 +1103,7 @@
/**
* Constructs the beforeDataMap.
- *
+ *
* <p>
* Algorithm: go through the involvedKeys, and find the entityData
* corresponding to each.
@@ -1418,7 +1424,7 @@
/**
* returns true if the property has been requested. TODO: use the properties
* that should be coming with the request.
- *
+ *
* @param p the field of entity ref
* @param propertyContext the root of the current dotted property reference
* @return has the property value been requested
diff --git a/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java b/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java
index f369ce8..5cbdbd1 100644
--- a/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java
+++ b/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java
@@ -127,7 +127,7 @@
private String asJsonString(Object value) {
if (value == null) {
- return "null";
+ return null;
}
if (value instanceof Iterable<?>) {
@@ -140,14 +140,18 @@
} else {
first = false;
}
- toReturn.append(asJsonString(val));
+ if (val == null) {
+ toReturn.append("null");
+ } else {
+ toReturn.append("\"" + asJsonString(val) + "\"");
+ }
}
toReturn.append(']');
return toReturn.toString();
}
if (value instanceof HasWireFormatId) {
- return "\"" + ((HasWireFormatId) value).wireFormatId() + "\"";
+ return ((HasWireFormatId) value).wireFormatId();
}
/*
diff --git a/user/test/com/google/gwt/requestfactory/client/EditorTest.java b/user/test/com/google/gwt/requestfactory/client/EditorTest.java
index 32161dd..46f1684 100644
--- a/user/test/com/google/gwt/requestfactory/client/EditorTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/EditorTest.java
@@ -104,7 +104,7 @@
final SimpleFooDriver driver = GWT.create(SimpleFooDriver.class);
driver.initialize(req, editor);
- req.simpleFooRequest().findSimpleFooById(0L).with(driver.getPaths()).fire(
+ req.simpleFooRequest().findSimpleFooById(1L).with(driver.getPaths()).fire(
new Receiver<SimpleFooProxy>() {
@Override
public void onSuccess(SimpleFooProxy response) {
@@ -143,7 +143,7 @@
assertEquals(Arrays.asList("barField.userName", "barField"),
Arrays.asList(driver.getPaths()));
- req.simpleFooRequest().findSimpleFooById(0L).with(driver.getPaths()).fire(
+ req.simpleFooRequest().findSimpleFooById(1L).with(driver.getPaths()).fire(
new Receiver<SimpleFooProxy>() {
@Override
public void onSuccess(SimpleFooProxy response) {
@@ -190,7 +190,7 @@
final SimpleFooDriver driver = GWT.create(SimpleFooDriver.class);
driver.initialize(req, editor);
- req.simpleFooRequest().findSimpleFooById(0L).with(driver.getPaths()).fire(
+ req.simpleFooRequest().findSimpleFooById(1L).with(driver.getPaths()).fire(
new Receiver<SimpleFooProxy>() {
@Override
public void onSuccess(SimpleFooProxy response) {
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
index ebb77d9..07ac4dc 100644
--- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -113,7 +113,7 @@
public void onSuccess(T response) {
/*
* Make sure your class path includes:
- *
+ *
* tools/lib/apache/log4j/log4j-1.2.16.jar
* tools/lib/hibernate/validator/hibernate-validator-4.1.0.Final.jar
* tools/lib/slf4j/slf4j-api/slf4j-api-1.6.1.jar
@@ -184,6 +184,38 @@
return "com.google.gwt.requestfactory.RequestFactorySuite";
}
+ /**
+ * Test that we can commit child objects.
+ *
+ * TODO: Causes a ConcurrentModificationException
+ */
+ public void disabledTestCascadingCommit() {
+ delayTestFinish(5000);
+ final SimpleFooProxy foo = req.create(SimpleFooProxy.class);
+ final SimpleBarProxy bar0 = req.create(SimpleBarProxy.class);
+ final SimpleBarProxy bar1 = req.create(SimpleBarProxy.class);
+ List<SimpleBarProxy> bars = new ArrayList<SimpleBarProxy>();
+ bars.add(bar0);
+ bars.add(bar1);
+
+ final SimpleFooEventHandler<SimpleBarProxy> handler = new SimpleFooEventHandler<SimpleBarProxy>();
+ EntityProxyChange.registerForProxyType(req.getEventBus(),
+ SimpleBarProxy.class, handler);
+
+ Request<SimpleFooProxy> request = req.simpleFooRequest().persistCascadingAndReturnSelf(foo);
+ SimpleFooProxy editFoo = request.edit(foo);
+ editFoo.setOneToManyField(bars);
+ request.fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ assertFalse(((ProxyImpl) response).unpersisted());
+ assertEquals(2, handler.persistEventCount); // two bars persisted.
+ assertEquals(2, handler.totalEventCount);
+ finishTestAndReset();
+ }
+ });
+ }
+
public void testClassToken() {
String token = req.getHistoryToken(SimpleFooProxy.class);
assertEquals(SimpleFooProxy.class, req.getProxyClass(token));
@@ -383,7 +415,7 @@
new Receiver<List<SimpleFooProxy>>() {
@Override
public void onSuccess(List<SimpleFooProxy> response) {
- assertEquals(1, response.size());
+ assertEquals(2, response.size());
for (SimpleFooProxy foo : response) {
assertNotNull(foo.stableId());
assertEquals("FOO", foo.getBarField().getUserName());
@@ -451,6 +483,125 @@
}
/**
+ * Test that a null value can be sent in a request.
+ */
+ public void testNullListRequest() {
+ delayTestFinish(5000);
+ final Request<Void> fooReq = req.simpleFooRequest().receiveNullList(null);
+ fooReq.fire(new Receiver<Void>() {
+ @Override
+ public void onSuccess(Void v) {
+ finishTestAndReset();
+ }
+ });
+ }
+
+ /**
+ * Test that a null value can be sent in a request.
+ */
+ public void disabledTestNullSimpleFooRequest() {
+ delayTestFinish(5000);
+ final Request<Void> fooReq = req.simpleFooRequest().receiveNullSimpleFoo(null);
+ fooReq.fire(new Receiver<Void>() {
+ @Override
+ public void onSuccess(Void v) {
+ finishTestAndReset();
+ }
+ });
+ }
+
+ /**
+ * Test that a null value can be sent to an instance method.
+ */
+ public void testNullStringInstanceRequest() {
+ delayTestFinish(5000);
+
+ // Get a valid proxy entity.
+ req.simpleFooRequest().findSimpleFooById(999L).fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ final Request<Void> fooReq = req.simpleFooRequest().receiveNull(response, null);
+ fooReq.fire(new Receiver<Void>() {
+ @Override
+ public void onSuccess(Void v) {
+ finishTestAndReset();
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Test that a null value can be sent in a request.
+ */
+ public void testNullStringRequest() {
+ delayTestFinish(5000);
+ final Request<Void> fooReq = req.simpleFooRequest().receiveNullString(null);
+ fooReq.fire(new Receiver<Void>() {
+ @Override
+ public void onSuccess(Void v) {
+ finishTestAndReset();
+ }
+ });
+ }
+
+ /**
+ * Test that a null value can be sent within a list of entities.
+ */
+ public void testNullValueInEntityListRequest() {
+ delayTestFinish(5000);
+
+ // Get a valid proxy entity.
+ req.simpleFooRequest().findSimpleFooById(999L).fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ List<SimpleFooProxy> list = new ArrayList<SimpleFooProxy>();
+ list.add(response); // non-null
+ list.add(null); // null
+ final Request<Void> fooReq = req.simpleFooRequest().receiveNullValueInEntityList(list);
+ fooReq.fire(new Receiver<Void>() {
+ @Override
+ public void onSuccess(Void v) {
+ finishTestAndReset();
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Test that a null value can be sent within a list of objects.
+ */
+ public void testNullValueInIntegerListRequest() {
+ delayTestFinish(5000);
+ List<Integer> list = Arrays.asList(new Integer[]{1, 2, null});
+ final Request<Void> fooReq = req.simpleFooRequest().receiveNullValueInIntegerList(
+ list);
+ fooReq.fire(new Receiver<Void>() {
+ @Override
+ public void onSuccess(Void v) {
+ finishTestAndReset();
+ }
+ });
+ }
+
+ /**
+ * Test that a null value can be sent within a list of strings.
+ */
+ public void testNullValueInStringListRequest() {
+ delayTestFinish(5000);
+ List<String> list = Arrays.asList(new String[]{"nonnull", "null", null});
+ final Request<Void> fooReq = req.simpleFooRequest().receiveNullValueInStringList(
+ list);
+ fooReq.fire(new Receiver<Void>() {
+ @Override
+ public void onSuccess(Void v) {
+ finishTestAndReset();
+ }
+ });
+ }
+
+ /**
* Ensures that a service method can respond with a null value.
*/
public void testNullListResult() {
@@ -501,7 +652,7 @@
@Override
public void onSuccess(Long response) {
assertCannotFire(mutateRequest);
- assertEquals(new Long(1L), response);
+ assertEquals(new Long(2L), response);
assertEquals(2, handler.updateEventCount);
assertEquals(2, handler.totalEventCount);
@@ -531,6 +682,63 @@
});
}
+ /**
+ * Test that removing a parent entity and implicitly removing the child sends
+ * an event to the client that the child was removed.
+ *
+ * TODO(rjrjr): Should cascading deletes be detected?
+ */
+ public void disableTestMethodWithSideEffectDeleteChild() {
+ delayTestFinish(5000);
+
+ // Persist bar.
+ final SimpleBarProxy bar = req.create(SimpleBarProxy.class);
+ req.simpleBarRequest().persistAndReturnSelf(bar).fire(new Receiver<SimpleBarProxy>() {
+ @Override
+ public void onSuccess(SimpleBarProxy persistentBar) {
+ // Persist foo with bar as a child.
+ SimpleFooProxy foo = req.create(SimpleFooProxy.class);
+ final Request<SimpleFooProxy> persistRequest =
+ req.simpleFooRequest().persistAndReturnSelf(foo);
+ foo = persistRequest.edit(foo);
+ foo.setUserName("John");
+ foo.setBarField(bar);
+ persistRequest.fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy persistentFoo) {
+ // Handle changes to SimpleFooProxy.
+ final SimpleFooEventHandler<SimpleFooProxy> fooHandler =
+ new SimpleFooEventHandler<SimpleFooProxy>();
+ EntityProxyChange.registerForProxyType(
+ req.getEventBus(), SimpleFooProxy.class, fooHandler);
+
+ // Handle changes to SimpleBarProxy.
+ final SimpleFooEventHandler<SimpleBarProxy> barHandler =
+ new SimpleFooEventHandler<SimpleBarProxy>();
+ EntityProxyChange.registerForProxyType(
+ req.getEventBus(), SimpleBarProxy.class, barHandler);
+
+ // Delete bar.
+ final Request<Void> deleteRequest = req.simpleFooRequest().deleteBar(persistentFoo);
+ SimpleFooProxy editable = deleteRequest.edit(persistentFoo);
+ editable.setBarField(bar);
+ deleteRequest.fire(new Receiver<Void>() {
+ @Override
+ public void onSuccess(Void response) {
+ assertEquals(1, fooHandler.updateEventCount); // set bar to null
+ assertEquals(1, fooHandler.totalEventCount);
+
+ assertEquals(1, barHandler.deleteEventCount); // deleted bar
+ assertEquals(1, barHandler.totalEventCount);
+ finishTestAndReset();
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
/*
* TODO: all these tests should check the final values. It will be easy when
* we have better persistence than the singleton pattern.
@@ -709,7 +917,7 @@
fooReq2.fire(new Receiver<Void>() {
@Override
public void onSuccess(Void response) {
- req.simpleFooRequest().findSimpleFooById(999L).with(
+ req.simpleFooRequest().findSimpleFooById(persistedFoo.getId()).with(
"barField.userName").fire(new Receiver<SimpleFooProxy>() {
@Override
public void onSuccess(SimpleFooProxy finalFooProxy) {
diff --git a/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java b/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java
index b6ad267..8f98ea1 100644
--- a/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java
+++ b/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java
@@ -130,7 +130,7 @@
JSONObject result = getResultFromServer(foo);
// check modified fields and no violations
- SimpleFoo fooResult = SimpleFoo.getSingleton();
+ SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
JSONArray updateArray = result.getJSONObject("sideEffects").getJSONArray(
"UPDATE");
assertEquals(1, updateArray.length());
@@ -152,7 +152,7 @@
JSONObject foo = fetchVerifyAndGetInitialObject();
// change the value on the server behind the back
- SimpleFoo fooResult = SimpleFoo.getSingleton();
+ SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
fooResult.setUserName("JSC");
fooResult.setIntId(45);
@@ -163,7 +163,7 @@
// check modified fields and no violations
assertFalse(result.getJSONObject("sideEffects").has("UPDATE"));
- fooResult = SimpleFoo.getSingleton();
+ fooResult = SimpleFoo.findSimpleFooById(999L);
assertEquals(45, (int) fooResult.getIntId());
assertEquals("JSC", fooResult.getUserName());
}
@@ -174,7 +174,7 @@
JSONObject foo = fetchVerifyAndGetInitialObject();
// change some fields but don't change other fields.
- SimpleFoo fooResult = SimpleFoo.getSingleton();
+ SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
fooResult.setUserName("JSC");
fooResult.setIntId(45);
fooResult.setNullField(null);
@@ -191,7 +191,7 @@
// check modified fields and no violations
assertTrue(result.getJSONObject("sideEffects").has("UPDATE"));
- fooResult = SimpleFoo.getSingleton();
+ fooResult = SimpleFoo.findSimpleFooById(999L);
assertEquals(45, (int) fooResult.getIntId());
assertNull(fooResult.getUserName());
assertEquals("test", fooResult.getNullField());
@@ -205,7 +205,7 @@
JSONObject foo = fetchVerifyAndGetInitialObject();
// change some fields but don't change other fields.
- SimpleFoo fooResult = SimpleFoo.getSingleton();
+ SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
fooResult.setUserName("JSC");
fooResult.setIntId(45);
foo.put("userName", "JSC");
@@ -218,7 +218,7 @@
// check modified fields and no violations
assertTrue(result.getJSONObject("sideEffects").has("UPDATE"));
- fooResult = SimpleFoo.getSingleton();
+ fooResult = SimpleFoo.findSimpleFooById(999L);
assertEquals(45, (int) fooResult.getIntId());
assertEquals("JSC", fooResult.getUserName());
assertEquals(newTime, fooResult.getCreated().getTime());
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleBar.java b/user/test/com/google/gwt/requestfactory/server/SimpleBar.java
index f6e2fd6..fd47a98 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleBar.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleBar.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -62,7 +62,7 @@
*/
public static SimpleBar findSimpleBarById(String id) {
SimpleBar toReturn = get().get(id);
- return toReturn.findFails ? null : toReturn;
+ return (toReturn == null || toReturn.findFails) ? null : toReturn;
}
@SuppressWarnings("unchecked")
@@ -131,6 +131,10 @@
userName = "FOO";
}
+ public void delete() {
+ get().remove(getId());
+ }
+
public Boolean getFindFails() {
return findFails;
}
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
index f596d25..4756f89 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -21,10 +21,11 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Date;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
@@ -37,12 +38,12 @@
/**
* DO NOT USE THIS UGLY HACK DIRECTLY! Call {@link #get} instead.
*/
- private static SimpleFoo jreTestSingleton = new SimpleFoo();
+ private static Map<Long, SimpleFoo> jreTestSingleton = new HashMap<Long, SimpleFoo>();
private static Long nextId = 1L;
public static Long countSimpleFoo() {
- return 1L;
+ return (long) get().size();
}
public static SimpleFoo echo(SimpleFoo simpleFoo) {
@@ -55,7 +56,7 @@
}
public static List<SimpleFoo> findAll() {
- return Collections.singletonList(get());
+ return new ArrayList<SimpleFoo>(get().values());
}
public static SimpleFoo findSimpleFoo(Long id) {
@@ -63,11 +64,11 @@
}
public static SimpleFoo findSimpleFooById(Long id) {
- get().setId(id);
- return get();
+ return get().get(id);
}
- public static synchronized SimpleFoo get() {
+ @SuppressWarnings("unchecked")
+ public static synchronized Map<Long, SimpleFoo> get() {
HttpServletRequest req = RequestFactoryServlet.getThreadLocalRequest();
if (req == null) {
// May be in a JRE test case, use the singleton
@@ -78,7 +79,7 @@
* that doesn't allow any requests to be processed unless they're
* associated with an existing session.
*/
- SimpleFoo value = (SimpleFoo) req.getSession().getAttribute(
+ Map<Long, SimpleFoo> value = (Map<Long, SimpleFoo>) req.getSession().getAttribute(
SimpleFoo.class.getCanonicalName());
if (value == null) {
value = reset();
@@ -103,10 +104,6 @@
return list;
}
- public static SimpleFoo getSingleton() {
- return get();
- }
-
public static Boolean processBooleanList(List<Boolean> values) {
return values.get(0);
}
@@ -123,8 +120,79 @@
return string;
}
- public static synchronized SimpleFoo reset() {
- SimpleFoo instance = new SimpleFoo();
+ public static void receiveNullList(List<SimpleFoo> value) {
+ if (value != null) {
+ throw new IllegalArgumentException(
+ "Expected value to be null. Actual value: \"" + value + "\"");
+ }
+ }
+
+ public static void receiveNullSimpleFoo(SimpleFoo value) {
+ if (value != null) {
+ throw new IllegalArgumentException(
+ "Expected value to be null. Actual value: \"" + value + "\"");
+ }
+ }
+
+ public static void receiveNullString(String value) {
+ if (value != null) {
+ throw new IllegalArgumentException(
+ "Expected value to be null. Actual value: \"" + value + "\"");
+ }
+ }
+
+ public static void receiveNullValueInEntityList(List<SimpleFoo> list) {
+ if (list == null) {
+ throw new IllegalArgumentException("Expected list to be non null.");
+ } else if (list.size() != 2) {
+ throw new IllegalArgumentException("Expected list to contain two items.");
+ } else if (list.get(0) == null) {
+ throw new IllegalArgumentException("Expected list.get(0) to return non null.");
+ } else if (list.get(1) != null) {
+ throw new IllegalArgumentException(
+ "Expected list.get(1) to return null. Actual: " + list.get(1));
+ }
+ }
+
+ public static void receiveNullValueInIntegerList(List<Integer> list) {
+ if (list == null) {
+ throw new IllegalArgumentException("Expected list to be non null.");
+ } else if (list.size() != 3) {
+ throw new IllegalArgumentException("Expected list to contain three items.");
+ } else if (list.get(0) == null || list.get(1) == null) {
+ throw new IllegalArgumentException("Expected list.get(0)/get(1) to return non null.");
+ } else if (list.get(2) != null) {
+ throw new IllegalArgumentException(
+ "Expected list.get(2) to return null. Actual: \"" + list.get(2) + "\"");
+ }
+ }
+
+ public static void receiveNullValueInStringList(List<String> list) {
+ if (list == null) {
+ throw new IllegalArgumentException("Expected list to be non null.");
+ } else if (list.size() != 3) {
+ throw new IllegalArgumentException("Expected list to contain three items.");
+ } else if (list.get(0) == null || list.get(1) == null) {
+ throw new IllegalArgumentException("Expected list.get(0)/get(1) to return non null.");
+ } else if (list.get(2) != null) {
+ throw new IllegalArgumentException(
+ "Expected list.get(2) to return null. Actual: \"" + list.get(2) + "\"");
+ }
+ }
+
+ public static synchronized Map<Long, SimpleFoo> reset() {
+ Map<Long, SimpleFoo> instance = new HashMap<Long, SimpleFoo>();
+ // fixtures
+ SimpleFoo s1 = new SimpleFoo();
+ s1.setId(1L);
+ s1.isNew = false;
+ instance.put(s1.getId(), s1);
+
+ SimpleFoo s2 = new SimpleFoo();
+ s2.setId(999L);
+ s2.isNew = false;
+ instance.put(s2.getId(), s2);
+
HttpServletRequest req = RequestFactoryServlet.getThreadLocalRequest();
if (req == null) {
jreTestSingleton = instance;
@@ -156,6 +224,7 @@
@Id
private Long id = 1L;
+ private boolean isNew = true;
@Size(min = 3, max = 30)
private String userName;
@@ -220,8 +289,15 @@
}
public Long countSimpleFooWithUserNameSideEffect() {
- get().setUserName(userName);
- return 1L;
+ findSimpleFoo(1L).setUserName(userName);
+ return countSimpleFoo();
+ }
+
+ public void deleteBar() {
+ if (barField != null) {
+ barField.delete();
+ }
+ barField = null;
}
public SimpleBar getBarField() {
@@ -357,7 +433,11 @@
}
public void persist() {
- setId(nextId++);
+ if (isNew) {
+ setId(nextId++);
+ isNew = false;
+ get().put(getId(), this);
+ }
}
public SimpleFoo persistAndReturnSelf() {
@@ -365,6 +445,11 @@
return this;
}
+ public SimpleFoo persistCascadingAndReturnSelf() {
+ persistCascadingAndReturnSelfImpl(new HashSet<SimpleFoo>());
+ return this;
+ }
+
public String processList(List<SimpleFoo> values) {
String result = "";
for (SimpleFoo n : values) {
@@ -373,6 +458,13 @@
return result;
}
+ public void receiveNull(String value) {
+ if (value != null) {
+ throw new IllegalArgumentException(
+ "Expected value to be null. Actual value: \"" + value + "\"");
+ }
+ }
+
public void setBarField(SimpleBar barField) {
this.barField = barField;
}
@@ -515,4 +607,55 @@
}
return sum;
}
+
+ /**
+ * Persist this entity and all child entities. This method can handle loops.
+ *
+ * @param processed the entities that have been processed
+ */
+ private void persistCascadingAndReturnSelfImpl(Set<SimpleFoo> processed) {
+ if (processed.contains(this)) {
+ return;
+ }
+
+ // Persist this entity.
+ processed.add(this);
+ persist();
+
+ // Persist SimpleBar children.
+ // We don't need to keep track of the processed SimpleBars because persist()
+ // is a no-op if the SimpleBar has already been persisted.
+ if (barField != null) {
+ barField.persist();
+ }
+ if (barNullField != null) {
+ barNullField.persist();
+ }
+ if (oneToManySetField != null) {
+ for (SimpleBar child : oneToManySetField) {
+ if (child != null) {
+ child.persist();
+ }
+ }
+ }
+ if (oneToManyField != null) {
+ for (SimpleBar child : oneToManyField) {
+ if (child != null) {
+ child.persist();
+ }
+ }
+ }
+
+ // Persist SimpleFoo children.
+ if (fooField != null) {
+ fooField.persistCascadingAndReturnSelfImpl(processed);
+ }
+ if (selfOneToManyField != null) {
+ for (SimpleFoo child : selfOneToManyField) {
+ if (child != null) {
+ child.persistCascadingAndReturnSelfImpl(processed);
+ }
+ }
+ }
+ }
}
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
index 3ccdf7d..b58c8ea 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -29,6 +29,9 @@
@Instance
Request<Long> countSimpleFooWithUserNameSideEffect(SimpleFooProxy proxy);
+ @Instance
+ Request<Void> deleteBar(SimpleFooProxy proxy);
+
Request<SimpleFooProxy> echo(SimpleFooProxy proxy);
Request<SimpleFooProxy> echoComplex(SimpleFooProxy fooProxy, SimpleBarProxy barProxy);
@@ -46,10 +49,13 @@
@Instance
Request<Void> persist(SimpleFooProxy proxy);
-
+
@Instance
Request<SimpleFooProxy> persistAndReturnSelf(SimpleFooProxy proxy);
+ @Instance
+ Request<SimpleFooProxy> persistCascadingAndReturnSelf(SimpleFooProxy proxy);
+
Request<Boolean> processBooleanList(List<Boolean> values);
Request<Date> processDateList(List<Date> values);
@@ -60,7 +66,22 @@
@Instance
Request<String> processList(SimpleFooProxy instance, List<SimpleFooProxy> values);
-
+
+ @Instance
+ Request<Void> receiveNull(SimpleFooProxy instance, String value);
+
+ Request<Void> receiveNullList(List<SimpleFooProxy> value);
+
+ Request<Void> receiveNullSimpleFoo(SimpleFooProxy value);
+
+ Request<Void> receiveNullString(String value);
+
+ Request<Void> receiveNullValueInEntityList(List<SimpleFooProxy> value);
+
+ Request<Void> receiveNullValueInIntegerList(List<Integer> value);
+
+ Request<Void> receiveNullValueInStringList(List<String> value);
+
Request<Void> reset();
Request<List<SimpleFooProxy>> returnNullList();