Integrate r10346 into GWT 2.4 branch.
git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/2.4@10368 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 38e5a97..4751d8d 100644
--- a/user/src/com/google/web/bindery/requestfactory/server/Resolver.java
+++ b/user/src/com/google/web/bindery/requestfactory/server/Resolver.java
@@ -22,7 +22,6 @@
import com.google.web.bindery.autobean.shared.ValueCodex;
import com.google.web.bindery.autobean.vm.impl.TypeUtils;
import com.google.web.bindery.requestfactory.shared.BaseProxy;
-import com.google.web.bindery.requestfactory.shared.EntityProxy;
import com.google.web.bindery.requestfactory.shared.EntityProxyId;
import com.google.web.bindery.requestfactory.shared.impl.Constants;
import com.google.web.bindery.requestfactory.shared.impl.SimpleProxyId;
@@ -34,9 +33,11 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.SortedSet;
import java.util.TreeSet;
/**
@@ -87,6 +88,163 @@
}
/**
+ * Copies values and references from a domain object to a client object. This
+ * type does not descend into referenced objects.
+ */
+ private class PropertyResolver extends AutoBeanVisitor {
+ private final Object domainEntity;
+ private final boolean isOwnerValueProxy;
+ private final boolean needsSimpleValues;
+ private final Set<String> propertyRefs;
+
+ private PropertyResolver(Resolution resolution) {
+ ResolutionKey key = resolution.getResolutionKey();
+ this.domainEntity = key.getDomainObject();
+ this.isOwnerValueProxy = state.isValueType(TypeUtils.ensureBaseType(key.requestedType));
+ this.needsSimpleValues = resolution.needsSimpleValues();
+ this.propertyRefs = resolution.takeWork();
+ }
+
+ @Override
+ public boolean visitReferenceProperty(String propertyName, AutoBean<?> value,
+ PropertyContext ctx) {
+ /*
+ * Send the property if the enclosing type is a ValueProxy, if the owner
+ * requested the property, or if the property is a list of values.
+ */
+ Class<?> elementType =
+ ctx instanceof CollectionPropertyContext ? ((CollectionPropertyContext) ctx)
+ .getElementType() : null;
+ boolean shouldSend =
+ isOwnerValueProxy || matchesPropertyRef(propertyRefs, propertyName)
+ || elementType != null && ValueCodex.canDecode(elementType);
+
+ if (!shouldSend) {
+ return false;
+ }
+
+ // Call the getter
+ Object domainValue = service.getProperty(domainEntity, propertyName);
+ if (domainValue == null) {
+ return false;
+ }
+
+ // Turn the domain object into something usable on the client side
+ Type type;
+ if (elementType == null) {
+ type = ctx.getType();
+ } else {
+ type = new CollectionType(ctx.getType(), elementType);
+ }
+ Resolution resolution = resolveClientValue(domainValue, type);
+ addPathsToResolution(resolution, propertyName, propertyRefs);
+ ctx.set(resolution.getClientObject());
+ return false;
+ }
+
+ @Override
+ public boolean visitValueProperty(String propertyName, Object value, PropertyContext ctx) {
+ /*
+ * Only call the getter for simple values once since they're not
+ * explicitly enumerated.
+ */
+ if (needsSimpleValues) {
+ // Limit unrequested value properties?
+ value = service.getProperty(domainEntity, propertyName);
+ ctx.set(value);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Tracks the state of resolving a single client object.
+ */
+ private static class Resolution {
+ /**
+ * There's no Collections shortcut for this.
+ */
+ private static final SortedSet<String> EMPTY = Collections
+ .unmodifiableSortedSet(new TreeSet<String>());
+
+ /**
+ * The client object.
+ */
+ private final Object clientObject;
+
+ /**
+ * A one-shot flag for {@link #hasWork()} to ensure that simple properties
+ * will be resolved, even when there's no requested property set.
+ */
+ private boolean needsSimpleValues;
+ private SortedSet<String> toResolve = EMPTY;
+ private final SortedSet<String> resolved = new TreeSet<String>();
+ private final ResolutionKey key;
+
+ public Resolution(Object simpleValue) {
+ assert !(simpleValue instanceof Resolution);
+ this.clientObject = simpleValue;
+ this.key = null;
+ }
+
+ public Resolution(ResolutionKey key, BaseProxy clientObject) {
+ this.clientObject = clientObject;
+ this.key = key;
+ needsSimpleValues = true;
+ }
+
+ /**
+ * Removes the prefix from each requested path and enqueues paths that have
+ * not been previously resolved for the next batch of work.
+ */
+ public void addPaths(String prefix, Collection<String> requestedPaths) {
+ // Identity comparison intentional
+ if (toResolve == EMPTY) {
+ toResolve = new TreeSet<String>();
+ }
+ prefix = prefix.isEmpty() ? prefix : (prefix + ".");
+ int prefixLength = prefix.length();
+ for (String path : requestedPaths) {
+ if (path.startsWith(prefix)) {
+ toResolve.add(path.substring(prefixLength));
+ }
+ }
+ toResolve.removeAll(resolved);
+ if (toResolve.isEmpty()) {
+ toResolve = EMPTY;
+ }
+ }
+
+ public Object getClientObject() {
+ return clientObject;
+ }
+
+ public ResolutionKey getResolutionKey() {
+ return key;
+ }
+
+ public boolean hasWork() {
+ return needsSimpleValues || !toResolve.isEmpty();
+ }
+
+ public boolean needsSimpleValues() {
+ return needsSimpleValues;
+ }
+
+ /**
+ * Returns client-object-relative reference paths that should be further
+ * resolved.
+ */
+ public SortedSet<String> takeWork() {
+ needsSimpleValues = false;
+ SortedSet<String> toReturn = toResolve;
+ resolved.addAll(toReturn);
+ toResolve = EMPTY;
+ return toReturn;
+ }
+ }
+
+ /**
* Used to map the objects being resolved and its API slice to the client-side
* value. This handles the case where a domain object is returned to the
* client mapped to two proxies of differing types.
@@ -118,6 +276,10 @@
return true;
}
+ public Object getDomainObject() {
+ return domainObject;
+ }
+
@Override
public int hashCode() {
return hashCode;
@@ -163,12 +325,40 @@
}
/**
+ * Expand the property references in an InvocationMessage into a
+ * fully-expanded list of properties. For example, <code>[foo.bar.baz]</code>
+ * will be converted into <code>[foo, foo.bar, foo.bar.baz]</code>.
+ */
+ private static Set<String> expandPropertyRefs(Set<String> refs) {
+ if (refs == null) {
+ return Collections.emptySet();
+ }
+
+ Set<String> toReturn = new TreeSet<String>();
+ for (String raw : refs) {
+ for (int idx = raw.length(); idx >= 0; idx = raw.lastIndexOf('.', idx - 1)) {
+ toReturn.add(raw.substring(0, idx));
+ }
+ }
+ return toReturn;
+ }
+
+ /**
+ * Maps proxy instances to the Resolution objects.
+ */
+ private Map<BaseProxy, Resolution> clientObjectsToResolutions =
+ new HashMap<BaseProxy, Resolution>();
+ /**
* Maps domain values to client values. This map prevents cycles in the object
* graph from causing infinite recursion.
*/
- private final Map<ResolutionKey, Object> resolved = new HashMap<ResolutionKey, Object>();
+ private final Map<ResolutionKey, Resolution> resolved = new HashMap<ResolutionKey, Resolution>();
private final ServiceLayer service;
private final RequestState state;
+ /**
+ * Contains Resolutions with path references that have not yet been resolved.
+ */
+ private Set<Resolution> toProcess = new LinkedHashSet<Resolution>();
private int syntheticId;
/**
@@ -190,7 +380,23 @@
* @param propertyRefs the property references requested by the client
*/
public Object resolveClientValue(Object domainValue, Type assignableTo, Set<String> propertyRefs) {
- return resolveClientValue(domainValue, assignableTo, getPropertyRefs(propertyRefs), "");
+ Resolution toReturn = resolveClientValue(domainValue, assignableTo);
+ if (toReturn == null) {
+ return null;
+ }
+ addPathsToResolution(toReturn, "", expandPropertyRefs(propertyRefs));
+ while (!toProcess.isEmpty()) {
+ List<Resolution> working = new ArrayList<Resolution>(toProcess);
+ toProcess.clear();
+ for (Resolution resolution : working) {
+ if (resolution.hasWork()) {
+ AutoBean<BaseProxy> bean =
+ AutoBeanUtils.getAutoBean((BaseProxy) resolution.getClientObject());
+ bean.accept(new PropertyResolver(resolution));
+ }
+ }
+ }
+ return toReturn.getClientObject();
}
/**
@@ -229,30 +435,69 @@
}
/**
- * Expand the property references in an InvocationMessage into a
- * fully-expanded list of properties. For example, <code>[foo.bar.baz]</code>
- * will be converted into <code>[foo, foo.bar, foo.bar.baz]</code>.
+ * Calls {@link Resolution#addPaths(String, Collection)}, enqueuing
+ * {@code key} if {@link Resolution#hasWork()} returns {@code true}. This
+ * method will also expand paths on the members of Collections.
*/
- private Set<String> getPropertyRefs(Set<String> refs) {
- if (refs == null) {
- return Collections.emptySet();
+ private void addPathsToResolution(Resolution resolution, String prefix, Set<String> propertyRefs) {
+ if (propertyRefs.isEmpty()) {
+ // No work to do
+ return;
}
-
- Set<String> toReturn = new TreeSet<String>();
- for (String raw : refs) {
- for (int idx = raw.length(); idx >= 0; idx = raw.lastIndexOf('.', idx - 1)) {
- toReturn.add(raw.substring(0, idx));
+ if (resolution.getResolutionKey() != null) {
+ // Working on a proxied type
+ assert resolution.getClientObject() instanceof BaseProxy : "Expecting BaseProxy, found "
+ + resolution.getClientObject().getClass().getCanonicalName();
+ resolution.addPaths(prefix, propertyRefs);
+ if (resolution.hasWork()) {
+ toProcess.add(resolution);
}
+ return;
}
- return toReturn;
+ if (resolution.getClientObject() instanceof Collection) {
+ // Pass the paths onto the Resolutions for the contained elements
+ Collection<?> collection = (Collection<?>) resolution.getClientObject();
+ for (Object obj : collection) {
+ Resolution subResolution = clientObjectsToResolutions.get(obj);
+ // subResolution will be null for List<Integer>, etc.
+ if (subResolution != null) {
+ addPathsToResolution(subResolution, prefix, propertyRefs);
+ }
+ }
+ return;
+ }
+ assert false : "Should not add paths to client type "
+ + resolution.getClientObject().getClass().getCanonicalName();
}
/**
- * Converts a domain entity into an EntityProxy that will be sent to the
- * client.
+ * Creates a resolution for a simple value.
*/
- private <T extends BaseProxy> T resolveClientProxy(final Object domainEntity, Class<T> proxyType,
- final Set<String> propertyRefs, ResolutionKey key, final String prefix) {
+ private Resolution makeResolution(Object domainValue) {
+ assert !state.isEntityType(domainValue.getClass())
+ && !state.isValueType(domainValue.getClass()) : "Not a simple value type";
+ return new Resolution(domainValue);
+ }
+
+ /**
+ * Create or reuse a Resolution for a proxy object.
+ */
+ private Resolution makeResolution(ResolutionKey key, BaseProxy clientObject) {
+ Resolution resolution = resolved.get(key);
+ if (resolution == null) {
+ resolution = new Resolution(key, clientObject);
+ clientObjectsToResolutions.put(clientObject, resolution);
+ toProcess.add(resolution);
+ resolved.put(key, resolution);
+ }
+ return resolution;
+ }
+
+ /**
+ * Creates a proxy instance held by a Resolution for a given domain type.
+ */
+ private <T extends BaseProxy> Resolution resolveClientProxy(Object domainEntity,
+ Class<T> proxyType, ResolutionKey key) {
if (domainEntity == null) {
return null;
}
@@ -260,7 +505,6 @@
SimpleProxyId<? extends BaseProxy> id = state.getStableId(domainEntity);
boolean isEntityProxy = state.isEntityType(proxyType);
- final boolean isOwnerValueProxy = state.isValueType(proxyType);
Object domainVersion;
// Create the id or update an ephemeral id by calculating its address
@@ -305,7 +549,6 @@
@SuppressWarnings("unchecked")
AutoBean<T> bean = (AutoBean<T>) state.getBeanForPayload(id, domainEntity);
- resolved.put(key, bean.as());
bean.setTag(Constants.IN_RESPONSE, true);
if (domainVersion != null) {
Splittable flatVersion = state.flatten(domainVersion);
@@ -313,80 +556,31 @@
.getPayload()));
}
- bean.accept(new AutoBeanVisitor() {
-
- @Override
- public boolean visitReferenceProperty(String propertyName, AutoBean<?> value,
- PropertyContext ctx) {
- // Does the user care about the property?
- String newPrefix = (prefix.length() > 0 ? (prefix + ".") : "") + propertyName;
-
- /*
- * Send the property if the enclosing type is a ValueProxy, if the owner
- * requested the property, or if the property is a list of values.
- */
- Class<?> elementType =
- ctx instanceof CollectionPropertyContext ? ((CollectionPropertyContext) ctx)
- .getElementType() : null;
- boolean shouldSend =
- isOwnerValueProxy || matchesPropertyRef(propertyRefs, newPrefix) || elementType != null
- && ValueCodex.canDecode(elementType);
-
- if (!shouldSend) {
- return false;
- }
-
- // Call the getter
- Object domainValue = service.getProperty(domainEntity, propertyName);
- if (domainValue == null) {
- return false;
- }
-
- // Turn the domain object into something usable on the client side
- Type type;
- if (elementType == null) {
- type = ctx.getType();
- } else {
- type = new CollectionType(ctx.getType(), elementType);
- }
- Object clientValue = resolveClientValue(domainValue, type, propertyRefs, newPrefix);
-
- ctx.set(clientValue);
- return false;
- }
-
- @Override
- public boolean visitValueProperty(String propertyName, Object value, PropertyContext ctx) {
- // Limit unrequested value properties?
- value = service.getProperty(domainEntity, propertyName);
- ctx.set(value);
- return false;
- }
- });
-
- return bean.as();
+ T clientObject = bean.as();
+ return makeResolution(key, clientObject);
}
/**
- * Recursive-descent implementation.
+ * Creates a Resolution object that holds a client value that represents the
+ * given domain value. The resolved client value will be assignable to
+ * {@code clientType}.
*/
- private Object resolveClientValue(Object domainValue, Type returnType, Set<String> propertyRefs,
- String prefix) {
+ private Resolution resolveClientValue(Object domainValue, Type clientType) {
if (domainValue == null) {
return null;
}
- boolean anyType = returnType == null;
+ boolean anyType = clientType == null;
if (anyType) {
- returnType = Object.class;
+ clientType = Object.class;
}
- Class<?> assignableTo = TypeUtils.ensureBaseType(returnType);
- ResolutionKey key = new ResolutionKey(domainValue, returnType);
+ Class<?> assignableTo = TypeUtils.ensureBaseType(clientType);
+ ResolutionKey key = new ResolutionKey(domainValue, clientType);
- Object previous = resolved.get(key);
- if (previous != null && assignableTo.isInstance(previous)) {
- return assignableTo.cast(previous);
+ Resolution previous = resolved.get(key);
+ if (previous != null && assignableTo.isInstance(previous.getClientObject())) {
+ return previous;
}
Class<?> returnClass = service.resolveClientType(domainValue.getClass(), assignableTo, true);
@@ -397,7 +591,7 @@
// Pass simple values through
if (ValueCodex.canDecode(returnClass)) {
- return assignableTo.cast(domainValue);
+ return makeResolution(domainValue);
}
// Convert entities to EntityProxies or EntityProxyIds
@@ -405,11 +599,7 @@
boolean isId = EntityProxyId.class.isAssignableFrom(returnClass);
if (isProxy || isId) {
Class<? extends BaseProxy> proxyClass = returnClass.asSubclass(BaseProxy.class);
- BaseProxy entity = resolveClientProxy(domainValue, proxyClass, propertyRefs, key, prefix);
- if (isId) {
- return assignableTo.cast(((EntityProxy) entity).stableId());
- }
- return assignableTo.cast(entity);
+ return resolveClientProxy(domainValue, proxyClass, key);
}
// Convert collections
@@ -422,13 +612,12 @@
} else {
throw new ReportableException("Unsupported collection type" + returnClass.getName());
}
- resolved.put(key, accumulator);
- Type elementType = TypeUtils.getSingleParameterization(Collection.class, returnType);
+ Type elementType = TypeUtils.getSingleParameterization(Collection.class, clientType);
for (Object o : (Collection<?>) domainValue) {
- accumulator.add(resolveClientValue(o, elementType, propertyRefs, prefix));
+ accumulator.add(resolveClientValue(o, elementType).getClientObject());
}
- return assignableTo.cast(accumulator);
+ return makeResolution(accumulator);
}
throw new ReportableException("Unsupported domain type " + returnClass.getCanonicalName());
diff --git a/user/src/com/google/web/bindery/requestfactory/server/SimpleRequestProcessor.java b/user/src/com/google/web/bindery/requestfactory/server/SimpleRequestProcessor.java
index 0df5c46..078ad2a 100644
--- a/user/src/com/google/web/bindery/requestfactory/server/SimpleRequestProcessor.java
+++ b/user/src/com/google/web/bindery/requestfactory/server/SimpleRequestProcessor.java
@@ -60,6 +60,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import javax.validation.ConstraintViolation;
@@ -416,7 +418,12 @@
// No method invocations which can happen via RequestContext.fire()
return;
}
+ List<Method> contextMethods = new ArrayList<Method>(invocations.size());
+ List<Object> invocationResults = new ArrayList<Object>(invocations.size());
+ Map<Object, SortedSet<String>> allPropertyRefs = new HashMap<Object, SortedSet<String>>();
for (InvocationMessage invocation : invocations) {
+ Object domainReturnValue;
+ boolean ok;
try {
// Find the Method
String operation = invocation.getOperation();
@@ -425,6 +432,7 @@
throw new UnexpectedException("Cannot resolve operation " + invocation.getOperation(),
null);
}
+ contextMethods.add(contextMethod);
Method domainMethod = service.resolveDomainMethod(operation);
if (domainMethod == null) {
throw new UnexpectedException(
@@ -440,20 +448,42 @@
args.add(0, serviceInstance);
}
// Invoke it
- Object returnValue = service.invoke(domainMethod, args.toArray());
-
+ domainReturnValue = service.invoke(domainMethod, args.toArray());
+ if (invocation.getPropertyRefs() != null) {
+ SortedSet<String> paths = allPropertyRefs.get(domainReturnValue);
+ if (paths == null) {
+ paths = new TreeSet<String>();
+ allPropertyRefs.put(domainReturnValue, paths);
+ }
+ paths.addAll(invocation.getPropertyRefs());
+ }
+ ok = true;
+ } catch (ReportableException e) {
+ domainReturnValue = AutoBeanCodex.encode(createFailureMessage(e));
+ ok = false;
+ }
+ invocationResults.add(domainReturnValue);
+ success.add(ok);
+ }
+ Iterator<Method> contextMethodIt = contextMethods.iterator();
+ Iterator<Object> objects = invocationResults.iterator();
+ Iterator<Boolean> successes = success.iterator();
+ while (successes.hasNext()) {
+ assert contextMethodIt.hasNext();
+ assert objects.hasNext();
+ Method contextMethod = contextMethodIt.next();
+ Object returnValue = objects.next();
+ if (successes.next()) {
// Convert domain object to client object
Type requestReturnType = service.getRequestReturnType(contextMethod);
returnValue =
state.getResolver().resolveClientValue(returnValue, requestReturnType,
- invocation.getPropertyRefs());
+ allPropertyRefs.get(returnValue));
// Convert the client object to a string
results.add(EntityCodex.encode(returnState, returnValue));
- success.add(true);
- } catch (ReportableException e) {
- results.add(AutoBeanCodex.encode(createFailureMessage(e)));
- success.add(false);
+ } else {
+ results.add((Splittable) returnValue);
}
}
}
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 df32514..fdff661 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
@@ -1122,7 +1122,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>() {
@Override
@@ -1137,7 +1137,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>() {
@Override
@@ -1148,6 +1148,14 @@
}
/**
+ * Test that a proxy only referenced via a parameterization is available.
+ */
+ public void testOnlyUsedInList() {
+ OnlyUsedInListProxy proxy = simpleFooRequest().create(OnlyUsedInListProxy.class);
+ assertNotNull(proxy);
+ }
+
+ /**
* Tests a message consisting only of operations, with no invocations.
*/
public void testOperationOnlyMessage() {
@@ -1325,11 +1333,6 @@
});
}
- /*
- * TODO: all these tests should check the final values. It will be easy when
- * we have better persistence than the singleton pattern.
- */
-
/**
* Ensure that a relationship can be set up between two newly-created objects.
*/
@@ -1547,6 +1550,11 @@
});
}
+ /*
+ * TODO: all these tests should check the final values. It will be easy when
+ * we have better persistence than the singleton pattern.
+ */
+
public void testPersistSelfOneToManyExistingEntityExistingRelation() {
delayTestFinish(DELAY_TEST_FINISH);
@@ -1606,11 +1614,6 @@
* TODO: all these tests should check the final values. It will be easy when
* we have better persistence than the singleton pattern.
*/
-
- /*
- * TODO: all these tests should check the final values. It will be easy when
- * we have better persistence than the singleton pattern.
- */
public void testPersistValueListNull() {
delayTestFinish(DELAY_TEST_FINISH);
simpleFooRequest().findSimpleFooById(999L).fire(new Receiver<SimpleFooProxy>() {
@@ -2050,6 +2053,48 @@
});
}
+ public void testPropertyRefsOnRecursiveProxyStructures() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().getFlattenedTripletReference().with("selfOneToManyField").fire(
+ new Receiver<List<SimpleFooProxy>>() {
+ @Override
+ public void onSuccess(List<SimpleFooProxy> response) {
+ for (int i = 0; i < response.size(); i++) {
+ SimpleFooProxy proxy = response.get(i);
+ checkSerialization(proxy); // do not reassign proxy as we
+ // assertSame() later
+ assertNotNull("Missing selfOneToManyField for item at index " + i, proxy
+ .getSelfOneToManyField());
+ assertEquals(1, proxy.getSelfOneToManyField().size());
+ // last one references itself
+ SimpleFooProxy next = response.get(Math.min(i + 1, response.size() - 1));
+ assertSame("Item at index " + i
+ + " does not link the following item in its selfOneToManyField", proxy
+ .getSelfOneToManyField().get(0), next);
+ }
+ finishTestAndReset();
+ }
+ });
+ }
+
+ public void testPropertyRefsOnSameObjectReturnedTwice() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ SimpleFooRequest request = simpleFooRequest();
+ request.findSimpleFooById(1L);
+ request.findAll().with("barField").to(new Receiver<List<SimpleFooProxy>>() {
+ @Override
+ public void onSuccess(List<SimpleFooProxy> response) {
+ for (SimpleFooProxy proxy : response) {
+ proxy = checkSerialization(proxy);
+ assertNotNull("barField has not been retrieved on id=" + proxy.getId(), proxy
+ .getBarField());
+ }
+ finishTestAndReset();
+ }
+ });
+ request.fire();
+ }
+
public void testProxyList() {
delayTestFinish(DELAY_TEST_FINISH);
final Request<SimpleFooProxy> fooReq =
@@ -2260,14 +2305,6 @@
}
/**
- * Test that a proxy only referenced via a parameterization is available.
- */
- public void testOnlyUsedInList() {
- OnlyUsedInListProxy proxy = simpleFooRequest().create(OnlyUsedInListProxy.class);
- assertNotNull(proxy);
- }
-
- /**
* Check if a graph of unpersisted objects can be echoed.
*/
public void testUnpersistedEchoComplexGraph() {
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 46ce807..d3cceaa 100644
--- a/user/test/com/google/web/bindery/requestfactory/server/SimpleFoo.java
+++ b/user/test/com/google/web/bindery/requestfactory/server/SimpleFoo.java
@@ -104,8 +104,8 @@
* that doesn't allow any requests to be processed unless they're
* associated with an existing session.
*/
- Map<Long, SimpleFoo> value = (Map<Long, SimpleFoo>) req.getSession().getAttribute(
- SimpleFoo.class.getCanonicalName());
+ Map<Long, SimpleFoo> value =
+ (Map<Long, SimpleFoo>) req.getSession().getAttribute(SimpleFoo.class.getCanonicalName());
if (value == null) {
value = resetImpl();
}
@@ -113,6 +113,18 @@
}
}
+ public static List<SimpleFoo> getFlattenedTripletReference() {
+ SimpleFoo foo1 = new SimpleFoo();
+ SimpleFoo foo2 = new SimpleFoo();
+ SimpleFoo foo3 = new SimpleFoo();
+ foo1.setSelfOneToManyField(Arrays.asList(foo2));
+ foo2.setSelfOneToManyField(Arrays.asList(foo3));
+ foo1.persist();
+ foo2.persist();
+ foo3.persist();
+ return Arrays.asList(foo1, foo2, foo3);
+ }
+
public static List<Integer> getNumberList() {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
@@ -179,8 +191,7 @@
public static void pleaseCrash(Integer crashIf42or43) throws Exception {
if (crashIf42or43 == 42) {
- throw new UnsupportedOperationException(
- "THIS EXCEPTION IS EXPECTED BY A TEST");
+ throw new UnsupportedOperationException("THIS EXCEPTION IS EXPECTED BY A TEST");
}
if (crashIf42or43 == 43) {
throw new Exception("THIS EXCEPTION IS EXPECTED BY A TEST");
@@ -247,8 +258,8 @@
long expectedTime = expectedDate.getTime();
long actualTime = actual.next().getTime();
if (expectedTime != actualTime) {
- throw new IllegalArgumentException(expectedDate.getClass().getName()
- + " " + expectedTime + " != " + actualTime);
+ throw new IllegalArgumentException(expectedDate.getClass().getName() + " " + expectedTime
+ + " != " + actualTime);
}
}
@@ -271,22 +282,22 @@
public static void receiveNullList(List<SimpleFoo> value) {
if (value != null) {
- throw new IllegalArgumentException(
- "Expected value to be null. Actual value: \"" + value + "\"");
+ 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 + "\"");
+ 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 + "\"");
+ throw new IllegalArgumentException("Expected value to be null. Actual value: \"" + value
+ + "\"");
}
}
@@ -296,11 +307,10 @@
} 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.");
+ 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));
+ throw new IllegalArgumentException("Expected list.get(1) to return null. Actual: "
+ + list.get(1));
}
}
@@ -308,15 +318,12 @@
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.");
+ 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.");
+ 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)
- + "\"");
+ throw new IllegalArgumentException("Expected list.get(2) to return null. Actual: \""
+ + list.get(2) + "\"");
}
}
@@ -324,15 +331,12 @@
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.");
+ 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.");
+ 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)
- + "\"");
+ throw new IllegalArgumentException("Expected list.get(2) to return null. Actual: \""
+ + list.get(2) + "\"");
}
}
@@ -357,8 +361,7 @@
if (req == null) {
jreTestSingleton = instance;
} else {
- req.getSession().setAttribute(SimpleFoo.class.getCanonicalName(),
- instance);
+ req.getSession().setAttribute(SimpleFoo.class.getCanonicalName(), instance);
}
return instance;
}
@@ -666,8 +669,8 @@
public void receiveNull(String value) {
if (value != null) {
- throw new IllegalArgumentException(
- "Expected value to be null. Actual value: \"" + value + "\"");
+ throw new IllegalArgumentException("Expected value to be null. Actual value: \"" + value
+ + "\"");
}
}
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 ebc02c0..3c3290e 100644
--- a/user/test/com/google/web/bindery/requestfactory/shared/SimpleFooRequest.java
+++ b/user/test/com/google/web/bindery/requestfactory/shared/SimpleFooRequest.java
@@ -39,8 +39,7 @@
Request<SimpleFooProxy> echo(SimpleFooProxy proxy);
- Request<SimpleFooProxy> echoComplex(SimpleFooProxy fooProxy,
- SimpleBarProxy barProxy);
+ Request<SimpleFooProxy> echoComplex(SimpleFooProxy fooProxy, SimpleBarProxy barProxy);
Request<SimpleFooProxy> fetchDoubleReference();
@@ -48,6 +47,8 @@
Request<SimpleFooProxy> findSimpleFooById(Long id);
+ Request<List<SimpleFooProxy>> getFlattenedTripletReference();
+
Request<List<Integer>> getNumberList();
Request<Set<Integer>> getNumberSet();
@@ -80,8 +81,7 @@
Request<SimpleEnum> processEnumList(List<SimpleEnum> values);
- InstanceRequest<SimpleFooProxy, String> processList(
- List<SimpleFooProxy> values);
+ InstanceRequest<SimpleFooProxy, String> processList(List<SimpleFooProxy> values);
Request<String> processString(String value);
@@ -109,8 +109,7 @@
Request<String> returnNullString();
- Request<Void> returnOnlyUsedInParameterization(
- List<OnlyUsedInListProxy> values);
+ Request<Void> returnOnlyUsedInParameterization(List<OnlyUsedInListProxy> values);
Request<SimpleFooProxy> returnSimpleFooSubclass();