Implements * globbing for RequestFactory with(), the simpler half of
the proposal in
http://code.google.com/p/google-web-toolkit/issues/detail?id=6697
Also fixes bugs exposed in using null members in collections
Review at http://gwt-code-reviews.appspot.com/1520808
Review by: robertvawter@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10560 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/web/bindery/requestfactory/server/Resolver.java b/user/src/com/google/web/bindery/requestfactory/server/Resolver.java
index 4751d8d..22e7a31 100644
--- a/user/src/com/google/web/bindery/requestfactory/server/Resolver.java
+++ b/user/src/com/google/web/bindery/requestfactory/server/Resolver.java
@@ -198,6 +198,11 @@
* not been previously resolved for the next batch of work.
*/
public void addPaths(String prefix, Collection<String> requestedPaths) {
+ if (clientObject == null) {
+ // No point trying to follow paths past a null value
+ return;
+ }
+
// Identity comparison intentional
if (toResolve == EMPTY) {
toResolve = new TreeSet<String>();
@@ -207,6 +212,8 @@
for (String path : requestedPaths) {
if (path.startsWith(prefix)) {
toResolve.add(path.substring(prefixLength));
+ } else if (path.startsWith("*.")) {
+ toResolve.add(path.substring("*.".length()));
}
}
toResolve.removeAll(resolved);
@@ -310,7 +317,14 @@
* references.
*/
static boolean matchesPropertyRef(Set<String> propertyRefs, String newPrefix) {
- return propertyRefs.contains(newPrefix.replaceAll("\\[\\d+\\]", ""));
+ /*
+ * Match all fields for a wildcard
+ *
+ * Also, remove list index suffixes. Not actually used, was in anticipation
+ * of OGNL type schemes. That said, Editor will slip in such things.
+ */
+ return propertyRefs.contains("*")
+ || propertyRefs.contains(newPrefix.replaceAll("\\[\\d+\\]", ""));
}
/**
@@ -567,7 +581,7 @@
*/
private Resolution resolveClientValue(Object domainValue, Type clientType) {
if (domainValue == null) {
- return null;
+ return new Resolution(null);
}
boolean anyType = clientType == null;
diff --git a/user/src/com/google/web/bindery/requestfactory/shared/impl/ProxySerializerImpl.java b/user/src/com/google/web/bindery/requestfactory/shared/impl/ProxySerializerImpl.java
index 2b523cf..d07e43a 100644
--- a/user/src/com/google/web/bindery/requestfactory/shared/impl/ProxySerializerImpl.java
+++ b/user/src/com/google/web/bindery/requestfactory/shared/impl/ProxySerializerImpl.java
@@ -93,6 +93,10 @@
}
public String serialize(BaseProxy rootObject) {
+ if (rootObject == null) {
+ return "null";
+ }
+
final AutoBean<? extends BaseProxy> root = AutoBeanUtils.getAutoBean(rootObject);
if (root == null) {
// Unexpected, some kind of foreign implementation of the BaseProxy?
diff --git a/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryPolymorphicTest.java b/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryPolymorphicTest.java
index ffd546d..ba57c5a 100644
--- a/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryPolymorphicTest.java
+++ b/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryPolymorphicTest.java
@@ -55,6 +55,8 @@
protected int id = idCount++;
+ private A nextA;
+
public String getA() {
return a;
}
@@ -63,6 +65,13 @@
return id;
}
+ public A getNextA() {
+ if (nextA == null) {
+ nextA = new A();
+ }
+ return nextA;
+ }
+
public int getVersion() {
return 0;
}
@@ -77,6 +86,8 @@
*/
@ProxyFor(A.class)
public interface AProxy extends EntityProxy, HasA {
+ AProxy getNextA();
+
// Mix in getA() from HasA
void setA(String value);
}
@@ -146,10 +157,20 @@
private String c = "c";
+ private C nextC;
+
public String getC() {
return c;
}
+ public C getNextC() {
+ if (nextC == null) {
+ nextC = new C();
+ }
+
+ return nextC;
+ }
+
public void setC(String value) {
c = value;
}
@@ -161,6 +182,8 @@
public interface C1Proxy extends B1Proxy {
String getC();
+ C1Proxy getNextC();
+
void setC(String value);
}
@@ -607,6 +630,50 @@
return "com.google.web.bindery.requestfactory.gwt.RequestFactorySuite";
}
+ public void testChain() {
+ delayTestFinish(TEST_DELAY);
+ Context ctx = factory.ctx();
+ ctx.CasA().with("nextA.nextA").fire(new Receiver<AProxy>() {
+ @Override
+ public void onSuccess(AProxy response) {
+ new CastAndCheckReceiver(AProxy.class).onSuccess(response.getNextA().getNextA());
+ assertNull(response.getNextA().getNextA().getNextA());
+ assertNull(((C1Proxy) response).getNextC());
+ finishTest();
+ }
+ });
+ }
+
+ public void testChainWithExtras() {
+ delayTestFinish(TEST_DELAY);
+ Context ctx = factory.ctx();
+ ctx.CasA().with("nextC.nextC").fire(new Receiver<AProxy>() {
+ @Override
+ public void onSuccess(AProxy response) {
+ assertNull(response.getNextA());
+ C1Proxy cast = (C1Proxy) response;
+ new CastAndCheckReceiver(C1Proxy.class).onSuccess(cast.getNextC().getNextC());
+ assertNull(cast.getNextC().getNextC().getNextC());
+ finishTest();
+ }
+ });
+ }
+
+ public void testChainWithWildcards() {
+ delayTestFinish(TEST_DELAY);
+ Context ctx = factory.ctx();
+ ctx.CasA().with("*.*").fire(new Receiver<AProxy>() {
+ @Override
+ public void onSuccess(AProxy response) {
+ new CastAndCheckReceiver(AProxy.class).onSuccess(response.getNextA().getNextA());
+ C1Proxy cast = (C1Proxy) response;
+ new CastAndCheckReceiver(C1Proxy.class).onSuccess(cast.getNextC().getNextC());
+ assertNull(cast.getNextC().getNextC().getNextC());
+ finishTest();
+ }
+ });
+ }
+
public void testCreation() {
delayTestFinish(TEST_DELAY);
Context ctx = factory.ctx();
diff --git a/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTest.java b/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTest.java
index f9935a4..01da1c3 100644
--- a/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTest.java
+++ b/user/test/com/google/web/bindery/requestfactory/gwt/client/RequestFactoryTest.java
@@ -700,6 +700,23 @@
}
});
}
+
+ public void testForwardReferenceWildcardDecode() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().getTripletReference().with("selfOneToManyField.*.fooField")
+ .fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ response = checkSerialization(response);
+ assertNotNull(response.getSelfOneToManyField().get(0));
+ assertNotNull(response.getSelfOneToManyField().get(0).getSelfOneToManyField());
+ assertNotNull(response.getSelfOneToManyField().get(0).getSelfOneToManyField().get(0));
+ assertNotNull(response.getSelfOneToManyField().get(0).getSelfOneToManyField().get(0)
+ .getFooField());
+ finishTestAndReset();
+ }
+ });
+ }
public void testGetEventBus() {
assertEquals(eventBus, req.getEventBus());
@@ -979,6 +996,19 @@
delayTestFinish(DELAY_TEST_FINISH);
simpleFooRequest().returnNullSimpleFoo().fire(new NullReceiver());
}
+
+ public void testNullEntityFieldResult() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().getSimpleFooWithNullRelationship().with("fooField.fooField.fooField").fire(
+ new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy v) {
+ checkSerialization(v);
+ assertNull(v.getFooField());
+ finishTestAndReset();
+ }
+ });
+ }
/**
* Test that a null value can be sent in a request.
@@ -1084,6 +1114,63 @@
}
});
}
+
+ public void testNullValueInEntityListResponse() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ final Request<SimpleFooProxy> fooReq =
+ req.simpleFooRequest().getNullInEntityList().with("selfOneToManyField");
+ fooReq.fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy v) {
+ List<SimpleFooProxy> manyFoos = v.getSelfOneToManyField();
+ assertEquals(3, manyFoos.size());
+
+ assertNotNull(manyFoos.get(0));
+ assertNull(manyFoos.get(1));
+ assertNotNull(manyFoos.get(2));
+
+ finishTestAndReset();
+ }
+ });
+ }
+
+ public void testNullValueInEntityListResponseWithWildcard() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ final Request<SimpleFooProxy> fooReq =
+ req.simpleFooRequest().getNullInEntityList().with("selfOneToManyField.*.fooField");
+ fooReq.fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy foo0) {
+ List<SimpleFooProxy> manyFoos = foo0.getSelfOneToManyField();
+ assertEquals(3, manyFoos.size());
+
+ assertSame(foo0, manyFoos.get(0).getSelfOneToManyField().get(0));
+ assertNull(manyFoos.get(1));
+ assertSame(foo0, manyFoos.get(2).getSelfOneToManyField().get(0));
+ assertSame(foo0, manyFoos.get(2).getFooField().getFooField());
+
+ finishTestAndReset();
+ }
+ });
+ }
+
+ public void testNullValueInEntityListResponseWithLongResolvePaths() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ final Request<SimpleFooProxy> fooReq =
+ req.simpleFooRequest().getNullInEntityList().with("selfOneToManyField.selfOneToManyField.selfOneToManyField");
+ fooReq.fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy v) {
+ assertEquals(3, v.getSelfOneToManyField().size());
+
+ assertNotNull(v.getSelfOneToManyField().get(0));
+ assertNull(v.getSelfOneToManyField().get(1));
+ assertNotNull(v.getSelfOneToManyField().get(2));
+
+ finishTestAndReset();
+ }
+ });
+ }
/**
* Test that a null value can be sent within a list of objects.
@@ -2044,6 +2131,31 @@
}
});
}
+
+ public void testPropertyRefsOnWildcardChain() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ final Request<SimpleFooProxy> fooReq =
+ req.simpleFooRequest().getLongChain().with("fooField.*.*.fooField");
+ fooReq.fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy foo0) {
+ assertNull(foo0.getSelfOneToManyField()); // didn't ask for it
+
+ SimpleFooProxy foo1 = foo0.getFooField(); // "fooField
+ SimpleFooProxy foo2 = foo1.getFooField(); // .*
+ SimpleFooProxy foo3 = foo2.getFooField(); // .*
+ SimpleFooProxy foo4 = foo3.getFooField(); // .fooField"
+ SimpleFooProxy foo5 = foo4.getFooField();
+
+ assertNotNull(foo1);
+ assertNotNull(foo2);
+ assertNotNull(foo3);
+ assertNotNull(foo4);
+ assertNull(foo5);
+ finishTestAndReset();
+ }
+ });
+ }
public void testPropertyRefsOnSameObjectReturnedTwice() {
delayTestFinish(DELAY_TEST_FINISH);
diff --git a/user/test/com/google/web/bindery/requestfactory/server/SimpleFoo.java b/user/test/com/google/web/bindery/requestfactory/server/SimpleFoo.java
index d3cceaa..fc20600 100644
--- a/user/test/com/google/web/bindery/requestfactory/server/SimpleFoo.java
+++ b/user/test/com/google/web/bindery/requestfactory/server/SimpleFoo.java
@@ -124,6 +124,53 @@
foo3.persist();
return Arrays.asList(foo1, foo2, foo3);
}
+
+ public static SimpleFoo getLongChain() {
+ SimpleFoo foo0 = new SimpleFoo();
+ SimpleFoo foo1 = new SimpleFoo();
+ SimpleFoo foo2 = new SimpleFoo();
+ SimpleFoo foo3 = new SimpleFoo();
+ SimpleFoo foo4 = new SimpleFoo();
+ SimpleFoo foo5 = new SimpleFoo();
+
+ foo0.setSelfOneToManyField(Arrays.asList(foo1, foo2));
+ foo0.setFooField(foo1);
+ foo1.setFooField(foo2);
+ foo2.setFooField(foo3);
+ foo3.setFooField(foo4);
+ foo4.setFooField(foo5);
+ foo5.setFooField(foo5);
+
+ foo0.persist();
+ foo1.persist();
+ foo2.persist();
+ foo3.persist();
+ foo4.persist();
+ foo5.persist();
+
+ return foo0;
+ }
+
+ public static SimpleFoo getNullInEntityList() {
+ SimpleFoo foo0 = new SimpleFoo();
+ SimpleFoo foo1 = new SimpleFoo();
+ SimpleFoo foo2 = new SimpleFoo();
+ SimpleFoo foo2FooField = new SimpleFoo();
+
+ foo0.setSelfOneToManyField(Arrays.asList(foo1, null, foo2));
+
+ foo1.setSelfOneToManyField(Arrays.asList(foo0));
+
+ foo2.setSelfOneToManyField(Arrays.asList(foo0));
+ foo2.setFooField(foo2FooField);
+ foo2FooField.setFooField(foo0);
+
+ foo0.persist();
+ foo1.persist();
+ foo2.persist();
+ foo2FooField.persist();
+ return foo0;
+ }
public static List<Integer> getNumberList() {
ArrayList<Integer> list = new ArrayList<Integer>();
@@ -141,6 +188,12 @@
return list;
}
+ public static SimpleFoo getSimpleFooWithNullRelationship() {
+ SimpleFoo foo = new SimpleFoo();
+ foo.persist();
+ return foo;
+ }
+
/**
* This tests that the server detects and disallows the use of persisted
* objects with a null version property.
diff --git a/user/test/com/google/web/bindery/requestfactory/shared/SimpleFooRequest.java b/user/test/com/google/web/bindery/requestfactory/shared/SimpleFooRequest.java
index 3c3290e..6183e0b 100644
--- a/user/test/com/google/web/bindery/requestfactory/shared/SimpleFooRequest.java
+++ b/user/test/com/google/web/bindery/requestfactory/shared/SimpleFooRequest.java
@@ -49,10 +49,16 @@
Request<List<SimpleFooProxy>> getFlattenedTripletReference();
- Request<List<Integer>> getNumberList();
+ Request<SimpleFooProxy> getLongChain();
+ Request<SimpleFooProxy> getNullInEntityList();
+
+ Request<List<Integer>> getNumberList();
+
Request<Set<Integer>> getNumberSet();
+ Request<SimpleFooProxy> getSimpleFooWithNullRelationship();
+
Request<SimpleFooProxy> getSimpleFooWithNullVersion();
Request<SimpleFooProxy> getSimpleFooWithSubPropertyCollection();