Add ServiceLocator API to allow service methods to be invoked on non-static methods.
http://code.google.com/p/google-web-toolkit/wiki/RequestFactory_2_1_1
Issue 5680.
Patch by: bobv
Review by: rchandia,rjrjr
Review at http://gwt-code-reviews.appspot.com/1162801
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9318 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/requestfactory/server/LocatorServiceLayer.java b/user/src/com/google/gwt/requestfactory/server/LocatorServiceLayer.java
index a2922e4..d5efc04 100644
--- a/user/src/com/google/gwt/requestfactory/server/LocatorServiceLayer.java
+++ b/user/src/com/google/gwt/requestfactory/server/LocatorServiceLayer.java
@@ -17,12 +17,19 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.Locator;
-import com.google.gwt.requestfactory.shared.LocatorFor;
-import com.google.gwt.requestfactory.shared.LocatorForName;
+import com.google.gwt.requestfactory.shared.ProxyFor;
+import com.google.gwt.requestfactory.shared.ProxyForName;
+import com.google.gwt.requestfactory.shared.Request;
+import com.google.gwt.requestfactory.shared.Service;
+import com.google.gwt.requestfactory.shared.ServiceLocator;
+import com.google.gwt.requestfactory.shared.ServiceName;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
/**
- * Adds support to the ServiceLayer chain for using {@link Locator} helper
- * objects.
+ * Adds support to the ServiceLayer chain for using {@link Locator} and
+ * {@link ServiceLocator} helper objects.
*/
final class LocatorServiceLayer extends ServiceLayerDecorator {
@@ -37,17 +44,15 @@
@Override
public <T extends Locator<?, ?>> T createLocator(Class<T> clazz) {
- Throwable ex;
- try {
- return clazz.newInstance();
- } catch (InstantiationException e) {
- ex = e;
- } catch (IllegalAccessException e) {
- ex = e;
- }
- return this.<T> die(ex,
- "Could not instantiate Locator %s. It is default-instantiable?",
- clazz.getCanonicalName());
+ return newInstance(clazz, Locator.class);
+ }
+
+ @Override
+ public Object createServiceInstance(Method contextMethod, Method domainMethod) {
+ Class<? extends ServiceLocator> locatorType = getTop().resolveServiceLocator(
+ contextMethod, domainMethod);
+ ServiceLocator locator = newInstance(locatorType, ServiceLocator.class);
+ return locator.getInstance(domainMethod.getDeclaringClass());
}
@Override
@@ -79,6 +84,17 @@
return doLoadDomainObject(clazz, domainId);
}
+ /**
+ * Returns true if the context method returns a {@link Request} and the domain
+ * method is non-static.
+ */
+ @Override
+ public boolean requiresServiceLocator(Method contextMethod,
+ Method domainMethod) {
+ return Request.class.isAssignableFrom(contextMethod.getReturnType())
+ && !Modifier.isStatic(domainMethod.getModifiers());
+ }
+
@Override
public Class<? extends Locator<?, ?>> resolveLocator(Class<?> domainType) {
// Find the matching BaseProxy
@@ -90,21 +106,24 @@
// Check it for annotations
Class<? extends Locator<?, ?>> locatorType;
- LocatorFor l = proxyType.getAnnotation(LocatorFor.class);
- LocatorForName ln = proxyType.getAnnotation(LocatorForName.class);
- if (l != null) {
- locatorType = l.value();
- } else if (ln != null) {
+ ProxyFor l = proxyType.getAnnotation(ProxyFor.class);
+ ProxyForName ln = proxyType.getAnnotation(ProxyForName.class);
+ if (l != null && !Locator.class.equals(l.locator())) {
+ @SuppressWarnings("unchecked")
+ Class<? extends Locator<?, ?>> found = (Class<? extends Locator<?, ?>>) l.locator();
+ locatorType = found;
+ } else if (ln != null && ln.locator().length() > 0) {
try {
@SuppressWarnings("unchecked")
Class<? extends Locator<?, ?>> found = (Class<? extends Locator<?, ?>>) Class.forName(
- ln.value(), false, domainType.getClassLoader()).asSubclass(
+ ln.locator(), false, domainType.getClassLoader()).asSubclass(
Locator.class);
locatorType = found;
} catch (ClassNotFoundException e) {
- return die(e,
- "Could not find the type specified in the @%s annotation %s",
- LocatorForName.class.getCanonicalName(), ln.value());
+ return die(
+ e,
+ "Could not find the locator type specified in the @%s annotation %s",
+ ProxyForName.class.getCanonicalName(), ln.value());
}
} else {
// No locator annotation
@@ -113,6 +132,34 @@
return locatorType;
}
+ @Override
+ public Class<? extends ServiceLocator> resolveServiceLocator(
+ Method contextMethod, Method domainMethod) {
+ Class<? extends ServiceLocator> locatorType;
+
+ // Look at the RequestContext
+ Class<?> requestContextClass = contextMethod.getDeclaringClass();
+ Service l = requestContextClass.getAnnotation(Service.class);
+ ServiceName ln = requestContextClass.getAnnotation(ServiceName.class);
+ if (l != null && !ServiceLocator.class.equals(l.locator())) {
+ locatorType = l.locator();
+ } else if (ln != null && ln.locator().length() > 0) {
+ try {
+ locatorType = Class.forName(ln.locator(), false,
+ requestContextClass.getClassLoader()).asSubclass(
+ ServiceLocator.class);
+ } catch (ClassNotFoundException e) {
+ return die(
+ e,
+ "Could not find the locator type specified in the @%s annotation %s",
+ ServiceName.class.getCanonicalName(), ln.value());
+ }
+ } else {
+ locatorType = null;
+ }
+ return locatorType;
+ }
+
private <T> Object doGetId(T domainObject) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) domainObject.getClass();
@@ -162,4 +209,18 @@
}
return (Locator<T, I>) getTop().createLocator(locatorType);
}
+
+ private <T> T newInstance(Class<T> clazz, Class<? super T> base) {
+ Throwable ex;
+ try {
+ return clazz.newInstance();
+ } catch (InstantiationException e) {
+ ex = e;
+ } catch (IllegalAccessException e) {
+ ex = e;
+ }
+ return this.<T> die(ex,
+ "Could not instantiate %s %s. Is it default-instantiable?",
+ base.getSimpleName(), clazz.getCanonicalName());
+ }
}
diff --git a/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java b/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java
index 5dafce4..2c8f005 100644
--- a/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java
+++ b/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java
@@ -31,8 +31,6 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.EntityProxy;
import com.google.gwt.requestfactory.shared.InstanceRequest;
-import com.google.gwt.requestfactory.shared.LocatorFor;
-import com.google.gwt.requestfactory.shared.LocatorForName;
import com.google.gwt.requestfactory.shared.ProxyFor;
import com.google.gwt.requestfactory.shared.ProxyForName;
import com.google.gwt.requestfactory.shared.Request;
@@ -44,6 +42,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -142,6 +141,7 @@
private class DomainMapper extends EmptyVisitor {
private final ErrorContext logger;
private String domainInternalName;
+ private List<Class<? extends Annotation>> found = new ArrayList<Class<? extends Annotation>>();
private String locatorInternalName;
public DomainMapper(ErrorContext logger) {
@@ -165,65 +165,93 @@
}
}
+ /**
+ * This method examines one annotation at a time.
+ */
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- final boolean foundLocator = desc.equals(Type.getDescriptor(LocatorFor.class));
- final boolean foundLocatorName = desc.equals(Type.getDescriptor(LocatorForName.class));
- boolean foundProxy = desc.equals(Type.getDescriptor(ProxyFor.class));
- boolean foundProxyName = desc.equals(Type.getDescriptor(ProxyForName.class));
- boolean foundService = desc.equals(Type.getDescriptor(Service.class));
- boolean foundServiceName = desc.equals(Type.getDescriptor(ServiceName.class));
+ // Set to true if the annotation should have class literal values
+ boolean expectClasses = false;
+ // Set to true if the annonation has string values
+ boolean expectNames = false;
- if (foundLocator || foundProxy || foundService) {
+ if (desc.equals(Type.getDescriptor(ProxyFor.class))) {
+ expectClasses = true;
+ found.add(ProxyFor.class);
+ } else if (desc.equals(Type.getDescriptor(ProxyForName.class))) {
+ expectNames = true;
+ found.add(ProxyForName.class);
+ } else if (desc.equals(Type.getDescriptor(Service.class))) {
+ expectClasses = true;
+ found.add(Service.class);
+ } else if (desc.equals(Type.getDescriptor(ServiceName.class))) {
+ expectNames = true;
+ found.add(ServiceName.class);
+ }
+
+ if (expectClasses) {
return new EmptyVisitor() {
@Override
public void visit(String name, Object value) {
if ("value".equals(name)) {
- String found = ((Type) value).getInternalName();
- if (foundLocator) {
- locatorInternalName = found;
- } else {
- domainInternalName = found;
- }
+ domainInternalName = ((Type) value).getInternalName();
+ } else if ("locator".equals(name)) {
+ locatorInternalName = ((Type) value).getInternalName();
}
}
};
}
- if (foundLocatorName || foundProxyName || foundServiceName) {
+ if (expectNames) {
return new EmptyVisitor() {
@Override
public void visit(String name, Object value) {
- if ("value".equals(name)) {
- String sourceName = (String) value;
-
- /*
- * The input is a source name, so we need to convert it to an
- * internal name. We'll do this by substituting dollar signs for
- * the last slash in the name until there are no more slashes.
- */
- StringBuffer desc = new StringBuffer(sourceName.replace('.', '/'));
- while (!loader.exists(desc.toString() + ".class")) {
- logger.spam("Did not find " + desc.toString());
- int idx = desc.lastIndexOf("/");
- if (idx == -1) {
- return;
- }
- desc.setCharAt(idx, '$');
- }
-
- if (foundLocatorName) {
- locatorInternalName = desc.toString();
- } else {
- domainInternalName = desc.toString();
- }
- logger.spam(domainInternalName);
+ String sourceName;
+ if ("value".equals(name) || "locator".equals(name)) {
+ sourceName = (String) value;
+ } else {
+ return;
}
+
+ /*
+ * The input is a source name, so we need to convert it to an
+ * internal name. We'll do this by substituting dollar signs for the
+ * last slash in the name until there are no more slashes.
+ */
+ StringBuffer desc = new StringBuffer(sourceName.replace('.', '/'));
+ while (!loader.exists(desc.toString() + ".class")) {
+ logger.spam("Did not find " + desc.toString());
+ int idx = desc.lastIndexOf("/");
+ if (idx == -1) {
+ return;
+ }
+ desc.setCharAt(idx, '$');
+ }
+
+ if ("locator".equals(name)) {
+ locatorInternalName = desc.toString();
+ } else {
+ domainInternalName = desc.toString();
+ }
+ logger.spam(domainInternalName);
}
};
}
return null;
}
+
+ @Override
+ public void visitEnd() {
+ // Only allow one annotation
+ if (found.size() > 1) {
+ StringBuilder sb = new StringBuilder();
+ for (Class<?> clazz : found) {
+ sb.append(" @").append(clazz.getSimpleName());
+ }
+ logger.poison("Redundant domain mapping annotations present:%s",
+ sb.toString());
+ }
+ }
}
/**
@@ -536,10 +564,10 @@
*/
private final Map<Type, Type> clientToDomainType = new HashMap<Type, Type>();
/**
- * Maps client types (e.g. FooProxy) to their locator types (e.g. FooLocator).
+ * Maps client types (e.g. FooProxy or FooContext) to their locator types
+ * (e.g. FooLocator or FooServiceLocator).
*/
private final Map<Type, Type> clientToLocatorMap = new HashMap<Type, Type>();
-
/**
* Maps domain types (e.g Foo) to client proxy types (e.g. FooAProxy,
* FooBProxy).
@@ -731,7 +759,8 @@
}
// Check the client method against the domain
- checkClientMethodInDomain(logger, method, domainServiceType);
+ checkClientMethodInDomain(logger, method, domainServiceType,
+ !clientToLocatorMap.containsKey(requestContextType));
maybeCheckReferredProxies(logger, method);
}
@@ -887,7 +916,7 @@
* to the server's domain type.
*/
private void checkClientMethodInDomain(ErrorContext logger, RFMethod method,
- Type domainServiceType) {
+ Type domainServiceType, boolean requireStaticMethodsForRequestType) {
logger = logger.setMethod(method);
// Create a "translated" method declaration to search for
@@ -905,7 +934,8 @@
logger.poison("The method %s is declared to return %s, but the"
+ " service method is static", method.getName(),
InstanceRequest.class.getCanonicalName());
- } else if (!isInstance && !found.isDeclaredStatic) {
+ } else if (requireStaticMethodsForRequestType && !isInstance
+ && !found.isDeclaredStatic()) {
logger.poison("The method %s is declared to return %s, but the"
+ " service method is not static", method.getName(),
Request.class.getCanonicalName());
diff --git a/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java b/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java
index a906e9f..8cd93a4 100644
--- a/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java
+++ b/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java
@@ -17,6 +17,7 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.Locator;
+import com.google.gwt.requestfactory.shared.ServiceLocator;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
@@ -109,6 +110,17 @@
public abstract <T extends Locator<?, ?>> T createLocator(Class<T> clazz);
/**
+ * Create an instance of a service object that can be used as the target for
+ * the given method invocation.
+ *
+ * @param contextMethod a method defined in a RequestContext
+ * @param domainMethod the method that the service object must implement
+ * @return an instance of the requested service object
+ */
+ public abstract Object createServiceInstance(Method contextMethod,
+ Method domainMethod);
+
+ /**
* Return the persistent id for a domain object. May return {@code null} to
* indicate that the domain object has not been persisted. The value returned
* from this method must be a simple type (e.g. Integer, String) or a domain
@@ -209,6 +221,18 @@
List<Object> domainIds);
/**
+ * Determines if the invocation of a domain method requires a
+ * {@link ServiceLocator} as the 0th parameter when passed into
+ * {@link #invoke(Method, Object...)}.
+ *
+ * @param contextMethod a method defined in a RequestContext
+ * @param domainMethod a domain method
+ * @return {@code true} if a ServiceLocator is required
+ */
+ public abstract boolean requiresServiceLocator(Method contextMethod,
+ Method domainMethod);
+
+ /**
* Given a type token previously returned from
* {@link #resolveTypeToken(Class)}, return the Class literal associated with
* the token.
@@ -278,6 +302,19 @@
String requestContextClass, String methodName);
/**
+ * Given a RequestContext method declaration, resolve the
+ * {@link ServiceLocator} that should be used when invoking the domain method.
+ * This method will only be called if {@link #requiresServiceLocator(Method)}
+ * returned {@code true} for the associated domain method.
+ *
+ * @param contextMethod a RequestContext method declaration
+ * @param domainMethod the domain method that will be invoked
+ * @return the type of ServiceLocator to use
+ */
+ public abstract Class<? extends ServiceLocator> resolveServiceLocator(
+ Method contextMethod, Method domainMethod);
+
+ /**
* Return a string used to represent the given type in the wire protocol.
*
* @param proxyType a client-side EntityProxy or ValueProxy type
diff --git a/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java b/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java
index 887d49c..0c89f75 100644
--- a/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java
+++ b/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java
@@ -17,6 +17,7 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.Locator;
+import com.google.gwt.requestfactory.shared.ServiceLocator;
import com.google.gwt.rpc.server.Pair;
import java.lang.ref.SoftReference;
@@ -42,20 +43,27 @@
private static SoftReference<Map<Method, Map<Object, Object>>> methodCache;
private static final Method createLocator;
+ private static final Method createServiceInstance;
private static final Method getIdType;
private static final Method getRequestReturnType;
+ private static final Method requiresServiceLocator;
private static final Method resolveClass;
private static final Method resolveClientType;
private static final Method resolveDomainClass;
private static final Method resolveDomainMethod;
private static final Method resolveLocator;
private static final Method resolveRequestContextMethod;
+ private static final Method resolveServiceLocator;
private static final Method resolveTypeToken;
static {
createLocator = getMethod("createLocator", Class.class);
+ createServiceInstance = getMethod("createServiceInstance", Method.class,
+ Method.class);
getIdType = getMethod("getIdType", Class.class);
getRequestReturnType = getMethod("getRequestReturnType", Method.class);
+ requiresServiceLocator = getMethod("requiresServiceLocator", Method.class,
+ Method.class);
resolveClass = getMethod("resolveClass", String.class);
resolveClientType = getMethod("resolveClientType", Class.class,
Class.class, boolean.class);
@@ -64,6 +72,8 @@
resolveLocator = getMethod("resolveLocator", Class.class);
resolveRequestContextMethod = getMethod("resolveRequestContextMethod",
String.class, String.class);
+ resolveServiceLocator = getMethod("resolveServiceLocator", Method.class,
+ Method.class);
resolveTypeToken = getMethod("resolveTypeToken", Class.class);
}
@@ -98,6 +108,12 @@
}
@Override
+ public Object createServiceInstance(Method contextMethod, Method domainMethod) {
+ return getOrCache(createServiceInstance, new Pair<Method, Method>(
+ contextMethod, domainMethod), Object.class, contextMethod, domainMethod);
+ }
+
+ @Override
public Class<?> getIdType(Class<?> domainType) {
return getOrCache(getIdType, domainType, Class.class, domainType);
}
@@ -109,18 +125,26 @@
}
@Override
+ public boolean requiresServiceLocator(Method contextMethod,
+ Method domainMethod) {
+ return getOrCache(requiresServiceLocator, new Pair<Method, Method>(
+ contextMethod, domainMethod), Boolean.class, contextMethod,
+ domainMethod);
+ }
+
+ @Override
public Class<? extends BaseProxy> resolveClass(String typeToken) {
Class<?> found = getOrCache(resolveClass, typeToken, Class.class, typeToken);
return found.asSubclass(BaseProxy.class);
}
@Override
- @SuppressWarnings("unchecked")
public <T> Class<? extends T> resolveClientType(Class<?> domainClass,
Class<T> clientType, boolean required) {
- return getOrCache(resolveClientType, new Pair<Class<?>, Class<?>>(
- domainClass, clientType), Class.class, domainClass, clientType,
- required);
+ Class<?> clazz = getOrCache(resolveClientType,
+ new Pair<Class<?>, Class<?>>(domainClass, clientType), Class.class,
+ domainClass, clientType, required);
+ return clazz == null ? null : clazz.asSubclass(clientType);
}
@Override
@@ -149,6 +173,15 @@
}
@Override
+ public Class<? extends ServiceLocator> resolveServiceLocator(
+ Method contextMethod, Method domainMethod) {
+ Class<?> clazz = getOrCache(resolveServiceLocator,
+ new Pair<Method, Method>(contextMethod, domainMethod), Class.class,
+ contextMethod, domainMethod);
+ return clazz == null ? null : clazz.asSubclass(ServiceLocator.class);
+ }
+
+ @Override
public String resolveTypeToken(Class<? extends BaseProxy> domainClass) {
return getOrCache(resolveTypeToken, domainClass, String.class, domainClass);
}
diff --git a/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java b/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java
index b9a2248..c642d94 100644
--- a/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java
+++ b/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java
@@ -17,6 +17,7 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.Locator;
+import com.google.gwt.requestfactory.shared.ServiceLocator;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -54,6 +55,11 @@
}
@Override
+ public Object createServiceInstance(Method contextMethod, Method domainMethod) {
+ return getNext().createServiceInstance(contextMethod, domainMethod);
+ }
+
+ @Override
public Object getId(Object domainObject) {
return getNext().getId(domainObject);
}
@@ -100,6 +106,12 @@
}
@Override
+ public boolean requiresServiceLocator(Method contextMethod,
+ Method domainMethod) {
+ return getNext().requiresServiceLocator(contextMethod, domainMethod);
+ }
+
+ @Override
public Class<? extends BaseProxy> resolveClass(String typeToken) {
return getNext().resolveClass(typeToken);
}
@@ -133,6 +145,12 @@
}
@Override
+ public Class<? extends ServiceLocator> resolveServiceLocator(
+ Method contextMethod, Method domainMethod) {
+ return getNext().resolveServiceLocator(contextMethod, domainMethod);
+ }
+
+ @Override
public String resolveTypeToken(Class<? extends BaseProxy> proxyType) {
return getNext().resolveTypeToken(proxyType);
}
diff --git a/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java b/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java
index 4be0769..07fe1f5 100644
--- a/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java
+++ b/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java
@@ -27,6 +27,7 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.EntityProxyId;
import com.google.gwt.requestfactory.shared.InstanceRequest;
+import com.google.gwt.requestfactory.shared.Request;
import com.google.gwt.requestfactory.shared.ServerFailure;
import com.google.gwt.requestfactory.shared.WriteOperation;
import com.google.gwt.requestfactory.shared.impl.BaseProxyCategory;
@@ -47,7 +48,6 @@
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
@@ -346,7 +346,7 @@
*/
private List<Object> decodeInvocationArguments(RequestState source,
InvocationMessage invocation, Method contextMethod, Method domainMethod) {
- boolean isStatic = Modifier.isStatic(domainMethod.getModifiers());
+ boolean isStatic = Request.class.isAssignableFrom(contextMethod.getReturnType());
int baseLength = contextMethod.getParameterTypes().length;
int length = baseLength + (isStatic ? 0 : 1);
int offset = isStatic ? 0 : 1;
@@ -418,9 +418,16 @@
+ invocation.getOperation(), null);
}
- // Invoke it
+ // Compute the arguments
List<Object> args = decodeInvocationArguments(state, invocation,
contextMethod, domainMethod);
+ // Possibly use a ServiceLocator
+ if (service.requiresServiceLocator(contextMethod, domainMethod)) {
+ Object serviceInstance = service.createServiceInstance(contextMethod,
+ domainMethod);
+ args.add(0, serviceInstance);
+ }
+ // Invoke it
Object returnValue = service.invoke(domainMethod, args.toArray());
// Convert domain object to client object
diff --git a/user/src/com/google/gwt/requestfactory/shared/Locator.java b/user/src/com/google/gwt/requestfactory/shared/Locator.java
index a88032b..3516984 100644
--- a/user/src/com/google/gwt/requestfactory/shared/Locator.java
+++ b/user/src/com/google/gwt/requestfactory/shared/Locator.java
@@ -29,7 +29,7 @@
* @param <T> the type of domain object the Locator will operate on
* @param <I> the type of object the Locator expects to use as an id for the
* domain object
- * @see LocatorFor
+ * @see ProxyFor#locator()
*/
public abstract class Locator<T, I> {
/**
diff --git a/user/src/com/google/gwt/requestfactory/shared/LocatorFor.java b/user/src/com/google/gwt/requestfactory/shared/LocatorFor.java
deleted file mode 100644
index 2c237fd..0000000
--- a/user/src/com/google/gwt/requestfactory/shared/LocatorFor.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.requestfactory.shared;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation on BaseProxy classes specifying the domain (server-side) object
- * {@link Locator}. Specifying an explicit {@code Locator} removes the
- * requirement to have a {@code findFoo()}, {@code getId()}, and
- * {@code getVersion()} method in the domain object type.
- *
- * @see LocatorForName
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface LocatorFor {
- Class<? extends Locator<?, ?>> value();
-}
diff --git a/user/src/com/google/gwt/requestfactory/shared/LocatorForName.java b/user/src/com/google/gwt/requestfactory/shared/LocatorForName.java
deleted file mode 100644
index f537cf4..0000000
--- a/user/src/com/google/gwt/requestfactory/shared/LocatorForName.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.requestfactory.shared;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation on BaseProxy classes specifying the domain (server-side) object
- * {@link Locator}. This annotation can be used in place of {@link LocatorFor}
- * if the domain Locator is not available to the GWT compiler or DevMode
- * runtime.
- *
- * @see LocatorFor
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface LocatorForName {
- String value();
-}
diff --git a/user/src/com/google/gwt/requestfactory/shared/ProxyFor.java b/user/src/com/google/gwt/requestfactory/shared/ProxyFor.java
index 4da1afe..38f6df6 100644
--- a/user/src/com/google/gwt/requestfactory/shared/ProxyFor.java
+++ b/user/src/com/google/gwt/requestfactory/shared/ProxyFor.java
@@ -21,13 +21,22 @@
import java.lang.annotation.Target;
/**
- * Annotation on EntityProxy classes specifying the domain (server-side) object
- * type.
+ * Annotation on EntityProxy and ValueProxy classes specifying the domain
+ * (server-side) object type.
*
* @see ProxyForName
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ProxyFor {
+ /**
+ * The domain type that the proxy is mapped to.
+ */
Class<?> value();
+
+ /**
+ * An optional {@link Locator} that provides instances of the domain objects.
+ */
+ @SuppressWarnings("rawtypes")
+ Class<? extends Locator> locator() default Locator.class;
}
diff --git a/user/src/com/google/gwt/requestfactory/shared/ProxyForName.java b/user/src/com/google/gwt/requestfactory/shared/ProxyForName.java
index fa3f5bd..5eb5594 100644
--- a/user/src/com/google/gwt/requestfactory/shared/ProxyForName.java
+++ b/user/src/com/google/gwt/requestfactory/shared/ProxyForName.java
@@ -28,5 +28,14 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ProxyForName {
+ /**
+ * The name of the domain type that the proxy is mapped to.
+ */
String value();
+
+ /**
+ * An optional name of a {@link Locator} that provides instances of the domain
+ * objects.
+ */
+ String locator() default "";
}
diff --git a/user/src/com/google/gwt/requestfactory/shared/Service.java b/user/src/com/google/gwt/requestfactory/shared/Service.java
index 29d8829..de14983 100644
--- a/user/src/com/google/gwt/requestfactory/shared/Service.java
+++ b/user/src/com/google/gwt/requestfactory/shared/Service.java
@@ -29,5 +29,16 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Service {
+ /**
+ * The domain type that provides the implementations for the methods defined
+ * in the RequestContext.
+ */
Class<?> value();
+
+ /**
+ * An optional {@link ServiceLocator} that provides instances of service
+ * objects used when invoking instance methods on the type returned by
+ * {@link #value()}.
+ */
+ Class<? extends ServiceLocator> locator() default ServiceLocator.class;
}
diff --git a/user/src/com/google/gwt/requestfactory/shared/ServiceLocator.java b/user/src/com/google/gwt/requestfactory/shared/ServiceLocator.java
new file mode 100644
index 0000000..dfa841d
--- /dev/null
+++ b/user/src/com/google/gwt/requestfactory/shared/ServiceLocator.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.requestfactory.shared;
+
+/**
+ * A ServiceLocator provides instances of a type specified by a {@link Service}
+ * when {@link Request} methods declared in a {@link RequestContext}are mapped
+ * onto instance (non-static) methods.
+ * <p>
+ * ServiceLocator subtypes must be default instantiable (i.e. public static
+ * types with a no-arg constructor). Instances of ServiceLocators may be
+ * retained and reused by the RequestFactory service layer.
+ *
+ * @see Service#locator()
+ */
+public interface ServiceLocator {
+ /**
+ * Returns an instance of the service object.
+ *
+ * @param clazz the requested type of service object
+ * @return an instance of the service object
+ */
+ Object getInstance(Class<?> clazz);
+}
diff --git a/user/src/com/google/gwt/requestfactory/shared/ServiceName.java b/user/src/com/google/gwt/requestfactory/shared/ServiceName.java
index beb72b6..464c032 100644
--- a/user/src/com/google/gwt/requestfactory/shared/ServiceName.java
+++ b/user/src/com/google/gwt/requestfactory/shared/ServiceName.java
@@ -28,5 +28,16 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ServiceName {
+ /**
+ * The binary name of the domain type that provides the implementations for
+ * the methods defined in the RequestContext.
+ */
String value();
+
+ /**
+ * An optional binary name of a {@link ServiceLocator} that provides instances
+ * of service objects used when invoking instance methods on the type returned
+ * by {@link #value()}.
+ */
+ String locator() default "";
}
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
index ace0f2f..c3fe25e 100644
--- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
@@ -761,6 +761,17 @@
});
}
+ public void testInstanceServiceRequest() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ req.instanceServiceRequest().add(5).fire(new Receiver<Integer>() {
+ @Override
+ public void onSuccess(Integer response) {
+ assertEquals(10, (int) response);
+ finishTestAndReset();
+ }
+ });
+ }
+
/**
* Make sure our stock RF logging service keeps receiving.
*/
@@ -1157,6 +1168,11 @@
});
}
+ /*
+ * 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.
*/
@@ -1183,11 +1199,6 @@
}
/*
- * TODO: all these tests should check the final values. It will be easy when
- * we have better persistence than the singleton pattern.
- */
-
- /*
* Find Entity2 Create Entity, Persist Entity Relate Entity2 to Entity Persist
* Entity
*/
@@ -1419,6 +1430,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 testPersistValueList() {
delayTestFinish(DELAY_TEST_FINISH);
simpleFooRequest().findSimpleFooById(999L).fire(
@@ -1482,11 +1498,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 testPersistValueListRemove() {
delayTestFinish(DELAY_TEST_FINISH);
simpleFooRequest().findSimpleFooById(999L).fire(
@@ -2071,28 +2082,6 @@
}
/**
- * We provide a simple UserInformation class to give GAE developers a hand,
- * and other developers a hint. Make sure RF doesn't break it (it relies on
- * server side upcasting, and a somewhat sleazey reflective lookup mechanism
- * in a static method on UserInformation).
- */
- public void testUserInfo() {
- delayTestFinish(DELAY_TEST_FINISH);
- req.userInformationRequest().getCurrentUserInformation("").fire(
- new Receiver<UserInformationProxy>() {
- @Override
- public void onSuccess(UserInformationProxy response) {
- response = checkSerialization(response);
- assertEquals("Dummy Email", response.getEmail());
- assertEquals("Dummy User", response.getName());
- assertEquals("", response.getLoginUrl());
- assertEquals("", response.getLogoutUrl());
- finishTestAndReset();
- }
- });
- }
-
- /**
* Check if a graph of unpersisted objects can be echoed.
*/
public void testUnpersistedEchoComplexGraph() {
@@ -2232,6 +2221,28 @@
});
}
+ /**
+ * We provide a simple UserInformation class to give GAE developers a hand,
+ * and other developers a hint. Make sure RF doesn't break it (it relies on
+ * server side upcasting, and a somewhat sleazey reflective lookup mechanism
+ * in a static method on UserInformation).
+ */
+ public void testUserInfo() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ req.userInformationRequest().getCurrentUserInformation("").fire(
+ new Receiver<UserInformationProxy>() {
+ @Override
+ public void onSuccess(UserInformationProxy response) {
+ response = checkSerialization(response);
+ assertEquals("Dummy Email", response.getEmail());
+ assertEquals("Dummy User", response.getName());
+ assertEquals("", response.getLoginUrl());
+ assertEquals("", response.getLogoutUrl());
+ finishTestAndReset();
+ }
+ });
+ }
+
public void testValueObjectCreateSetRetrieveUpdate() {
delayTestFinish(DELAY_TEST_FINISH);
SimpleFooRequest req = simpleFooRequest();
@@ -2373,6 +2384,48 @@
checkEqualityAndHashcode(a, b);
}
+ /**
+ * Since a ValueProxy cannot be passed into RequestContext edit, a proxy
+ * returned from a service method should be mutable by default.
+ */
+ public void testValueObjectReturnedFromRequestIsImmutable() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().returnValueProxy().fire(
+ new Receiver<SimpleValueProxy>() {
+ @Override
+ public void onSuccess(SimpleValueProxy a) {
+ a = checkSerialization(a);
+ try {
+ a.setNumber(77);
+ fail();
+ } catch (IllegalStateException expected) {
+ }
+ try {
+ // Ensure Dates comply with ValueProxy mutation behaviors
+ a.getDate().setTime(1);
+ fail();
+ } catch (IllegalStateException expected) {
+ }
+ SimpleFooRequest ctx = simpleFooRequest();
+ final SimpleValueProxy toCheck = ctx.edit(a);
+ toCheck.setNumber(77);
+ toCheck.getDate().setTime(1);
+ ctx.returnValueProxy().fire(new Receiver<SimpleValueProxy>() {
+ @Override
+ public void onSuccess(SimpleValueProxy b) {
+ b = checkSerialization(b);
+ b = simpleFooRequest().edit(b);
+ // Now check that same value is equal across contexts
+ b.setNumber(77);
+ b.setDate(new Date(1));
+ checkEqualityAndHashcode(toCheck, b);
+ finishTestAndReset();
+ }
+ });
+ }
+ });
+ }
+
public void testValueObjectViolationsOnCreate() {
delayTestFinish(DELAY_TEST_FINISH);
SimpleFooRequest req = simpleFooRequest();
@@ -2433,48 +2486,6 @@
});
}
- /**
- * Since a ValueProxy cannot be passed into RequestContext edit, a proxy
- * returned from a service method should be mutable by default.
- */
- public void testValueObjectReturnedFromRequestIsImmutable() {
- delayTestFinish(DELAY_TEST_FINISH);
- simpleFooRequest().returnValueProxy().fire(
- new Receiver<SimpleValueProxy>() {
- @Override
- public void onSuccess(SimpleValueProxy a) {
- a = checkSerialization(a);
- try {
- a.setNumber(77);
- fail();
- } catch (IllegalStateException expected) {
- }
- try {
- // Ensure Dates comply with ValueProxy mutation behaviors
- a.getDate().setTime(1);
- fail();
- } catch (IllegalStateException expected) {
- }
- SimpleFooRequest ctx = simpleFooRequest();
- final SimpleValueProxy toCheck = ctx.edit(a);
- toCheck.setNumber(77);
- toCheck.getDate().setTime(1);
- ctx.returnValueProxy().fire(new Receiver<SimpleValueProxy>() {
- @Override
- public void onSuccess(SimpleValueProxy b) {
- b = checkSerialization(b);
- b = simpleFooRequest().edit(b);
- // Now check that same value is equal across contexts
- b.setNumber(77);
- b.setDate(new Date(1));
- checkEqualityAndHashcode(toCheck, b);
- finishTestAndReset();
- }
- });
- }
- });
- }
-
public void testViolationAbsent() {
delayTestFinish(DELAY_TEST_FINISH);
diff --git a/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java b/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java
index 3e160e5..ce68390 100644
--- a/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java
+++ b/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java
@@ -28,12 +28,14 @@
import com.google.gwt.requestfactory.server.TestContextImpl;
import com.google.gwt.requestfactory.shared.EntityProxy;
import com.google.gwt.requestfactory.shared.InstanceRequest;
+import com.google.gwt.requestfactory.shared.Locator;
import com.google.gwt.requestfactory.shared.ProxyFor;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.shared.Request;
import com.google.gwt.requestfactory.shared.RequestContext;
import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.requestfactory.shared.Service;
+import com.google.gwt.requestfactory.shared.ServiceLocator;
import com.google.gwt.requestfactory.shared.ValueProxy;
import junit.framework.TestCase;
@@ -269,8 +271,10 @@
new EmptyMockJavaResource(Iterable.class),
new EmptyMockJavaResource(EntityProxy.class),
new EmptyMockJavaResource(InstanceRequest.class),
+ new EmptyMockJavaResource(Locator.class),
new EmptyMockJavaResource(RequestFactory.class),
new EmptyMockJavaResource(Receiver.class),
+ new EmptyMockJavaResource(ServiceLocator.class),
new EmptyMockJavaResource(ValueProxy.class),
new RealJavaResource(Request.class),
diff --git a/user/test/com/google/gwt/requestfactory/server/InstanceService.java b/user/test/com/google/gwt/requestfactory/server/InstanceService.java
new file mode 100644
index 0000000..9d9c940
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/server/InstanceService.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.requestfactory.server;
+
+/**
+ * A service API that doesn't have static methods and that can't be
+ * default-instantiated.
+ */
+public interface InstanceService {
+ Integer add(int value);
+}
diff --git a/user/test/com/google/gwt/requestfactory/server/InstanceServiceImpl.java b/user/test/com/google/gwt/requestfactory/server/InstanceServiceImpl.java
new file mode 100644
index 0000000..e2dd226
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/server/InstanceServiceImpl.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.requestfactory.server;
+
+/**
+ * A service API that doesn't have static methods and that can't be
+ * default-instantiated.
+ */
+public class InstanceServiceImpl implements InstanceService {
+ private final int base;
+
+ public InstanceServiceImpl(int base) {
+ this.base = base;
+ }
+
+ public Integer add(int value) {
+ return base + value;
+ }
+}
diff --git a/user/test/com/google/gwt/requestfactory/server/InstanceServiceLocator.java b/user/test/com/google/gwt/requestfactory/server/InstanceServiceLocator.java
new file mode 100644
index 0000000..e5a5b9e
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/server/InstanceServiceLocator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.requestfactory.server;
+
+import com.google.gwt.requestfactory.shared.ServiceLocator;
+
+/**
+ * Demonstrates instance-based service objects.
+ */
+public class InstanceServiceLocator implements ServiceLocator {
+
+ public Object getInstance(Class<?> clazz) {
+ assert InstanceService.class.equals(clazz);
+ return clazz.cast(new InstanceServiceImpl(5));
+ }
+}
diff --git a/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java b/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java
index eb87261..f6640da 100644
--- a/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java
+++ b/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java
@@ -19,12 +19,13 @@
import com.google.gwt.requestfactory.shared.EntityProxy;
import com.google.gwt.requestfactory.shared.InstanceRequest;
import com.google.gwt.requestfactory.shared.Locator;
-import com.google.gwt.requestfactory.shared.LocatorFor;
import com.google.gwt.requestfactory.shared.ProxyFor;
+import com.google.gwt.requestfactory.shared.ProxyForName;
import com.google.gwt.requestfactory.shared.Request;
import com.google.gwt.requestfactory.shared.RequestContext;
import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.requestfactory.shared.Service;
+import com.google.gwt.requestfactory.shared.ServiceName;
import com.google.gwt.requestfactory.shared.SimpleRequestFactory;
import com.google.gwt.requestfactory.shared.ValueProxy;
import com.google.gwt.requestfactory.shared.impl.FindRequest;
@@ -180,8 +181,7 @@
}
}
- @ProxyFor(LocatorEntity.class)
- @LocatorFor(LocatorEntityLocator.class)
+ @ProxyFor(value = LocatorEntity.class, locator = LocatorEntityLocator.class)
interface LocatorEntityProxy extends EntityProxy {
}
@@ -228,6 +228,13 @@
Request<Integer> doesNotExist(int a);
}
+ @ProxyFor(Domain.class)
+ @ProxyForName("Domain")
+ @Service(Domain.class)
+ @ServiceName("Domain")
+ interface TooManyAnnotations extends RequestContext {
+ }
+
static class UnexpectedIdAndVersionDomain {
Random getId() {
return null;
@@ -349,6 +356,11 @@
assertFalse(v.isPoisoned());
}
+ public void testTooManyAnnotations() {
+ v.validateRequestContext(TooManyAnnotations.class.getName());
+ assertTrue(v.isPoisoned());
+ }
+
public void testUnexpectedIdAndVersion() {
v.validateEntityProxy(UnexpectedIdAndVersionProxy.class.getName());
assertTrue(v.isPoisoned());
diff --git a/user/test/com/google/gwt/requestfactory/shared/InstanceServiceRequest.java b/user/test/com/google/gwt/requestfactory/shared/InstanceServiceRequest.java
new file mode 100644
index 0000000..79fef75
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/shared/InstanceServiceRequest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.requestfactory.shared;
+
+import com.google.gwt.requestfactory.server.InstanceService;
+import com.google.gwt.requestfactory.server.InstanceServiceLocator;
+
+/**
+ * Used to test the ServiceLocator extension hook.
+ */
+@Service(value = InstanceService.class, locator = InstanceServiceLocator.class)
+public interface InstanceServiceRequest extends RequestContext {
+ Request<Integer> add(int value);
+}
diff --git a/user/test/com/google/gwt/requestfactory/shared/LocatorTest.java b/user/test/com/google/gwt/requestfactory/shared/LocatorTest.java
index fc550e8..a321383 100644
--- a/user/test/com/google/gwt/requestfactory/shared/LocatorTest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/LocatorTest.java
@@ -82,8 +82,7 @@
static final Domain INSTANCE = new Domain();
}
- @ProxyFor(Domain.class)
- @LocatorFor(DomainLocator.class)
+ @ProxyFor(value = Domain.class, locator = DomainLocator.class)
interface DomainProxy extends EntityProxy {
EntityProxyId<DomainProxy> stableId();
};
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleRequestFactory.java b/user/test/com/google/gwt/requestfactory/shared/SimpleRequestFactory.java
index c62b5a5..7def869 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleRequestFactory.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleRequestFactory.java
@@ -20,6 +20,8 @@
* UserInformation and Logging services.
*/
public interface SimpleRequestFactory extends BasicRequestFactory {
+
+ InstanceServiceRequest instanceServiceRequest();
SimpleBarRequest simpleBarRequest();