Allows isBoolean() properties to be handled correctly by AutoBeanCodex and RequestFactory.
Issue 5902.
Moves all method-to-property computations into BeanMethod and JBeanMethod utiliy enums.
Move server reflection implementation classes into server.impl package to clean up organization.
Patch by: bobv, t.broyer
Review by: rjrjr
Reported by: jasonhall, t.broyer
Review at http://gwt-code-reviews.appspot.com/1320801
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9619 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/autobean/rebind/AutoBeanFactoryGenerator.java b/user/src/com/google/gwt/autobean/rebind/AutoBeanFactoryGenerator.java
index fec733f..0adbd02 100644
--- a/user/src/com/google/gwt/autobean/rebind/AutoBeanFactoryGenerator.java
+++ b/user/src/com/google/gwt/autobean/rebind/AutoBeanFactoryGenerator.java
@@ -16,10 +16,10 @@
package com.google.gwt.autobean.rebind;
import com.google.gwt.autobean.client.impl.AbstractAutoBeanFactory;
+import com.google.gwt.autobean.rebind.model.JBeanMethod;
import com.google.gwt.autobean.rebind.model.AutoBeanFactoryMethod;
import com.google.gwt.autobean.rebind.model.AutoBeanFactoryModel;
import com.google.gwt.autobean.rebind.model.AutoBeanMethod;
-import com.google.gwt.autobean.rebind.model.AutoBeanMethod.Action;
import com.google.gwt.autobean.rebind.model.AutoBeanType;
import com.google.gwt.autobean.shared.AutoBean;
import com.google.gwt.autobean.shared.AutoBeanFactory;
@@ -559,7 +559,7 @@
sw.indent();
for (AutoBeanMethod method : type.getMethods()) {
- if (!method.getAction().equals(Action.GET)) {
+ if (!method.getAction().equals(JBeanMethod.GET)) {
continue;
}
@@ -567,7 +567,7 @@
// If it's not a simple bean type, try to find a real setter method
if (!type.isSimpleBean()) {
for (AutoBeanMethod maybeSetter : type.getMethods()) {
- if (maybeSetter.getAction().equals(Action.SET)
+ if (maybeSetter.getAction().equals(JBeanMethod.SET)
&& maybeSetter.getPropertyName().equals(method.getPropertyName())) {
setter = maybeSetter;
break;
diff --git a/user/src/com/google/gwt/autobean/rebind/model/AutoBeanFactoryModel.java b/user/src/com/google/gwt/autobean/rebind/model/AutoBeanFactoryModel.java
index 9268c26..b073335 100644
--- a/user/src/com/google/gwt/autobean/rebind/model/AutoBeanFactoryModel.java
+++ b/user/src/com/google/gwt/autobean/rebind/model/AutoBeanFactoryModel.java
@@ -15,7 +15,6 @@
*/
package com.google.gwt.autobean.rebind.model;
-import com.google.gwt.autobean.rebind.model.AutoBeanMethod.Action;
import com.google.gwt.autobean.shared.AutoBean;
import com.google.gwt.autobean.shared.AutoBeanFactory;
import com.google.gwt.autobean.shared.AutoBeanFactory.Category;
@@ -152,7 +151,7 @@
+ " methods did not have static implementations:",
beanType.getQualifiedSourceName());
for (AutoBeanMethod missing : autoBeanType.getMethods()) {
- if (missing.getAction().equals(Action.CALL)
+ if (missing.getAction().equals(JBeanMethod.CALL)
&& missing.getStaticImpl() == null) {
poison(missing.getMethod().getReadableDeclaration());
}
@@ -235,9 +234,9 @@
}
// GET, SET, or CALL
- Action action = Action.which(method);
+ JBeanMethod action = JBeanMethod.which(method);
builder.setAction(action);
- if (Action.CALL.equals(action)) {
+ if (JBeanMethod.CALL.equals(action)) {
JMethod staticImpl = findStaticImpl(beanType, method);
if (staticImpl == null && objectMethods.contains(method)) {
// Don't complain about lack of implementation for Object methods
diff --git a/user/src/com/google/gwt/autobean/rebind/model/AutoBeanMethod.java b/user/src/com/google/gwt/autobean/rebind/model/AutoBeanMethod.java
index 0362aea..516ce3e 100644
--- a/user/src/com/google/gwt/autobean/rebind/model/AutoBeanMethod.java
+++ b/user/src/com/google/gwt/autobean/rebind/model/AutoBeanMethod.java
@@ -20,7 +20,6 @@
import com.google.gwt.core.ext.typeinfo.JEnumConstant;
import com.google.gwt.core.ext.typeinfo.JEnumType;
import com.google.gwt.core.ext.typeinfo.JMethod;
-import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.editor.rebind.model.ModelUtils;
@@ -34,108 +33,14 @@
*/
public class AutoBeanMethod {
/**
- * Describes the type of method that was invoked.
- */
- public enum Action {
- GET {
- @Override
- String inferName(JMethod method) {
- if (JPrimitiveType.BOOLEAN.equals(method.getReturnType())) {
- String name = method.getName();
- if (name.startsWith("is") && name.length() > 2) {
- name = Character.toLowerCase(name.charAt(2))
- + (name.length() >= 4 ? name.substring(3) : "");
- return name;
- }
- }
- return super.inferName(method);
- }
-
- @Override
- boolean matches(JMethod method) {
- if (method.getParameters().length > 0) {
- return false;
- }
- String name = method.getName();
-
- // Allow boolean isFoo() or boolean hasFoo();
- if (JPrimitiveType.BOOLEAN.equals(method.getReturnType())) {
- if (name.startsWith("is") && name.length() > 2) {
- return true;
- }
- if (name.startsWith("has") && name.length() > 3) {
- return true;
- }
- }
- if (name.startsWith("get") && name.length() > 3) {
- return true;
- }
- return false;
- }
- },
- SET {
- @Override
- boolean matches(JMethod method) {
- if (!JPrimitiveType.VOID.equals(method.getReturnType())) {
- return false;
- }
- if (method.getParameters().length != 1) {
- return false;
- }
- String name = method.getName();
- if (name.startsWith("set") && name.length() > 3) {
- return true;
- }
- return false;
- }
- },
- CALL {
- /**
- * Matches all leftover methods.
- */
- @Override
- boolean matches(JMethod method) {
- return true;
- }
- };
-
- /**
- * Determine which Action a method maps to.
- */
- public static Action which(JMethod method) {
- for (Action action : Action.values()) {
- if (action.matches(method)) {
- return action;
- }
- }
- throw new RuntimeException("CALL should have matched");
- }
-
- /**
- * Infer the name of a property from the method.
- */
- String inferName(JMethod method) {
- String name = method.getName();
- name = Character.toLowerCase(name.charAt(3))
- + (name.length() >= 5 ? name.substring(4) : "");
- return name;
- }
-
- /**
- * Returns {@code true} if the Action matches the method.
- */
- abstract boolean matches(JMethod method);
- }
-
- /**
* Creates AutoBeanMethods.
*/
public static class Builder {
private AutoBeanMethod toReturn = new AutoBeanMethod();
public AutoBeanMethod build() {
- if (toReturn.action.equals(Action.GET)
- || toReturn.action.equals(Action.SET)) {
+ if (toReturn.action.equals(JBeanMethod.GET)
+ || toReturn.action.equals(JBeanMethod.SET)) {
PropertyName annotation = toReturn.method.getAnnotation(PropertyName.class);
if (annotation != null) {
toReturn.propertyName = annotation.value();
@@ -151,7 +56,7 @@
}
}
- public void setAction(Action action) {
+ public void setAction(JBeanMethod action) {
toReturn.action = action;
}
@@ -227,7 +132,7 @@
}
}
- private Action action;
+ private JBeanMethod action;
private JClassType elementType;
private Map<JEnumConstant, String> enumMap;
private JClassType keyType;
@@ -241,7 +146,7 @@
private AutoBeanMethod() {
}
- public Action getAction() {
+ public JBeanMethod getAction() {
return action;
}
diff --git a/user/src/com/google/gwt/autobean/rebind/model/AutoBeanType.java b/user/src/com/google/gwt/autobean/rebind/model/AutoBeanType.java
index 1697a9f..5fd64e5 100644
--- a/user/src/com/google/gwt/autobean/rebind/model/AutoBeanType.java
+++ b/user/src/com/google/gwt/autobean/rebind/model/AutoBeanType.java
@@ -15,7 +15,6 @@
*/
package com.google.gwt.autobean.rebind.model;
-import com.google.gwt.autobean.rebind.model.AutoBeanMethod.Action;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
@@ -71,7 +70,7 @@
toReturn.simpleBean = true;
for (AutoBeanMethod method : methods) {
- if (method.getAction().equals(Action.CALL)) {
+ if (method.getAction().equals(JBeanMethod.CALL)) {
if (method.getStaticImpl() == null) {
toReturn.simpleBean = false;
} else {
diff --git a/user/src/com/google/gwt/autobean/rebind/model/JBeanMethod.java b/user/src/com/google/gwt/autobean/rebind/model/JBeanMethod.java
new file mode 100644
index 0000000..e403530
--- /dev/null
+++ b/user/src/com/google/gwt/autobean/rebind/model/JBeanMethod.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011 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.autobean.rebind.model;
+
+import static com.google.gwt.autobean.server.impl.BeanMethod.GET_PREFIX;
+import static com.google.gwt.autobean.server.impl.BeanMethod.HAS_PREFIX;
+import static com.google.gwt.autobean.server.impl.BeanMethod.IS_PREFIX;
+import static com.google.gwt.autobean.server.impl.BeanMethod.SET_PREFIX;
+
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
+import com.google.gwt.core.ext.typeinfo.JType;
+
+import java.beans.Introspector;
+
+/**
+ * Common utility code for matching {@link JMethod} and against bean-style
+ * accessor semantics.
+ *
+ * @see com.google.gwt.autobean.server.impl.BeanMethod
+ */
+public enum JBeanMethod {
+ GET {
+ @Override
+ public String inferName(JMethod method) {
+ if (isBooleanProperty(method) && method.getName().startsWith(IS_PREFIX)) {
+ return Introspector.decapitalize(method.getName().substring(2));
+ }
+ return super.inferName(method);
+ }
+
+ @Override
+ public boolean matches(JMethod method) {
+ if (method.getParameters().length > 0) {
+ return false;
+ }
+
+ if (isBooleanProperty(method)) {
+ return true;
+ }
+
+ String name = method.getName();
+ if (name.startsWith(GET_PREFIX) && name.length() > 3) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if the method matches {@code boolean isFoo()} or
+ * {@code boolean hasFoo()} property accessors.
+ */
+ private boolean isBooleanProperty(JMethod method) {
+ JType returnType = method.getReturnType();
+ if (JPrimitiveType.BOOLEAN.equals(returnType)
+ || method.getEnclosingType().getOracle().findType(
+ Boolean.class.getCanonicalName()).equals(returnType)) {
+ String name = method.getName();
+ if (name.startsWith(IS_PREFIX) && name.length() > 2) {
+ return true;
+ }
+ if (name.startsWith(HAS_PREFIX) && name.length() > 3) {
+ return true;
+ }
+ }
+ return false;
+ }
+ },
+ SET {
+ @Override
+ public boolean matches(JMethod method) {
+ if (!JPrimitiveType.VOID.equals(method.getReturnType())) {
+ return false;
+ }
+ if (method.getParameters().length != 1) {
+ return false;
+ }
+ String name = method.getName();
+ if (name.startsWith(SET_PREFIX) && name.length() > 3) {
+ return true;
+ }
+ return false;
+ }
+ },
+ CALL {
+ /**
+ * Matches all leftover methods.
+ */
+ @Override
+ public boolean matches(JMethod method) {
+ return true;
+ }
+ };
+
+ /**
+ * Determine which Action a method maps to.
+ */
+ public static JBeanMethod which(JMethod method) {
+ for (JBeanMethod action : JBeanMethod.values()) {
+ if (action.matches(method)) {
+ return action;
+ }
+ }
+ throw new RuntimeException("CALL should have matched");
+ }
+
+ /**
+ * Infer the name of a property from the method.
+ */
+ public String inferName(JMethod method) {
+ if (this == CALL) {
+ throw new UnsupportedOperationException(
+ "Cannot infer a property name for a CALL-type method");
+ }
+ return Introspector.decapitalize(method.getName().substring(3));
+ }
+
+ /**
+ * Returns {@code true} if the BeanLikeMethod matches the method.
+ */
+ public abstract boolean matches(JMethod method);
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/autobean/server/AutoBeanFactoryMagic.java b/user/src/com/google/gwt/autobean/server/AutoBeanFactoryMagic.java
index c18d943..6ab47d1 100644
--- a/user/src/com/google/gwt/autobean/server/AutoBeanFactoryMagic.java
+++ b/user/src/com/google/gwt/autobean/server/AutoBeanFactoryMagic.java
@@ -15,14 +15,14 @@
*/
package com.google.gwt.autobean.server;
+import com.google.gwt.autobean.server.impl.FactoryHandler;
+import com.google.gwt.autobean.server.impl.ProxyAutoBean;
import com.google.gwt.autobean.shared.AutoBean;
import com.google.gwt.autobean.shared.AutoBeanFactory;
import com.google.gwt.autobean.shared.AutoBeanFactory.Category;
import com.google.gwt.autobean.shared.AutoBeanFactory.NoWrap;
import com.google.gwt.autobean.shared.impl.EnumMap;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Proxy;
/**
* Generates JVM-compatible implementations of AutoBeanFactory and AutoBean
@@ -59,7 +59,7 @@
builder.setNoWrap(noWrap.value());
}
- return makeProxy(clazz, new FactoryHandler(builder.build()), EnumMap.class);
+ return ProxyAutoBean.makeProxy(clazz, new FactoryHandler(builder.build()), EnumMap.class);
}
/**
@@ -73,29 +73,4 @@
Configuration configuration) {
return new ProxyAutoBean<T>(EMPTY, clazz, configuration);
}
-
- /**
- * Utility method to crete a new {@link Proxy} instance.
- *
- * @param <T> the interface type to be implemented by the Proxy
- * @param intf the Class representing the interface type
- * @param handler the implementation of the interface
- * @param extraInterfaces additional interface types the Proxy should
- * implement
- * @return a Proxy instance
- */
- static <T> T makeProxy(Class<T> intf, InvocationHandler handler,
- Class<?>... extraInterfaces) {
- Class<?>[] intfs;
- if (extraInterfaces == null) {
- intfs = new Class<?>[] {intf};
- } else {
- intfs = new Class<?>[extraInterfaces.length + 1];
- intfs[0] = intf;
- System.arraycopy(extraInterfaces, 0, intfs, 1, extraInterfaces.length);
- }
-
- return intf.cast(Proxy.newProxyInstance(intf.getClassLoader(), intfs,
- handler));
- }
}
diff --git a/user/src/com/google/gwt/autobean/server/BeanMethod.java b/user/src/com/google/gwt/autobean/server/impl/BeanMethod.java
similarity index 76%
rename from user/src/com/google/gwt/autobean/server/BeanMethod.java
rename to user/src/com/google/gwt/autobean/server/impl/BeanMethod.java
index 24c2009..6cdf277 100644
--- a/user/src/com/google/gwt/autobean/server/BeanMethod.java
+++ b/user/src/com/google/gwt/autobean/server/impl/BeanMethod.java
@@ -13,23 +13,31 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.autobean.server;
+package com.google.gwt.autobean.server.impl;
-import com.google.gwt.autobean.server.impl.TypeUtils;
import com.google.gwt.autobean.shared.AutoBean;
+import java.beans.Introspector;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Breakout of method types that an AutoBean shim interface can implement. The
* order of the values of the enum is important.
+ *
+ * @see com.google.gwt.autobean.rebind.model.JBeanMethod
*/
-enum BeanMethod {
+public enum BeanMethod {
/**
* Methods defined in Object.
*/
OBJECT {
+
+ @Override
+ public String inferName(Method method) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
Object invoke(SimpleBeanHandler<?> handler, Method method, Object[] args)
throws Throwable {
@@ -49,15 +57,20 @@
*/
GET {
@Override
- Object invoke(SimpleBeanHandler<?> handler, Method method, Object[] args) {
- String propertyName;
+ public String inferName(Method method) {
String name = method.getName();
- if (Boolean.TYPE.equals(method.getReturnType()) && name.startsWith("is")) {
- propertyName = name.substring(2);
- } else {
- // A regular getter or a boolean hasFoo()
- propertyName = name.substring(3);
+ if (name.startsWith(IS_PREFIX)) {
+ Class<?> returnType = method.getReturnType();
+ if (Boolean.TYPE.equals(returnType) || Boolean.class.equals(returnType)) {
+ return Introspector.decapitalize(name.substring(2));
+ }
}
+ return super.inferName(method);
+ }
+
+ @Override
+ Object invoke(SimpleBeanHandler<?> handler, Method method, Object[] args) {
+ String propertyName = inferName(method);
Object toReturn = handler.getBean().getValues().get(propertyName);
if (toReturn == null && method.getReturnType().isPrimitive()) {
toReturn = TypeUtils.getDefaultPrimitiveValue(method.getReturnType());
@@ -74,13 +87,13 @@
}
String name = method.getName();
- if (Boolean.TYPE.equals(returnType)) {
- if (name.startsWith("is") && name.length() > 2
- || name.startsWith("has") && name.length() > 3) {
+ if (Boolean.TYPE.equals(returnType) || Boolean.class.equals(returnType)) {
+ if (name.startsWith(IS_PREFIX) && name.length() > 2
+ || name.startsWith(HAS_PREFIX) && name.length() > 3) {
return true;
}
}
- return name.startsWith("get") && name.length() > 3;
+ return name.startsWith(GET_PREFIX) && name.length() > 3;
}
},
/**
@@ -89,14 +102,14 @@
SET {
@Override
Object invoke(SimpleBeanHandler<?> handler, Method method, Object[] args) {
- handler.getBean().getValues().put(method.getName().substring(3), args[0]);
+ handler.getBean().getValues().put(inferName(method), args[0]);
return null;
}
@Override
boolean matches(SimpleBeanHandler<?> handler, Method method) {
String name = method.getName();
- return name.startsWith("set") && name.length() > 3
+ return name.startsWith(SET_PREFIX) && name.length() > 3
&& method.getParameterTypes().length == 1
&& method.getReturnType().equals(Void.TYPE);
}
@@ -106,6 +119,11 @@
*/
CALL {
@Override
+ public String inferName(Method method) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
Object invoke(SimpleBeanHandler<?> handler, Method method, Object[] args)
throws Throwable {
if (args == null) {
@@ -131,6 +149,11 @@
}
};
+ public static final String GET_PREFIX = "get";
+ public static final String HAS_PREFIX = "has";
+ public static final String IS_PREFIX = "is";
+ public static final String SET_PREFIX = "set";
+
private static final Object[] EMPTY_OBJECT = new Object[0];
static Method findMethod(SimpleBeanHandler<?> handler, Method method) {
@@ -161,6 +184,17 @@
return null;
}
+ public String inferName(Method method) {
+ return Introspector.decapitalize(method.getName().substring(3));
+ }
+
+ /**
+ * Convenience method, not valid for {@link BeanMethod#CALL}.
+ */
+ public boolean matches(Method method) {
+ return matches(null, method);
+ }
+
/**
* Invoke the method.
*/
@@ -168,13 +202,6 @@
Object[] args) throws Throwable;
/**
- * Convenience method, not valid for {@link BeanMethod#CALL}.
- */
- boolean matches(Method method) {
- return matches(null, method);
- }
-
- /**
* Determine if the method maches the given type.
*/
abstract boolean matches(SimpleBeanHandler<?> handler, Method method);
diff --git a/user/src/com/google/gwt/autobean/server/BeanPropertyContext.java b/user/src/com/google/gwt/autobean/server/impl/BeanPropertyContext.java
similarity index 75%
rename from user/src/com/google/gwt/autobean/server/BeanPropertyContext.java
rename to user/src/com/google/gwt/autobean/server/impl/BeanPropertyContext.java
index f0014b7..8b1a7a5 100644
--- a/user/src/com/google/gwt/autobean/server/BeanPropertyContext.java
+++ b/user/src/com/google/gwt/autobean/server/impl/BeanPropertyContext.java
@@ -13,9 +13,8 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.autobean.server;
+package com.google.gwt.autobean.server.impl;
-import com.google.gwt.autobean.server.impl.TypeUtils;
import java.lang.reflect.Method;
import java.util.Map;
@@ -30,7 +29,7 @@
public BeanPropertyContext(ProxyAutoBean<?> bean, Method getter) {
super(getter);
- propertyName = getter.getName().substring(3);
+ propertyName = BeanMethod.GET.inferName(getter);
map = bean.getPropertyMap();
}
@@ -41,6 +40,9 @@
@Override
public void set(Object value) {
- map.put(propertyName, TypeUtils.maybeAutobox(getType()).cast(value));
+ Class<?> maybeAutobox = TypeUtils.maybeAutobox(getType());
+ assert value == null || maybeAutobox.isInstance(value) : value.getClass().getCanonicalName()
+ + " is not assignable to " + maybeAutobox.getCanonicalName();
+ map.put(propertyName, maybeAutobox.cast(value));
}
}
diff --git a/user/src/com/google/gwt/autobean/server/FactoryHandler.java b/user/src/com/google/gwt/autobean/server/impl/FactoryHandler.java
similarity index 95%
rename from user/src/com/google/gwt/autobean/server/FactoryHandler.java
rename to user/src/com/google/gwt/autobean/server/impl/FactoryHandler.java
index c8090d1..4d21c6d 100644
--- a/user/src/com/google/gwt/autobean/server/FactoryHandler.java
+++ b/user/src/com/google/gwt/autobean/server/impl/FactoryHandler.java
@@ -13,8 +13,9 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.autobean.server;
+package com.google.gwt.autobean.server.impl;
+import com.google.gwt.autobean.server.Configuration;
import com.google.gwt.autobean.shared.AutoBean.PropertyName;
import com.google.gwt.autobean.shared.AutoBeanFactory;
import com.google.gwt.autobean.shared.AutoBeanUtils;
@@ -27,7 +28,7 @@
/**
* Handles dispatches on AutoBeanFactory interfaces.
*/
-class FactoryHandler implements InvocationHandler {
+public class FactoryHandler implements InvocationHandler {
private final Configuration configuration;
/**
diff --git a/user/src/com/google/gwt/autobean/server/GetterPropertyContext.java b/user/src/com/google/gwt/autobean/server/impl/GetterPropertyContext.java
similarity index 79%
rename from user/src/com/google/gwt/autobean/server/GetterPropertyContext.java
rename to user/src/com/google/gwt/autobean/server/impl/GetterPropertyContext.java
index ed904ea..7e61307 100644
--- a/user/src/com/google/gwt/autobean/server/GetterPropertyContext.java
+++ b/user/src/com/google/gwt/autobean/server/impl/GetterPropertyContext.java
@@ -13,7 +13,8 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.autobean.server;
+package com.google.gwt.autobean.server.impl;
+
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -30,12 +31,16 @@
this.shim = bean.as();
// Look for the setter method.
- Method found;
- try {
- found = bean.getBeanType().getMethod(
- "set" + getter.getName().substring(3), getter.getReturnType());
- } catch (NoSuchMethodException expected) {
- found = null;
+ Method found = null;
+ String name = BeanMethod.GET.inferName(getter);
+ for (Method m : getter.getDeclaringClass().getMethods()) {
+ if (BeanMethod.SET.matches(m)) {
+ if (BeanMethod.SET.inferName(m).equals(name)
+ && getter.getReturnType().isAssignableFrom(m.getParameterTypes()[0])) {
+ found = m;
+ break;
+ }
+ }
}
setter = found;
}
diff --git a/user/src/com/google/gwt/autobean/server/MethodPropertyContext.java b/user/src/com/google/gwt/autobean/server/impl/MethodPropertyContext.java
similarity index 96%
rename from user/src/com/google/gwt/autobean/server/MethodPropertyContext.java
rename to user/src/com/google/gwt/autobean/server/impl/MethodPropertyContext.java
index 315e185..b88d44b 100644
--- a/user/src/com/google/gwt/autobean/server/MethodPropertyContext.java
+++ b/user/src/com/google/gwt/autobean/server/impl/MethodPropertyContext.java
@@ -13,9 +13,8 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.autobean.server;
+package com.google.gwt.autobean.server.impl;
-import com.google.gwt.autobean.server.impl.TypeUtils;
import com.google.gwt.autobean.shared.AutoBeanVisitor.CollectionPropertyContext;
import com.google.gwt.autobean.shared.AutoBeanVisitor.MapPropertyContext;
diff --git a/user/src/com/google/gwt/autobean/server/ProxyAutoBean.java b/user/src/com/google/gwt/autobean/server/impl/ProxyAutoBean.java
similarity index 86%
rename from user/src/com/google/gwt/autobean/server/ProxyAutoBean.java
rename to user/src/com/google/gwt/autobean/server/impl/ProxyAutoBean.java
index 0992adc..4c93baa 100644
--- a/user/src/com/google/gwt/autobean/server/ProxyAutoBean.java
+++ b/user/src/com/google/gwt/autobean/server/impl/ProxyAutoBean.java
@@ -13,9 +13,9 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.autobean.server;
+package com.google.gwt.autobean.server.impl;
-import com.google.gwt.autobean.server.impl.TypeUtils;
+import com.google.gwt.autobean.server.Configuration;
import com.google.gwt.autobean.shared.AutoBean;
import com.google.gwt.autobean.shared.AutoBeanFactory;
import com.google.gwt.autobean.shared.AutoBeanUtils;
@@ -23,6 +23,7 @@
import com.google.gwt.autobean.shared.impl.AbstractAutoBean;
import com.google.gwt.core.client.impl.WeakMapping;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@@ -38,7 +39,7 @@
*
* @param <T> the type of interface being wrapped
*/
-class ProxyAutoBean<T> extends AbstractAutoBean<T> {
+public class ProxyAutoBean<T> extends AbstractAutoBean<T> {
private static class Data {
final List<Method> getters = new ArrayList<Method>();
final List<String> getterNames = new ArrayList<String>();
@@ -51,6 +52,31 @@
private static final Map<Class<?>, Data> cache = new WeakHashMap<Class<?>, Data>();
+ /**
+ * Utility method to crete a new {@link Proxy} instance.
+ *
+ * @param <T> the interface type to be implemented by the Proxy
+ * @param intf the Class representing the interface type
+ * @param handler the implementation of the interface
+ * @param extraInterfaces additional interface types the Proxy should
+ * implement
+ * @return a Proxy instance
+ */
+ public static <T> T makeProxy(Class<T> intf, InvocationHandler handler,
+ Class<?>... extraInterfaces) {
+ Class<?>[] intfs;
+ if (extraInterfaces == null) {
+ intfs = new Class<?>[] {intf};
+ } else {
+ intfs = new Class<?>[extraInterfaces.length + 1];
+ intfs[0] = intf;
+ System.arraycopy(extraInterfaces, 0, intfs, 1, extraInterfaces.length);
+ }
+
+ return intf.cast(Proxy.newProxyInstance(intf.getClassLoader(), intfs,
+ handler));
+ }
+
private static Data calculateData(Class<?> beanType) {
Data toReturn;
synchronized (cache) {
@@ -66,9 +92,7 @@
if (annotation != null) {
name = annotation.value();
} else {
- name = method.getName();
- name = Character.toLowerCase(name.charAt(3))
- + (name.length() >= 5 ? name.substring(4) : "");
+ name = BeanMethod.GET.inferName(method);
}
toReturn.getterNames.add(name);
@@ -93,6 +117,7 @@
private final Class<T> beanType;
private final Configuration configuration;
private final Data data;
+
private final T shim;
// These constructors mirror the generated constructors.
@@ -171,8 +196,7 @@
@Override
protected T createSimplePeer() {
- return AutoBeanFactoryMagic.makeProxy(beanType, new SimpleBeanHandler<T>(
- this));
+ return ProxyAutoBean.makeProxy(beanType, new SimpleBeanHandler<T>(this));
}
/**
@@ -293,8 +317,8 @@
}
private T createShim() {
- T toReturn = AutoBeanFactoryMagic.makeProxy(beanType, new ShimHandler<T>(
- this, getWrapped()));
+ T toReturn = ProxyAutoBean.makeProxy(beanType, new ShimHandler<T>(this,
+ getWrapped()));
WeakMapping.set(toReturn, AutoBean.class.getName(), this);
return toReturn;
}
diff --git a/user/src/com/google/gwt/autobean/server/ShimHandler.java b/user/src/com/google/gwt/autobean/server/impl/ShimHandler.java
similarity index 97%
rename from user/src/com/google/gwt/autobean/server/ShimHandler.java
rename to user/src/com/google/gwt/autobean/server/impl/ShimHandler.java
index 94103ae..d2930d6 100644
--- a/user/src/com/google/gwt/autobean/server/ShimHandler.java
+++ b/user/src/com/google/gwt/autobean/server/impl/ShimHandler.java
@@ -13,9 +13,8 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.autobean.server;
+package com.google.gwt.autobean.server.impl;
-import com.google.gwt.autobean.server.impl.TypeUtils;
import com.google.gwt.autobean.shared.AutoBean;
import com.google.gwt.autobean.shared.AutoBeanUtils;
diff --git a/user/src/com/google/gwt/autobean/server/SimpleBeanHandler.java b/user/src/com/google/gwt/autobean/server/impl/SimpleBeanHandler.java
similarity index 97%
rename from user/src/com/google/gwt/autobean/server/SimpleBeanHandler.java
rename to user/src/com/google/gwt/autobean/server/impl/SimpleBeanHandler.java
index 9f0dc3f..d25468d 100644
--- a/user/src/com/google/gwt/autobean/server/SimpleBeanHandler.java
+++ b/user/src/com/google/gwt/autobean/server/impl/SimpleBeanHandler.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.google.gwt.autobean.server;
+package com.google.gwt.autobean.server.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
diff --git a/user/src/com/google/gwt/requestfactory/rebind/model/RequestFactoryModel.java b/user/src/com/google/gwt/requestfactory/rebind/model/RequestFactoryModel.java
index 2ea756b..1e3419b 100644
--- a/user/src/com/google/gwt/requestfactory/rebind/model/RequestFactoryModel.java
+++ b/user/src/com/google/gwt/requestfactory/rebind/model/RequestFactoryModel.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.requestfactory.rebind.model;
+import com.google.gwt.autobean.rebind.model.JBeanMethod;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
@@ -236,6 +237,7 @@
// Look at the methods declared on the EntityProxy
List<RequestMethod> requestMethods = new ArrayList<RequestMethod>();
+ Map<String, JMethod> duplicatePropertyGetters = new HashMap<String, JMethod>();
for (JMethod method : entityProxyType.getInheritableMethods()) {
if (method.getEnclosingType().equals(entityProxyInterface)) {
// Ignore methods on EntityProxy
@@ -246,11 +248,18 @@
JType transportedType;
String name = method.getName();
- if (name.startsWith("get") && method.getParameters().length == 0) {
- // Getter
+ if (JBeanMethod.GET.matches(method)) {
transportedType = method.getReturnType();
+ String propertyName = JBeanMethod.GET.inferName(method);
+ JMethod previouslySeen = duplicatePropertyGetters.get(propertyName);
+ if (previouslySeen == null) {
+ duplicatePropertyGetters.put(propertyName, method);
+ } else {
+ poison("Duplicate accessors for property %s: %s() and %s()",
+ propertyName, previouslySeen.getName(), method.getName());
+ }
- } else if (name.startsWith("set") && method.getParameters().length == 1) {
+ } else if (JBeanMethod.SET.matches(method)) {
transportedType = method.getParameters()[0].getType();
} else if (name.equals("stableId")
diff --git a/user/src/com/google/gwt/requestfactory/server/ReflectiveServiceLayer.java b/user/src/com/google/gwt/requestfactory/server/ReflectiveServiceLayer.java
index 4f20c7b..a04226b 100644
--- a/user/src/com/google/gwt/requestfactory/server/ReflectiveServiceLayer.java
+++ b/user/src/com/google/gwt/requestfactory/server/ReflectiveServiceLayer.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.requestfactory.server;
+import com.google.gwt.autobean.server.impl.BeanMethod;
import com.google.gwt.autobean.server.impl.TypeUtils;
import com.google.gwt.autobean.shared.ValueCodex;
import com.google.gwt.requestfactory.shared.BaseProxy;
@@ -65,9 +66,19 @@
jsr303Validator = found;
}
- private static String capitalize(String name) {
- return Character.toUpperCase(name.charAt(0))
- + (name.length() >= 1 ? name.substring(1) : "");
+ /**
+ * Linear search, but we want to handle getFoo, isFoo, and hasFoo. The result
+ * of this method will be cached by the ServiceLayerCache.
+ */
+ private static Method getBeanMethod(BeanMethod methodType,
+ Class<?> domainType, String property) {
+ for (Method m : domainType.getMethods()) {
+ if (methodType.matches(m) && property.equals(methodType.inferName(m))) {
+ m.setAccessible(true);
+ return m;
+ }
+ }
+ return null;
}
@Override
@@ -96,6 +107,11 @@
}
@Override
+ public Method getGetter(Class<?> domainType, String property) {
+ return getBeanMethod(BeanMethod.GET, domainType, property);
+ }
+
+ @Override
public Object getId(Object domainObject) {
return getTop().getProperty(domainObject, "id");
}
@@ -107,25 +123,19 @@
@Override
public Object getProperty(Object domainObject, String property) {
- Throwable toReport;
try {
- Method method = domainObject.getClass().getMethod(
- "get" + capitalize(property));
- method.setAccessible(true);
- Object value = method.invoke(domainObject);
+ Method getter = getTop().getGetter(domainObject.getClass(), property);
+ if (getter == null) {
+ die(null, "Could not determine getter for property %s on type %s",
+ property, domainObject.getClass().getCanonicalName());
+ }
+ Object value = getter.invoke(domainObject);
return value;
- } catch (SecurityException e) {
- toReport = e;
- } catch (NoSuchMethodException e) {
- toReport = e;
- } catch (IllegalArgumentException e) {
- toReport = e;
} catch (IllegalAccessException e) {
- toReport = e;
+ return die(e, "Could not retrieve property %s", property);
} catch (InvocationTargetException e) {
return report(e);
}
- return die(toReport, "Could not retrieve property %s", property);
}
@Override
@@ -147,6 +157,11 @@
}
@Override
+ public Method getSetter(Class<?> domainType, String property) {
+ return getBeanMethod(BeanMethod.SET, domainType, property);
+ }
+
+ @Override
public Object getVersion(Object domainObject) {
return getTop().getProperty(domainObject, "version");
}
@@ -210,28 +225,19 @@
@Override
public void setProperty(Object domainObject, String property,
Class<?> expectedType, Object value) {
- Method setter;
- Throwable ex;
try {
- setter = domainObject.getClass().getMethod("set" + capitalize(property),
- expectedType);
- setter.setAccessible(true);
+ Method setter = getTop().getSetter(domainObject.getClass(), property);
+ if (setter == null) {
+ die(null, "Could not locate setter for property %s in type %s",
+ property, domainObject.getClass().getCanonicalName());
+ }
setter.invoke(domainObject, value);
return;
- } catch (SecurityException e) {
- ex = e;
- } catch (NoSuchMethodException e) {
- ex = e;
- } catch (IllegalArgumentException e) {
- ex = e;
} catch (IllegalAccessException e) {
- ex = e;
+ die(e, "Could not set property %s", property);
} catch (InvocationTargetException e) {
report(e);
- return;
}
- die(ex, "Could not locate setter for property %s in type %s", property,
- domainObject.getClass().getCanonicalName());
}
@Override
diff --git a/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java b/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java
index 8cd93a4..1c4062a 100644
--- a/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java
+++ b/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java
@@ -44,6 +44,12 @@
*/
/**
+ * Provides a flag to disable the ServiceLayerCache for debugging purposes.
+ */
+ private static final boolean ENABLE_CACHE = Boolean.valueOf(System.getProperty(
+ "gwt.rf.ServiceLayerCache", "true"));
+
+ /**
* Create a RequestFactory ServiceLayer that is optionally modified by the
* given decorators.
*
@@ -54,7 +60,8 @@
public static ServiceLayer create(ServiceLayerDecorator... decorators) {
List<ServiceLayerDecorator> list = new ArrayList<ServiceLayerDecorator>();
// Always hit the cache first
- ServiceLayerCache cache = new ServiceLayerCache();
+ ServiceLayerDecorator cache = ENABLE_CACHE ? new ServiceLayerCache()
+ : new ServiceLayerDecorator();
list.add(cache);
// The the user-provided decorators
if (decorators != null) {
@@ -121,6 +128,16 @@
Method domainMethod);
/**
+ * Determine the method to invoke when retrieving the given property.
+ *
+ * @param domainType a domain entity type
+ * @param property the name of the property to be retrieved
+ * @return the Method that should be invoked to retrieve the property or
+ * {@code null} if the method could not be located
+ */
+ public abstract Method getGetter(Class<?> domainType, String property);
+
+ /**
* 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
@@ -162,6 +179,16 @@
public abstract Type getRequestReturnType(Method contextMethod);
/**
+ * Determine the method to invoke when setting the given property.
+ *
+ * @param domainType a domain entity type
+ * @param property the name of the property to be set
+ * @return the Method that should be invoked to set the property or
+ * {@code null} if the method could not be located
+ */
+ public abstract Method getSetter(Class<?> domainType, String property);
+
+ /**
* 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 type for which a mapping to an EntityProxy or
diff --git a/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java b/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java
index 0c89f75..80102cc 100644
--- a/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java
+++ b/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java
@@ -44,8 +44,10 @@
private static final Method createLocator;
private static final Method createServiceInstance;
+ private static final Method getGetter;
private static final Method getIdType;
private static final Method getRequestReturnType;
+ private static final Method getSetter;
private static final Method requiresServiceLocator;
private static final Method resolveClass;
private static final Method resolveClientType;
@@ -60,8 +62,10 @@
createLocator = getMethod("createLocator", Class.class);
createServiceInstance = getMethod("createServiceInstance", Method.class,
Method.class);
+ getGetter = getMethod("getGetter", Class.class, String.class);
getIdType = getMethod("getIdType", Class.class);
getRequestReturnType = getMethod("getRequestReturnType", Method.class);
+ getSetter = getMethod("getSetter", Class.class, String.class);
requiresServiceLocator = getMethod("requiresServiceLocator", Method.class,
Method.class);
resolveClass = getMethod("resolveClass", String.class);
@@ -114,6 +118,12 @@
}
@Override
+ public Method getGetter(Class<?> domainType, String property) {
+ return getOrCache(getGetter, new Pair<Class<?>, String>(domainType,
+ property), Method.class, domainType, property);
+ }
+
+ @Override
public Class<?> getIdType(Class<?> domainType) {
return getOrCache(getIdType, domainType, Class.class, domainType);
}
@@ -125,6 +135,12 @@
}
@Override
+ public Method getSetter(Class<?> domainType, String property) {
+ return getOrCache(getSetter, new Pair<Class<?>, String>(domainType,
+ property), Method.class, domainType, property);
+ }
+
+ @Override
public boolean requiresServiceLocator(Method contextMethod,
Method domainMethod) {
return getOrCache(requiresServiceLocator, new Pair<Method, Method>(
diff --git a/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java b/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java
index c642d94..3167acb 100644
--- a/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java
+++ b/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java
@@ -60,6 +60,11 @@
}
@Override
+ public Method getGetter(Class<?> domainType, String property) {
+ return getNext().getGetter(domainType, property);
+ }
+
+ @Override
public Object getId(Object domainObject) {
return getNext().getId(domainObject);
}
@@ -80,6 +85,11 @@
}
@Override
+ public Method getSetter(Class<?> domainType, String property) {
+ return getNext().getSetter(domainType, property);
+ }
+
+ @Override
public Object getVersion(Object domainObject) {
return getNext().getVersion(domainObject);
}
diff --git a/user/test/com/google/gwt/autobean/client/AutoBeanTest.java b/user/test/com/google/gwt/autobean/client/AutoBeanTest.java
index c9484a1..759b93c 100644
--- a/user/test/com/google/gwt/autobean/client/AutoBeanTest.java
+++ b/user/test/com/google/gwt/autobean/client/AutoBeanTest.java
@@ -104,9 +104,13 @@
interface OtherIntf {
Intf getIntf();
+ HasBoolean getHasBoolean();
+
UnreferencedInFactory getUnreferenced();
void setIntf(Intf intf);
+
+ void setHasBoolean(HasBoolean value);
}
static class RealIntf implements Intf {
@@ -362,17 +366,26 @@
public void testTraversal() {
final AutoBean<OtherIntf> other = factory.otherIntf();
final AutoBean<Intf> intf = factory.intf();
+ final AutoBean<HasBoolean> hasBoolean = factory.hasBoolean();
other.as().setIntf(intf.as());
+ other.as().setHasBoolean(hasBoolean.as());
intf.as().setInt(42);
+ hasBoolean.as().setGet(true);
+ hasBoolean.as().setHas(true);
+ hasBoolean.as().setIs(true);
class Checker extends AutoBeanVisitor {
- boolean seenOther;
+ boolean seenHasBoolean;
boolean seenIntf;
+ boolean seenOther;
@Override
public void endVisitReferenceProperty(String propertyName,
AutoBean<?> value, PropertyContext ctx) {
- if ("intf".equals(propertyName)) {
+ if ("hasBoolean".equals(propertyName)) {
+ assertSame(hasBoolean, value);
+ assertEquals(HasBoolean.class, ctx.getType());
+ } else if ("intf".equals(propertyName)) {
assertSame(intf, value);
assertEquals(Intf.class, ctx.getType());
} else if ("unreferenced".equals(propertyName)) {
@@ -392,6 +405,10 @@
} else if ("string".equals(propertyName)) {
assertNull(value);
assertEquals(String.class, ctx.getType());
+ } else if ("get".equals(propertyName) || "has".equals(propertyName)
+ || "is".equals(propertyName)) {
+ assertEquals(boolean.class, ctx.getType());
+ assertTrue((Boolean) value);
} else {
fail("Unknown value property " + propertyName);
}
@@ -399,10 +416,12 @@
@Override
public boolean visit(AutoBean<?> bean, Context ctx) {
- if (bean == other) {
- seenOther = true;
+ if (bean == hasBoolean) {
+ seenHasBoolean = true;
} else if (bean == intf) {
seenIntf = true;
+ } else if (bean == other) {
+ seenOther = true;
} else {
fail("Unknown AutoBean");
}
@@ -410,8 +429,9 @@
}
void check() {
- assertTrue(seenOther);
+ assertTrue(seenHasBoolean);
assertTrue(seenIntf);
+ assertTrue(seenOther);
}
}
Checker c = new Checker();
diff --git a/user/test/com/google/gwt/autobean/shared/AutoBeanCodexTest.java b/user/test/com/google/gwt/autobean/shared/AutoBeanCodexTest.java
index 348dfe3..798bdce 100644
--- a/user/test/com/google/gwt/autobean/shared/AutoBeanCodexTest.java
+++ b/user/test/com/google/gwt/autobean/shared/AutoBeanCodexTest.java
@@ -147,8 +147,16 @@
String getString();
+ Boolean hasOtherBoolean();
+
+ boolean isBoolean();
+
+ void setBoolean(boolean b);
+
void setInt(int i);
+ void setOtherBoolean(Boolean b);
+
void setString(String s);
}
@@ -265,11 +273,15 @@
public void testSimple() {
AutoBean<Simple> bean = f.simple();
Simple simple = bean.as();
+ simple.setBoolean(true);
simple.setInt(42);
+ simple.setOtherBoolean(true);
simple.setString("Hello World!");
AutoBean<Simple> decodedBean = checkEncode(bean);
assertTrue(AutoBeanUtils.diff(bean, decodedBean).isEmpty());
+ assertTrue(decodedBean.as().isBoolean());
+ assertTrue(decodedBean.as().hasOtherBoolean());
AutoBean<HasSimple> bean2 = f.hasSimple();
bean2.as().setSimple(simple);
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 ce68390..14f14fb 100644
--- a/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java
+++ b/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java
@@ -140,6 +140,11 @@
"Invalid Request parameterization java.lang.Iterable");
}
+ public void testDuplicateBooleanGetters() {
+ testModelWithMethodDecl("Request<t.ProxyWithRepeatedGetters> method();",
+ "Duplicate accessors for property foo: getFoo() and isFoo()");
+ }
+
public void testMissingProxyFor() {
testModelWithMethodDeclArgs("Request<TestProxy> okMethodProxy();",
TestContextImpl.class.getName(), null,
@@ -233,6 +238,22 @@
code.append("}");
return code;
}
+ }, new MockJavaResource("t.ProxyWithRepeatedGetters") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuilder code = new StringBuilder();
+ code.append("package t;\n");
+ code.append("import " + ProxyFor.class.getName() + ";\n");
+ code.append("import " + EntityProxy.class.getName() + ";\n");
+ if (proxyClass != null) {
+ code.append("@ProxyFor(" + proxyClass + ".class)");
+ }
+ code.append("interface ProxyWithRepeatedGetters extends EntityProxy {\n");
+ code.append(" boolean getFoo();");
+ code.append(" boolean isFoo();");
+ code.append("}");
+ return code;
+ }
}, new MockJavaResource("java.util.List") {
// Tests a Driver interface that extends more than RFED
@Override
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
index dad490c..d02ce15 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
@@ -129,6 +129,8 @@
* objects with a null version property.
*/
public static SimpleFoo getSimpleFooWithNullVersion() {
+ System.err.println("The following exception about an entity with a null"
+ + " version is expected");
SimpleFoo foo = new SimpleFoo();
foo.setVersion(null);
return foo;
diff --git a/user/test/com/google/gwt/requestfactory/shared/BoxesAndPrimitivesTest.java b/user/test/com/google/gwt/requestfactory/shared/BoxesAndPrimitivesTest.java
index ddcea1d..99fe784 100644
--- a/user/test/com/google/gwt/requestfactory/shared/BoxesAndPrimitivesTest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/BoxesAndPrimitivesTest.java
@@ -51,6 +51,22 @@
return 0;
}
+ public boolean hasHas() {
+ return EXPECTED_BOOL;
+ }
+
+ public Boolean hasHasBoxed() {
+ return EXPECTED_BOOL_BOXED;
+ }
+
+ public boolean isIs() {
+ return EXPECTED_BOOL;
+ }
+
+ public Boolean isIsBoxed() {
+ return EXPECTED_BOOL_BOXED;
+ }
+
public void setBoxed(Integer value) {
assertEquals(EXPECTED_BOXED, value);
}
@@ -111,6 +127,14 @@
int getPrimitive();
+ boolean hasHas();
+
+ Boolean hasHasBoxed();
+
+ boolean isIs();
+
+ Boolean isIsBoxed();
+
void setBoxed(Integer value);
void setPrimitive(int value);
@@ -125,6 +149,8 @@
private static final int EXPECTED = 42;
private static final Integer EXPECTED_BOXED = Integer.valueOf(EXPECTED);
+ private static final boolean EXPECTED_BOOL = true;
+ private static final Boolean EXPECTED_BOOL_BOXED = Boolean.TRUE;
private static final int TEST_DELAY = 5000;
private Factory factory;
@@ -163,6 +189,10 @@
public void onSuccess(Proxy response) {
assertEquals(EXPECTED_BOXED, response.getBoxed());
assertEquals(EXPECTED, response.getPrimitive());
+ assertEquals(EXPECTED_BOOL, response.isIs());
+ assertEquals(EXPECTED_BOOL_BOXED, response.isIsBoxed());
+ assertEquals(EXPECTED_BOOL, response.hasHas());
+ assertEquals(EXPECTED_BOOL_BOXED, response.hasHasBoxed());
}
});
// Boxed service argument