Revision: 8937
Author: b...@google.com
Date: Tue Oct 5 09:11:00 2010
Log: Fix ROO-1488 where forward references were not correctly resolved.
Patch by: cromwellian, bobv
Review by: bobv, cromwellian
Review at http://gwt-code-reviews.appspot.com/958801
http://code.google.com/p/google-web-toolkit/source/detail?r=8937
Modified:
/trunk/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestContext.java
/trunk/user/src/com/google/gwt/requestfactory/client/impl/EntityCodex.java
/trunk/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
/trunk/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
/trunk/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
=======================================
---
/trunk/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestContext.java
Sun Oct 3 14:17:43 2010
+++
/trunk/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequestContext.java
Tue Oct 5 09:11:00 2010
@@ -26,15 +26,16 @@
import com.google.gwt.requestfactory.shared.EntityProxyChange;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.shared.RequestContext;
+import
com.google.gwt.requestfactory.shared.RequestTransport.TransportReceiver;
import com.google.gwt.requestfactory.shared.ServerFailure;
import com.google.gwt.requestfactory.shared.ValueCodex;
import com.google.gwt.requestfactory.shared.Violation;
import com.google.gwt.requestfactory.shared.WriteOperation;
-import
com.google.gwt.requestfactory.shared.RequestTransport.TransportReceiver;
import com.google.gwt.requestfactory.shared.impl.Constants;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -56,8 +57,13 @@
* Objects are placed into this map by being passed into {...@link #edit}
or as
* an invocation argument.
*/
- private final Map<SimpleEntityProxyId<?>, EntityProxy> seenProxies = new
LinkedHashMap<SimpleEntityProxyId<?>, EntityProxy>();
+ private final Map<SimpleEntityProxyId<?>, AutoBean<?>> editedProxies =
new LinkedHashMap<SimpleEntityProxyId<?>, AutoBean<?>>();
private Set<Violation> errors = new LinkedHashSet<Violation>();
+ /**
+ * A map that contains the canonical instance of an entity to return in
the
+ * return graph, since this is built from scratch.
+ */
+ private final Map<SimpleEntityProxyId<?>, AutoBean<?>> returnedProxies =
new HashMap<SimpleEntityProxyId<?>, AutoBean<?>>();
protected AbstractRequestContext(AbstractRequestFactory factory) {
this.requestFactory = factory;
@@ -71,7 +77,7 @@
AutoBean<T> created = requestFactory.createEntityProxy(clazz,
requestFactory.allocateId(clazz));
- return makeEdited(created);
+ return takeOwnership(created);
}
public <T extends EntityProxy> T edit(T object) {
@@ -80,25 +86,21 @@
checkLocked();
@SuppressWarnings("unchecked")
- T toReturn = (T) seenProxies.get(object.stableId());
- if (toReturn != null) {
+ AutoBean<T> previouslySeen = (AutoBean<T>)
editedProxies.get(object.stableId());
+ if (previouslySeen != null && !previouslySeen.isFrozen()) {
/*
* If we've seen the object before, it might be because it was
passed in
* as a method argument. This does not guarantee its mutability, so
check
* that here before returning the cached object.
*/
- AutoBean<T> previouslySeen = AutoBeanUtils.getAutoBean(toReturn);
- if (!previouslySeen.isFrozen()) {
- return toReturn;
- }
+ return previouslySeen.as();
}
// Create editable copies
AutoBean<T> parent = bean;
bean = cloneBeanAndCollections(bean);
- toReturn = makeEdited(bean);
bean.setTag(PARENT_OBJECT, parent);
- return toReturn;
+ return takeOwnership(bean);
}
/**
@@ -146,13 +148,12 @@
* simple flag-check because of the possibility of "unmaking" a
change, per
* the JavaDoc.
*/
- for (EntityProxy edited : seenProxies.values()) {
- AutoBean<EntityProxy> bean = AutoBeanUtils.getAutoBean(edited);
+ for (AutoBean<?> bean : editedProxies.values()) {
AutoBean<?> previous = bean.getTag(PARENT_OBJECT);
if (previous == null) {
// Compare to empty object
- previous = getRequestFactory().getAutoBeanFactory().create(
- edited.stableId().getProxyClass());
+ Class<?> proxyClass = ((EntityProxy)
bean.as()).stableId().getProxyClass();
+ previous =
getRequestFactory().getAutoBeanFactory().create(proxyClass);
}
if (!AutoBeanUtils.diff(previous, bean).isEmpty()) {
return true;
@@ -182,7 +183,7 @@
*/
protected void addInvocation(AbstractRequest<?> request) {
if (invocations.size() > 0) {
- // TODO(bobv): Upgrade wire protocal and server to handle chains
+ // TODO(bobv): Upgrade wire protocol and server to handle chains
throw new IllegalStateException("Method chaining not implemented");
}
invocations.add(request);
@@ -192,38 +193,35 @@
}
/**
- * Called by generated subclasses when decoding a request.
+ * Creates or retrieves a new canonical AutoBean to represent the given
id in
+ * the returned payload.
*/
- EntityProxy getSeenEntityProxy(SimpleEntityProxyId<?> id) {
- return seenProxies.get(id);
+ <Q extends EntityProxy> AutoBean<Q> getProxyForReturnPayloadGraph(
+ SimpleEntityProxyId<Q> id) {
+ assert !id.isEphemeral();
+
+ @SuppressWarnings("unchecked")
+ AutoBean<Q> bean = (AutoBean<Q>) returnedProxies.get(id);
+ if (bean == null) {
+ Class<Q> proxyClass = id.getProxyClass();
+ bean = requestFactory.createEntityProxy(proxyClass, id);
+ returnedProxies.put(id, bean);
+ }
+
+ return bean;
}
/**
- * Apply the deltas in a ReturnRecord to an EntityProxy.
+ * Create a new EntityProxy from a snapshot in the return payload.
*
- * @param id the EntityProxyId of the object being mutated
+ * @param id the EntityProxyId of the object
* @param returnRecord the JSON map containing property/value pairs
* @param operations the WriteOperation eventns to broadcast over the
EventBus
*/
<Q extends EntityProxy> Q processReturnRecord(SimpleEntityProxyId<Q> id,
final ReturnRecord returnRecord, WriteOperation... operations) {
- @SuppressWarnings("unchecked")
- Q proxy = (Q) seenProxies.get(id);
- AutoBean<Q> toMutate;
-
- if (proxy == null) {
- // The server is sending us an object that hasn't been seen before
- assert !id.isEphemeral();
- Class<Q> proxyClass = id.getProxyClass();
- toMutate = requestFactory.createEntityProxy(proxyClass, id);
- makeEdited(toMutate);
- } else {
- // Create a new copy of the object
- AutoBean<Q> original = AutoBeanUtils.getAutoBean(proxy);
- toMutate = cloneBeanAndCollections(original);
- }
-
- proxy = toMutate.as();
+
+ AutoBean<Q> toMutate = getProxyForReturnPayloadGraph(id);
// Apply updates
toMutate.accept(new AutoBeanVisitor() {
@@ -266,6 +264,7 @@
// Finished applying updates, freeze the bean
makeImmutable(toMutate);
+ Q proxy = toMutate.as();
/*
* Notify subscribers if the object differs from when it first came
into the
@@ -394,8 +393,9 @@
if (errors.isEmpty()) {
receiver.onSuccess(null);
// After success, shut down the context
- seenProxies.clear();
+ editedProxies.clear();
invocations.clear();
+ returnedProxies.clear();
} else {
receiver.onViolation(errors);
}
@@ -411,22 +411,10 @@
* Set the frozen status of all EntityProxies owned by this context.
*/
private void freezeEntities(boolean frozen) {
- for (EntityProxy proxy : seenProxies.values()) {
- AutoBean<?> bean = AutoBeanUtils.getAutoBean(proxy);
+ for (AutoBean<?> bean : editedProxies.values()) {
bean.setFrozen(frozen);
}
}
-
- /**
- * Make the EnityProxy bean edited and owned by this RequestContext.
- */
- private <T extends EntityProxy> T makeEdited(AutoBean<T> bean) {
- T toReturn = bean.as();
- seenProxies.put(EntityProxyCategory.stableId(bean), toReturn);
- bean.setTag(EntityProxyCategory.REQUEST_CONTEXT,
- AbstractRequestContext.this);
- return toReturn;
- }
/**
* Make an EntityProxy immutable.
@@ -456,17 +444,16 @@
RequestContentData data = new RequestContentData();
// Compute deltas for each entity seen by the context
- for (EntityProxy proxy : seenProxies.values()) {
+ for (AutoBean<?> currentView : editedProxies.values()) {
boolean isPersist = false;
@SuppressWarnings("unchecked")
- SimpleEntityProxyId<EntityProxy> stableId =
(SimpleEntityProxyId<EntityProxy>) proxy.stableId();
+ SimpleEntityProxyId<EntityProxy> stableId =
EntityProxyCategory.stableId((AutoBean<EntityProxy>) currentView);
// Encoded string representations of the properties
Map<String, String> encoded = new LinkedHashMap<String, String>();
{
// Find the object to compare against
- AutoBean<?> currentView = AutoBeanUtils.getAutoBean(proxy);
AutoBean<?> parent = currentView.getTag(PARENT_OBJECT);
if (parent == null) {
// Newly-created object, use a blank object to compare against
@@ -546,4 +533,14 @@
edit((EntityProxy) arg);
}
}
-}
+
+ /**
+ * Make the EnityProxy bean edited and owned by this RequestContext.
+ */
+ private <T extends EntityProxy> T takeOwnership(AutoBean<T> bean) {
+ editedProxies.put(EntityProxyCategory.stableId(bean), bean);
+ bean.setTag(EntityProxyCategory.REQUEST_CONTEXT,
+ AbstractRequestContext.this);
+ return bean.as();
+ }
+}
=======================================
---
/trunk/user/src/com/google/gwt/requestfactory/client/impl/EntityCodex.java
Fri Oct 1 18:15:55 2010
+++
/trunk/user/src/com/google/gwt/requestfactory/client/impl/EntityCodex.java
Tue Oct 5 09:11:00 2010
@@ -79,7 +79,8 @@
if (requestContext.getRequestFactory().getTypeToken(type) != null) {
EntityProxyId<?> id = requestContext.getRequestFactory().getProxyId(
(String) jso);
- return requestContext.getSeenEntityProxy((SimpleEntityProxyId<?>)
id);
+ return requestContext.getProxyForReturnPayloadGraph(
+ (SimpleEntityProxyId<?>) id).as();
}
// Fall back to values
=======================================
---
/trunk/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
Mon Oct 4 15:35:00 2010
+++
/trunk/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
Tue Oct 5 09:11:00 2010
@@ -42,7 +42,6 @@
* Tests for {...@link com.google.gwt.requestfactory.shared.RequestFactory}.
*/
public class RequestFactoryTest extends RequestFactoryTestBase {
- private static final int DELAY_TEST_FINISH = 5000;
/*
* DO NOT USE finishTest(). Instead, call finishTestAndReset();
@@ -167,6 +166,8 @@
doTest();
}
}
+
+ private static final int DELAY_TEST_FINISH = 5000;
public <T extends EntityProxy> void assertContains(Collection<T> col, T
value) {
for (T x : col) {
@@ -174,8 +175,9 @@
return;
}
}
- assertTrue(("Value " + value + " not found in collection ")
- + col.toString(), false);
+ assertTrue(
+ ("Value " + value + " not found in collection ") + col.toString(),
+ false);
}
public <T extends EntityProxy> void assertNotContains(Collection<T> col,
@@ -184,11 +186,131 @@
assertNotSame(x.stableId(), value.stableId());
}
}
+
+ public void disabled_testEchoComplexFutures() {
+ // relate futures on the server. Check if the relationship is still
present
+ // on the client.
+ delayTestFinish(DELAY_TEST_FINISH);
+ final SimpleFooEventHandler<SimpleFooProxy> handler = new
SimpleFooEventHandler<SimpleFooProxy>();
+ EntityProxyChange.registerForProxyType(req.getEventBus(),
+ SimpleFooProxy.class, handler);
+ SimpleFooRequest context = req.simpleFooRequest();
+ final SimpleFooProxy simpleFoo = context.create(SimpleFooProxy.class);
+ final SimpleBarProxy simpleBar = context.create(SimpleBarProxy.class);
+ context.echoComplex(simpleFoo, simpleBar).fire(
+ new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ assertEquals(0, handler.totalEventCount);
+ checkStableIdEquals(simpleFoo, response);
+ SimpleBarProxy responseBar = response.getBarField();
+ assertNotNull(responseBar);
+ checkStableIdEquals(simpleBar, responseBar);
+ finishTestAndReset();
+ }
+ });
+ }
+
+ public void disabled_testEchoSimpleFutures() {
+ // tests if futureIds can be echoed back.
+ delayTestFinish(DELAY_TEST_FINISH);
+ final SimpleFooEventHandler<SimpleFooProxy> handler = new
SimpleFooEventHandler<SimpleFooProxy>();
+ EntityProxyChange.registerForProxyType(req.getEventBus(),
+ SimpleFooProxy.class, handler);
+ SimpleFooRequest context = req.simpleFooRequest();
+ final SimpleFooProxy simpleFoo = context.create(SimpleFooProxy.class);
+ context.echo(simpleFoo).fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ assertEquals(0, handler.totalEventCount);
+ checkStableIdEquals(simpleFoo, response);
+ finishTestAndReset();
+ }
+ });
+ }
+
+ /**
+ * 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(DELAY_TEST_FINISH);
+
+ // Persist bar.
+ SimpleBarRequest context = req.simpleBarRequest();
+ final SimpleBarProxy bar = context.create(SimpleBarProxy.class);
+ context.persistAndReturnSelf().using(bar).fire(
+ new Receiver<SimpleBarProxy>() {
+ @Override
+ public void onSuccess(SimpleBarProxy persistentBar) {
+ // Persist foo with bar as a child.
+ SimpleFooRequest context = req.simpleFooRequest();
+ SimpleFooProxy foo = context.create(SimpleFooProxy.class);
+ final Request<SimpleFooProxy> persistRequest =
context.persistAndReturnSelf().using(
+ foo);
+ foo = context.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.
+ SimpleFooRequest context = req.simpleFooRequest();
+ final Request<Void> deleteRequest =
context.deleteBar().using(
+ persistentFoo);
+ SimpleFooProxy editable = context.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();
+ }
+ });
+ }
+ });
+ }
+ });
+ }
@Override
public String getModuleName() {
return "com.google.gwt.requestfactory.RequestFactorySuite";
}
+
+ /**
+ * Test that the same object, referenced twice, points to the same
instance.
+ */
+ public void testAntiAliasing() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().fetchDoubleReference().with("fooField",
+ "selfOneToManyField").fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ assertNotNull(response.getFooField());
+ assertSame(response.getFooField(),
+ response.getSelfOneToManyField().get(0));
+ finishTestAndReset();
+ }
+ });
+ }
/**
* Test that we can commit child objects.
@@ -221,11 +343,6 @@
}
});
}
-
- public void testChangedNothing() {
- SimpleFooRequest context = simpleFooRequest();
- assertFalse(context.isChanged());
- }
public void testChangedCreate() {
SimpleFooRequest context = simpleFooRequest();
@@ -276,6 +393,11 @@
}
});
}
+
+ public void testChangedNothing() {
+ SimpleFooRequest context = simpleFooRequest();
+ assertFalse(context.isChanged());
+ }
public void testClassToken() {
String token = req.getHistoryToken(SimpleFooProxy.class);
@@ -284,6 +406,21 @@
SimpleFooProxy foo = simpleFooRequest().create(SimpleFooProxy.class);
assertEquals(SimpleFooProxy.class, foo.stableId().getProxyClass());
}
+
+ public void testCollectionSubProperties() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().getSimpleFooWithSubPropertyCollection().with(
+ "selfOneToManyField", "selfOneToManyField.fooField").fire(
+ new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ assertEquals(
+ "I'm here",
+
response.getSelfOneToManyField().get(0).getFooField().getUserName());
+ finishTestAndReset();
+ }
+ });
+ }
public void testDummyCreate() {
delayTestFinish(DELAY_TEST_FINISH);
@@ -360,92 +497,6 @@
}
});
}
-
- public void testFindFindEdit() {
- delayTestFinish(5000);
-
- final SimpleFooEventHandler<SimpleFooProxy> handler = new
SimpleFooEventHandler<SimpleFooProxy>();
- EntityProxyChange.registerForProxyType(req.getEventBus(),
- SimpleFooProxy.class, handler);
-
- req.simpleFooRequest().findSimpleFooById(999L).fire(
- new Receiver<SimpleFooProxy>() {
-
- @Override
- public void onSuccess(SimpleFooProxy newFoo) {
- assertEquals(1, handler.updateEventCount);
- assertEquals(1, handler.totalEventCount);
-
- req.simpleFooRequest().findSimpleFooById(999L).fire(
- new Receiver<SimpleFooProxy>() {
-
- @Override
- public void onSuccess(SimpleFooProxy newFoo) {
- // no events are fired second time.
- assertEquals(1, handler.updateEventCount);
- assertEquals(1, handler.totalEventCount);
- SimpleFooRequest context = req.simpleFooRequest();
- final Request<Void> mutateRequest =
context.persist().using(
- newFoo);
- newFoo = context.edit(newFoo);
- newFoo.setUserName("Ray");
- mutateRequest.fire(new Receiver<Void>() {
- @Override
- public void onSuccess(Void response) {
- // events fired on updates.
- assertEquals(2, handler.updateEventCount);
- assertEquals(2, handler.totalEventCount);
-
- finishTestAndReset();
- }
- });
- }
- });
- }
- });
- }
-
- public void disabled_testEchoSimpleFutures() {
- // tests if futureIds can be echoed back.
- delayTestFinish(DELAY_TEST_FINISH);
- final SimpleFooEventHandler<SimpleFooProxy> handler = new
SimpleFooEventHandler<SimpleFooProxy>();
- EntityProxyChange.registerForProxyType(req.getEventBus(),
- SimpleFooProxy.class, handler);
- SimpleFooRequest context = req.simpleFooRequest();
- final SimpleFooProxy simpleFoo = context.create(SimpleFooProxy.class);
- context.echo(simpleFoo).fire(new Receiver<SimpleFooProxy>() {
- @Override
- public void onSuccess(SimpleFooProxy response) {
- assertEquals(0, handler.totalEventCount);
- checkStableIdEquals(simpleFoo, response);
- finishTestAndReset();
- }
- });
- }
-
- public void disabled_testEchoComplexFutures() {
- // relate futures on the server. Check if the relationship is still
present
- // on the client.
- delayTestFinish(DELAY_TEST_FINISH);
- final SimpleFooEventHandler<SimpleFooProxy> handler = new
SimpleFooEventHandler<SimpleFooProxy>();
- EntityProxyChange.registerForProxyType(req.getEventBus(),
- SimpleFooProxy.class, handler);
- SimpleFooRequest context = req.simpleFooRequest();
- final SimpleFooProxy simpleFoo = context.create(SimpleFooProxy.class);
- final SimpleBarProxy simpleBar = context.create(SimpleBarProxy.class);
- context.echoComplex(simpleFoo, simpleBar).fire(
- new Receiver<SimpleFooProxy>() {
- @Override
- public void onSuccess(SimpleFooProxy response) {
- assertEquals(0, handler.totalEventCount);
- checkStableIdEquals(simpleFoo, response);
- SimpleBarProxy responseBar = response.getBarField();
- assertNotNull(responseBar);
- checkStableIdEquals(simpleBar, responseBar);
- finishTestAndReset();
- }
- });
- }
/**
* Tests behaviors relating to editing an object with one context and
then
@@ -546,6 +597,67 @@
}
});
}
+
+ public void testFindFindEdit() {
+ delayTestFinish(5000);
+
+ final SimpleFooEventHandler<SimpleFooProxy> handler = new
SimpleFooEventHandler<SimpleFooProxy>();
+ EntityProxyChange.registerForProxyType(req.getEventBus(),
+ SimpleFooProxy.class, handler);
+
+ req.simpleFooRequest().findSimpleFooById(999L).fire(
+ new Receiver<SimpleFooProxy>() {
+
+ @Override
+ public void onSuccess(SimpleFooProxy newFoo) {
+ assertEquals(1, handler.updateEventCount);
+ assertEquals(1, handler.totalEventCount);
+
+ req.simpleFooRequest().findSimpleFooById(999L).fire(
+ new Receiver<SimpleFooProxy>() {
+
+ @Override
+ public void onSuccess(SimpleFooProxy newFoo) {
+ // no events are fired second time.
+ assertEquals(1, handler.updateEventCount);
+ assertEquals(1, handler.totalEventCount);
+ SimpleFooRequest context = req.simpleFooRequest();
+ final Request<Void> mutateRequest =
context.persist().using(
+ newFoo);
+ newFoo = context.edit(newFoo);
+ newFoo.setUserName("Ray");
+ mutateRequest.fire(new Receiver<Void>() {
+ @Override
+ public void onSuccess(Void response) {
+ // events fired on updates.
+ assertEquals(2, handler.updateEventCount);
+ assertEquals(2, handler.totalEventCount);
+
+ finishTestAndReset();
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
+ public void testForwardReferenceDecode() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().getTripletReference().with(
+ "selfOneToManyField.selfOneToManyField.fooField").fire(
+ new Receiver<SimpleFooProxy>() {
+ public void onSuccess(SimpleFooProxy 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());
@@ -625,6 +737,87 @@
}
});
}
+
+ /*
+ * tests that (a) any method can have a side effect that is handled
correctly.
+ * (b) instance methods are handled correctly and (c) a request cannot be
+ * reused after a successful response is received. (Yet?)
+ */
+ public void testMethodWithSideEffects() {
+ delayTestFinish(DELAY_TEST_FINISH);
+
+ final SimpleFooEventHandler<SimpleFooProxy> handler = new
SimpleFooEventHandler<SimpleFooProxy>();
+ EntityProxyChange.registerForProxyType(req.getEventBus(),
+ SimpleFooProxy.class, handler);
+
+ simpleFooRequest().findSimpleFooById(999L).fire(
+ new Receiver<SimpleFooProxy>() {
+
+ @Override
+ public void onSuccess(SimpleFooProxy newFoo) {
+ assertEquals(1, handler.updateEventCount);
+ assertEquals(1, handler.totalEventCount);
+ SimpleFooRequest context = simpleFooRequest();
+ final Request<Long> mutateRequest =
context.countSimpleFooWithUserNameSideEffect().using(
+ newFoo);
+ newFoo = context.edit(newFoo);
+ newFoo.setUserName("Ray");
+ mutateRequest.fire(new Receiver<Long>() {
+ @Override
+ public void onSuccess(Long response) {
+ assertCannotFire(mutateRequest);
+ assertEquals(new Long(2L), response);
+ assertEquals(2, handler.updateEventCount);
+ assertEquals(2, handler.totalEventCount);
+
+ // confirm that the instance method did have the desired
+ // sideEffect.
+ simpleFooRequest().findSimpleFooById(999L).fire(
+ new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy finalFoo) {
+ assertEquals("Ray", finalFoo.getUserName());
+ assertEquals(2, handler.updateEventCount);
+ assertEquals(2, handler.totalEventCount);
+ finishTestAndReset();
+ }
+ });
+ }
+
+ });
+
+ try {
+ newFoo.setUserName("Barney");
+ fail();
+ } catch (IllegalStateException e) {
+ /* pass, cannot change a request that is in flight */
+ }
+ }
+ });
+ }
+
+ public void testMultipleEdits() {
+ RequestContext c1 = req.simpleFooRequest();
+ SimpleFooProxy proxy = c1.create(SimpleFooProxy.class);
+ // Re-editing is idempotent
+ assertSame(proxy, c1.edit(c1.edit(proxy)));
+
+ // Should not allow "crossing the steams"
+ RequestContext c2 = req.simpleFooRequest();
+ try {
+ c2.edit(proxy);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ /**
+ * Ensures that a service method can respond with a null value.
+ */
+ public void testNullEntityProxyResult() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().returnNullSimpleFoo().fire(new NullReceiver());
+ }
/**
* Test that a null value can be sent in a request.
@@ -639,6 +832,14 @@
}
});
}
+
+ /**
+ * Ensures that a service method can respond with a null value.
+ */
+ public void testNullListResult() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().returnNullList().fire(new NullReceiver());
+ }
/**
* Test that a null value can be sent in a request.
@@ -691,6 +892,14 @@
}
});
}
+
+ /**
+ * Ensures that a service method can respond with a null value.
+ */
+ public void testNullStringResult() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().returnNullString().fire(new NullReceiver());
+ }
/**
* Test that a null value can be sent within a list of entities.
@@ -723,7 +932,7 @@
*/
public void testNullValueInIntegerListRequest() {
delayTestFinish(DELAY_TEST_FINISH);
- List<Integer> list = Arrays.asList(new Integer[] {1, 2, null});
+ List<Integer> list = Arrays.asList(new Integer[]{1, 2, null});
final Request<Void> fooReq =
req.simpleFooRequest().receiveNullValueInIntegerList(
list);
fooReq.fire(new Receiver<Void>() {
@@ -739,7 +948,7 @@
*/
public void testNullValueInStringListRequest() {
delayTestFinish(DELAY_TEST_FINISH);
- List<String> list = Arrays.asList(new String[] {"nonnull", "null",
null});
+ List<String> list = Arrays.asList(new String[]{"nonnull", "null",
null});
final Request<Void> fooReq =
req.simpleFooRequest().receiveNullValueInStringList(
list);
fooReq.fire(new Receiver<Void>() {
@@ -749,164 +958,6 @@
}
});
}
-
- /**
- * Ensures that a service method can respond with a null value.
- */
- public void testNullListResult() {
- delayTestFinish(DELAY_TEST_FINISH);
- simpleFooRequest().returnNullList().fire(new NullReceiver());
- }
-
- public void testMultipleEdits() {
- RequestContext c1 = req.simpleFooRequest();
- SimpleFooProxy proxy = c1.create(SimpleFooProxy.class);
- // Re-editing is idempotent
- assertSame(proxy, c1.edit(c1.edit(proxy)));
-
- // Should not allow "crossing the steams"
- RequestContext c2 = req.simpleFooRequest();
- try {
- c2.edit(proxy);
- fail();
- } catch (IllegalArgumentException expected) {
- }
- }
-
- /**
- * Ensures that a service method can respond with a null value.
- */
- public void testNullEntityProxyResult() {
- delayTestFinish(DELAY_TEST_FINISH);
- simpleFooRequest().returnNullSimpleFoo().fire(new NullReceiver());
- }
-
- /**
- * Ensures that a service method can respond with a null value.
- */
- public void testNullStringResult() {
- delayTestFinish(DELAY_TEST_FINISH);
- simpleFooRequest().returnNullString().fire(new NullReceiver());
- }
-
- /*
- * tests that (a) any method can have a side effect that is handled
correctly.
- * (b) instance methods are handled correctly and (c) a request cannot be
- * reused after a successful response is received. (Yet?)
- */
- public void testMethodWithSideEffects() {
- delayTestFinish(DELAY_TEST_FINISH);
-
- final SimpleFooEventHandler<SimpleFooProxy> handler = new
SimpleFooEventHandler<SimpleFooProxy>();
- EntityProxyChange.registerForProxyType(req.getEventBus(),
- SimpleFooProxy.class, handler);
-
- simpleFooRequest().findSimpleFooById(999L).fire(
- new Receiver<SimpleFooProxy>() {
-
- @Override
- public void onSuccess(SimpleFooProxy newFoo) {
- assertEquals(1, handler.updateEventCount);
- assertEquals(1, handler.totalEventCount);
- SimpleFooRequest context = simpleFooRequest();
- final Request<Long> mutateRequest =
context.countSimpleFooWithUserNameSideEffect().using(
- newFoo);
- newFoo = context.edit(newFoo);
- newFoo.setUserName("Ray");
- mutateRequest.fire(new Receiver<Long>() {
- @Override
- public void onSuccess(Long response) {
- assertCannotFire(mutateRequest);
- assertEquals(new Long(2L), response);
- assertEquals(2, handler.updateEventCount);
- assertEquals(2, handler.totalEventCount);
-
- // confirm that the instance method did have the desired
- // sideEffect.
- simpleFooRequest().findSimpleFooById(999L).fire(
- new Receiver<SimpleFooProxy>() {
- @Override
- public void onSuccess(SimpleFooProxy finalFoo) {
- assertEquals("Ray", finalFoo.getUserName());
- assertEquals(2, handler.updateEventCount);
- assertEquals(2, handler.totalEventCount);
- finishTestAndReset();
- }
- });
- }
-
- });
-
- try {
- newFoo.setUserName("Barney");
- fail();
- } catch (IllegalStateException e) {
- /* pass, cannot change a request that is in flight */
- }
- }
- });
- }
-
- /**
- * 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(DELAY_TEST_FINISH);
-
- // Persist bar.
- SimpleBarRequest context = req.simpleBarRequest();
- final SimpleBarProxy bar = context.create(SimpleBarProxy.class);
- context.persistAndReturnSelf().using(bar).fire(
- new Receiver<SimpleBarProxy>() {
- @Override
- public void onSuccess(SimpleBarProxy persistentBar) {
- // Persist foo with bar as a child.
- SimpleFooRequest context = req.simpleFooRequest();
- SimpleFooProxy foo = context.create(SimpleFooProxy.class);
- final Request<SimpleFooProxy> persistRequest =
context.persistAndReturnSelf().using(
- foo);
- foo = context.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.
- SimpleFooRequest context = req.simpleFooRequest();
- final Request<Void> deleteRequest =
context.deleteBar().using(
- persistentFoo);
- SimpleFooProxy editable = context.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();
- }
- });
- }
- });
- }
- });
- }
public void testPersistAllValueTypes() {
delayTestFinish(DELAY_TEST_FINISH);
@@ -915,8 +966,8 @@
SimpleFooProxy f = r.create(SimpleFooProxy.class);
f.setUserName("user name");
- f.setByteField((byte)100);
- f.setShortField((short)12345);
+ f.setByteField((byte) 100);
+ f.setShortField((short) 12345);
f.setFloatField(1234.56f);
f.setDoubleField(1.2345);
f.setLongField(1234L);
@@ -928,8 +979,8 @@
@Override
public void onSuccess(SimpleFooProxy f) {
assertEquals("user name", f.getUserName());
- assertEquals(Byte.valueOf((byte)100), f.getByteField());
- assertEquals(Short.valueOf((short)12345), f.getShortField());
+ assertEquals(Byte.valueOf((byte) 100), f.getByteField());
+ assertEquals(Short.valueOf((short) 12345), f.getShortField());
assertEquals(Float.valueOf(1234.56f), f.getFloatField());
assertEquals(Double.valueOf(1.2345), f.getDoubleField());
assertEquals(Long.valueOf(1234L), f.getLongField());
@@ -966,35 +1017,35 @@
fooProxy.setBarField(barProxy);
fooProxy.setUserName("Hello");
fooProxy.setByteField((byte) 55);
- context.persistAndReturnSelf().using(fooProxy).fire(
- new Receiver<SimpleFooProxy>() {
- @Override
- public void onSuccess(SimpleFooProxy received) {
- // Check that Foo points to Bar
- assertNotNull(received.getBarField());
- assertEquals(barProxy.stableId(),
- received.getBarField().stableId());
- assertEquals("Hello", received.getUserName());
- assertTrue(55 == received.getByteField());
-
- // Unset the association
- SimpleFooRequest context = simpleFooRequest();
- received = context.edit(received);
- received.setBarField(null);
- received.setUserName(null);
- received.setByteField(null);
-
context.persistAndReturnSelf().using(received).fire(
- new Receiver<SimpleFooProxy>() {
- @Override
- public void onSuccess(SimpleFooProxy
response) {
- assertNull(response.getBarField());
- assertNull(response.getUserName());
- assertNull(response.getByteField());
- finishTestAndReset();
- }
- });
- }
- });
+ context.persistAndReturnSelf().using(fooProxy).with(
+ "barField").fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy received) {
+ // Check that Foo points to Bar
+ assertNotNull(received.getBarField());
+ assertEquals(barProxy.stableId(),
+ received.getBarField().stableId());
+ assertEquals("Hello", received.getUserName());
+ assertTrue(55 == received.getByteField());
+
+ // Unset the association
+ SimpleFooRequest context = simpleFooRequest();
+ received = context.edit(received);
+ received.setBarField(null);
+ received.setUserName(null);
+ received.setByteField(null);
+
context.persistAndReturnSelf().using(received).fire(
+ new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy
response) {
+ assertNull(response.getBarField());
+ assertNull(response.getUserName());
+ assertNull(response.getByteField());
+ finishTestAndReset();
+ }
+ });
+ }
+ });
}
});
}
@@ -1053,6 +1104,30 @@
}
});
}
+
+ /**
+ * Ensure that a relationship can be set up between two newly-created
objects.
+ */
+ public void testPersistFutureToFuture() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ SimpleFooRequest context = simpleFooRequest();
+ SimpleFooProxy newFoo = context.create(SimpleFooProxy.class);
+ final SimpleBarProxy newBar = context.create(SimpleBarProxy.class);
+
+ Request<SimpleFooProxy> fooReq = context.persistAndReturnSelf().using(
+ newFoo).with("barField");
+ newFoo = context.edit(newFoo);
+ newFoo.setBarField(newBar);
+
+ fooReq.fire(new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ assertNotNull(response.getBarField());
+ assertEquals(newBar.stableId(), response.getBarField().stableId());
+ finishTestAndReset();
+ }
+ });
+ }
/*
* Find Entity2 Create Entity, Persist Entity Relate Entity2 to Entity
Persist
@@ -1091,30 +1166,6 @@
}
});
}
-
- /**
- * Ensure that a relationship can be set up between two newly-created
objects.
- */
- public void testPersistFutureToFuture() {
- delayTestFinish(DELAY_TEST_FINISH);
- SimpleFooRequest context = simpleFooRequest();
- SimpleFooProxy newFoo = context.create(SimpleFooProxy.class);
- final SimpleBarProxy newBar = context.create(SimpleBarProxy.class);
-
- Request<SimpleFooProxy> fooReq = context.persistAndReturnSelf().using(
- newFoo).with("barField");
- newFoo = context.edit(newFoo);
- newFoo.setBarField(newBar);
-
- fooReq.fire(new Receiver<SimpleFooProxy>() {
- @Override
- public void onSuccess(SimpleFooProxy response) {
- assertNotNull(response.getBarField());
- assertEquals(newBar.stableId(), response.getBarField().stableId());
- finishTestAndReset();
- }
- });
- }
/*
* Create Entity, Persist Entity Create Entity2, Perist Entity2 relate
Entity2
@@ -1976,14 +2027,14 @@
}
});
}
-
- protected SimpleFooRequest simpleFooRequest() {
- return req.simpleFooRequest();
- }
protected SimpleBarRequest simpleBarRequest() {
return req.simpleBarRequest();
}
+
+ protected SimpleFooRequest simpleFooRequest() {
+ return req.simpleFooRequest();
+ }
private void assertCannotFire(final Request<Long> mutateRequest) {
try {
=======================================
--- /trunk/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
Mon Oct 4 15:35:00 2010
+++ /trunk/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
Tue Oct 5 09:11:00 2010
@@ -21,6 +21,7 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -58,6 +59,16 @@
simpleFoo.setBarField(simpleBar);
return simpleFoo;
}
+
+ public static SimpleFoo fetchDoubleReference() {
+ SimpleFoo foo = new SimpleFoo();
+ SimpleFoo foo2 = new SimpleFoo();
+ foo.setFooField(foo2);
+ foo.setSelfOneToManyField(Arrays.asList(foo2));
+ foo.persist();
+ foo2.persist();
+ return foo;
+ }
public static List<SimpleFoo> findAll() {
return new ArrayList<SimpleFoo>(get().values());
@@ -107,6 +118,36 @@
list.add(3);
return list;
}
+
+ public static SimpleFoo getSimpleFooWithSubPropertyCollection() {
+ SimpleFoo foo = new SimpleFoo();
+ SimpleFoo subFoo = new SimpleFoo();
+ SimpleFoo subSubFoo = new SimpleFoo();
+ subFoo.setFooField(subSubFoo);
+ subSubFoo.setUserName("I'm here");
+ subSubFoo.persist();
+ subFoo.persist();
+ foo.persist();
+ foo.setSelfOneToManyField(Arrays.asList(subFoo));
+ return foo;
+ }
+
+ public static SimpleFoo getTripletReference() {
+ SimpleFoo foo1 = new SimpleFoo();
+ SimpleFoo foo2 = new SimpleFoo();
+ SimpleFoo foo3 = new SimpleFoo();
+ ArrayList<SimpleFoo> foos = new ArrayList<SimpleFoo>();
+ foos.add(foo2);
+ ArrayList<SimpleFoo> subFoos = new ArrayList<SimpleFoo>();
+ subFoos.add(foo3);
+ foo1.setSelfOneToManyField(foos);
+ foo2.setSelfOneToManyField(subFoos);
+ foo3.setFooField(foo2);
+ foo1.persist();
+ foo2.persist();
+ foo3.persist();
+ return foo1;
+ }
public static Boolean processBooleanList(List<Boolean> values) {
return values.get(0);
=======================================
---
/trunk/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
Fri Oct 1 18:15:55 2010
+++
/trunk/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
Tue Oct 5 09:11:00 2010
@@ -37,6 +37,8 @@
Request<SimpleFooProxy> echoComplex(SimpleFooProxy fooProxy,
SimpleBarProxy barProxy);
+ Request<SimpleFooProxy> fetchDoubleReference();
+
Request<List<SimpleFooProxy>> findAll();
Request<SimpleFooProxy> findSimpleFooById(Long id);
@@ -45,6 +47,10 @@
Request<Set<Integer>> getNumberSet();
+ Request<SimpleFooProxy> getSimpleFooWithSubPropertyCollection();
+
+ Request<SimpleFooProxy> getTripletReference();
+
InstanceRequest<SimpleFooProxy, String> hello(SimpleBarProxy proxy);
InstanceRequest<SimpleFooProxy, Void> persist();
@@ -59,11 +65,11 @@
Request<SimpleEnum> processEnumList(List<SimpleEnum> values);
- Request<String> processString(String value);
-
InstanceRequest<SimpleFooProxy, String> processList(
List<SimpleFooProxy> values);
+ Request<String> processString(String value);
+
InstanceRequest<SimpleFooProxy, Void> receiveNull(String value);
Request<Void> receiveNullList(List<SimpleFooProxy> value);
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors