Support up-casting subclasses of java.util.Date (e.g. java.sql.Date).
Issue 5675.
Patch by: bobv
Review by: rjrjr, rchandia
Review at http://gwt-code-reviews.appspot.com/1177801
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9336 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/tools/api-checker/config/gwt21_22userApi.conf b/tools/api-checker/config/gwt21_22userApi.conf
index f876d49..e700609 100644
--- a/tools/api-checker/config/gwt21_22userApi.conf
+++ b/tools/api-checker/config/gwt21_22userApi.conf
@@ -73,6 +73,7 @@
:**/server/**\
:**/tools/**\
:user/src/com/google/gwt/regexp/shared/**\
+:user/src/com/google/gwt/autobean/shared/ValueCodexHelper.java\
:user/src/com/google/gwt/autobean/shared/impl/StringQuoter.java\
:user/src/com/google/gwt/core/client/impl/WeakMapping.java\
:user/src/com/google/gwt/junit/*.java\
diff --git a/user/src/com/google/gwt/autobean/shared/AutoBeanCodex.java b/user/src/com/google/gwt/autobean/shared/AutoBeanCodex.java
index 9d228f4..2ae2f0e 100644
--- a/user/src/com/google/gwt/autobean/shared/AutoBeanCodex.java
+++ b/user/src/com/google/gwt/autobean/shared/AutoBeanCodex.java
@@ -295,7 +295,8 @@
if (ValueCodex.canDecode(ctx.getElementType())) {
for (Object element : collection) {
- sb.append(",").append(encodeValue(element).getPayload());
+ sb.append(",").append(
+ encodeValue(ctx.getElementType(), element).getPayload());
}
} else {
boolean isEncoded = Splittable.class.equals(ctx.getElementType());
@@ -330,15 +331,18 @@
return false;
}
- boolean isEncodedKey = Splittable.class.equals(ctx.getKeyType());
- boolean isEncodedValue = Splittable.class.equals(ctx.getValueType());
- boolean isValueKey = ValueCodex.canDecode(ctx.getKeyType());
- boolean isValueValue = ValueCodex.canDecode(ctx.getValueType());
+ Class<?> keyType = ctx.getKeyType();
+ Class<?> valueType = ctx.getValueType();
+ boolean isEncodedKey = Splittable.class.equals(keyType);
+ boolean isEncodedValue = Splittable.class.equals(valueType);
+ boolean isValueKey = ValueCodex.canDecode(keyType);
+ boolean isValueValue = ValueCodex.canDecode(valueType);
if (isValueKey) {
- writeValueKeyMap(map, isEncodedValue, isValueValue);
+ writeValueKeyMap(map, keyType, valueType, isEncodedValue, isValueValue);
} else {
- writeObjectKeyMap(map, isEncodedKey, isEncodedValue, isValueValue);
+ writeObjectKeyMap(map, valueType, isEncodedKey, isEncodedValue,
+ isValueValue);
}
return false;
@@ -377,7 +381,7 @@
// Special handling for enums if we have an obfuscation map
Splittable split;
- split = encodeValue(value);
+ split = encodeValue(type, value);
sb.append(",\"").append(propertyName).append("\":").append(
split.getPayload());
return false;
@@ -409,12 +413,13 @@
* Encodes a value, with special handling for enums to allow the field name
* to be overridden.
*/
- private Splittable encodeValue(Object value) {
+ private Splittable encodeValue(Class<?> expectedType, Object value) {
Splittable split;
if (value instanceof Enum<?> && enumMap != null) {
- split = ValueCodex.encode(enumMap.getToken((Enum<?>) value));
+ split = ValueCodex.encode(String.class,
+ enumMap.getToken((Enum<?>) value));
} else {
- split = ValueCodex.encode(value);
+ split = ValueCodex.encode(expectedType, value);
}
return split;
}
@@ -429,8 +434,8 @@
* encoded as a list of two lists, since it's possible that two distinct
* objects have the same encoded form.
*/
- private void writeObjectKeyMap(Map<?, ?> map, boolean isEncodedKey,
- boolean isEncodedValue, boolean isValueValue) {
+ private void writeObjectKeyMap(Map<?, ?> map, Class<?> valueType,
+ boolean isEncodedKey, boolean isEncodedValue, boolean isValueValue) {
StringBuilder keys = new StringBuilder();
StringBuilder values = new StringBuilder();
@@ -445,7 +450,8 @@
values.append(",").append(
((Splittable) entry.getValue()).getPayload());
} else if (isValueValue) {
- values.append(",").append(encodeValue(entry.getValue()).getPayload());
+ values.append(",").append(
+ encodeValue(valueType, entry.getValue()).getPayload());
} else {
encodeToStringBuilder(values.append(","), entry.getValue());
}
@@ -462,15 +468,15 @@
/**
* Writes a map JSON literal where the keys are value types.
*/
- private void writeValueKeyMap(Map<?, ?> map, boolean isEncodedValue,
- boolean isValueValue) {
+ private void writeValueKeyMap(Map<?, ?> map, Class<?> keyType,
+ Class<?> valueType, boolean isEncodedValue, boolean isValueValue) {
for (Map.Entry<?, ?> entry : map.entrySet()) {
- sb.append(",").append(encodeValue(entry.getKey()).getPayload()).append(
+ sb.append(",").append(encodeValue(keyType, entry.getKey()).getPayload()).append(
":");
if (isEncodedValue) {
sb.append(((Splittable) entry.getValue()).getPayload());
} else if (isValueValue) {
- sb.append(encodeValue(entry.getValue()).getPayload());
+ sb.append(encodeValue(valueType, entry.getValue()).getPayload());
} else {
encodeToStringBuilder(sb, entry.getValue());
}
diff --git a/user/src/com/google/gwt/autobean/shared/ValueCodex.java b/user/src/com/google/gwt/autobean/shared/ValueCodex.java
index d4a452f..ca867eb 100644
--- a/user/src/com/google/gwt/autobean/shared/ValueCodex.java
+++ b/user/src/com/google/gwt/autobean/shared/ValueCodex.java
@@ -20,9 +20,11 @@
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
/**
* Provides unified encoding and decoding of value objects.
@@ -31,6 +33,11 @@
enum Type {
BIG_DECIMAL(BigDecimal.class) {
@Override
+ public boolean canUpcast(Object value) {
+ return value instanceof BigDecimal;
+ }
+
+ @Override
public BigDecimal decode(Class<?> clazz, String value) {
return new BigDecimal(value);
}
@@ -42,6 +49,11 @@
},
BIG_INTEGER(BigInteger.class) {
@Override
+ public boolean canUpcast(Object value) {
+ return value instanceof BigInteger;
+ }
+
+ @Override
public BigInteger decode(Class<?> clazz, String value) {
return new BigInteger(value);
}
@@ -71,6 +83,11 @@
},
DATE(Date.class) {
@Override
+ public boolean canUpcast(Object value) {
+ return value instanceof Date;
+ }
+
+ @Override
public Date decode(Class<?> clazz, String value) {
return new Date(Long.valueOf(value));
}
@@ -158,6 +175,15 @@
this.defaultValue = defaultValue;
}
+ /**
+ * Determines whether or not the Type can handle the given value via
+ * upcasting semantics.
+ */
+ public boolean canUpcast(Object value) {
+ // Most value types are final, so this method is meaningless
+ return false;
+ }
+
public abstract Object decode(Class<?> clazz, String value);
public Object getDefaultValue() {
@@ -177,14 +203,18 @@
}
}
- private static Map<Class<?>, Type> typesByClass = new HashMap<Class<?>, Type>();
+ private static final Set<Class<?>> ALL_VALUE_TYPES;
+ private static final Map<Class<?>, Type> TYPES_BY_CLASS;
static {
+ Map<Class<?>, Type> temp = new HashMap<Class<?>, Type>();
for (Type t : Type.values()) {
- typesByClass.put(t.getType(), t);
+ temp.put(t.getType(), t);
if (t.getPrimitiveType() != null) {
- typesByClass.put(t.getPrimitiveType(), t);
+ temp.put(t.getPrimitiveType(), t);
}
}
+ ALL_VALUE_TYPES = Collections.unmodifiableSet(temp.keySet());
+ TYPES_BY_CLASS = Collections.unmodifiableMap(temp);
}
/**
@@ -194,7 +224,11 @@
* @return {@code true} if the given object type can be decoded
*/
public static boolean canDecode(Class<?> clazz) {
- return findType(clazz) != null;
+ if (findType(clazz) != null) {
+ return true;
+ }
+ // Use other platform-specific tests
+ return ValueCodexHelper.canDecode(clazz);
}
public static <T> T decode(Class<T> clazz, Splittable split) {
@@ -212,12 +246,42 @@
return (T) getTypeOrDie(clazz).decode(clazz, string);
}
+ /**
+ * Encode a value object when the wire format type is known. This method
+ * should be preferred over {@link #encode(Object)} when possible.
+ */
+ public static Splittable encode(Class<?> clazz, Object obj) {
+ if (obj == null) {
+ return LazySplittable.NULL;
+ }
+ return new LazySplittable(getTypeOrDie(clazz).toJsonExpression(obj));
+ }
+
public static Splittable encode(Object obj) {
if (obj == null) {
return LazySplittable.NULL;
}
- return new LazySplittable(
- getTypeOrDie(obj.getClass()).toJsonExpression(obj));
+ Type t = findType(obj.getClass());
+ // Try upcasting
+ if (t == null) {
+ for (Type maybe : Type.values()) {
+ if (maybe.canUpcast(obj)) {
+ t = maybe;
+ break;
+ }
+ }
+ }
+ if (t == null) {
+ throw new UnsupportedOperationException(obj.getClass().getName());
+ }
+ return new LazySplittable(t.toJsonExpression(obj));
+ }
+
+ /**
+ * Return all Value types that can be processed by the ValueCodex.
+ */
+ public static Set<Class<?>> getAllValueTypes() {
+ return ALL_VALUE_TYPES;
}
/**
@@ -235,13 +299,10 @@
* May return <code>null</code>.
*/
private static <T> Type findType(Class<T> clazz) {
- Type type = typesByClass.get(clazz);
- if (type == null) {
- if (clazz.isEnum()) {
- return Type.ENUM;
- }
+ if (clazz.isEnum()) {
+ return Type.ENUM;
}
- return type;
+ return TYPES_BY_CLASS.get(clazz);
}
private static <T> Type getTypeOrDie(Class<T> clazz) {
diff --git a/user/src/com/google/gwt/autobean/shared/ValueCodexHelper.java b/user/src/com/google/gwt/autobean/shared/ValueCodexHelper.java
new file mode 100644
index 0000000..c6f72c8
--- /dev/null
+++ b/user/src/com/google/gwt/autobean/shared/ValueCodexHelper.java
@@ -0,0 +1,38 @@
+/*
+ * 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.autobean.shared;
+
+import com.google.gwt.core.client.GWT;
+
+/**
+ * Provides reflection-based operation for server (JVM) implementation. There is
+ * a no-op super-source version for client (dev- and web-mode) code.
+ */
+class ValueCodexHelper {
+ /**
+ * Returns {@code true} if {@code clazz} is assignable to any of the value
+ * types.
+ */
+ static boolean canDecode(Class<?> clazz) {
+ assert !GWT.isClient();
+ for (Class<?> valueType : ValueCodex.getAllValueTypes()) {
+ if (valueType.isAssignableFrom(clazz)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java b/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java
index 583c49d..310b9dd 100644
--- a/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java
+++ b/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java
@@ -15,15 +15,14 @@
*/
package com.google.gwt.editor.rebind.model;
+import com.google.gwt.autobean.shared.ValueCodex;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.Date;
import java.util.HashSet;
import java.util.Set;
@@ -32,16 +31,12 @@
*/
public class ModelUtils {
- @SuppressWarnings("unchecked")
- static final Set<Class<?>> VALUE_TYPES = Collections.unmodifiableSet(new HashSet<Class<?>>(
- Arrays.asList(Boolean.class, Character.class, Class.class, Date.class,
- Enum.class, Number.class, String.class, Void.class)));
-
static final Set<String> VALUE_TYPE_NAMES;
static {
- Set<String> names = new HashSet<String>(VALUE_TYPES.size());
- for (Class<?> clazz : VALUE_TYPES) {
+ Set<Class<?>> valueTypes = ValueCodex.getAllValueTypes();
+ Set<String> names = new HashSet<String>(valueTypes.size());
+ for (Class<?> clazz : valueTypes) {
names.add(clazz.getName());
}
VALUE_TYPE_NAMES = Collections.unmodifiableSet(names);
@@ -110,11 +105,14 @@
if (classType == null) {
return true;
}
+ if (type.isEnum() != null) {
+ return true;
+ }
for (String valueType : VALUE_TYPE_NAMES) {
JClassType found = oracle.findType(valueType);
// null check to accommodate limited mock CompilationStates
- if (found != null && found.isAssignableFrom(classType)) {
+ if (found != null && found.equals(classType)) {
return true;
}
}
diff --git a/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java b/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java
index 2c8f005..f034b1c 100644
--- a/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java
+++ b/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.requestfactory.server;
+import com.google.gwt.autobean.shared.ValueCodex;
import com.google.gwt.dev.asm.AnnotationVisitor;
import com.google.gwt.dev.asm.ClassReader;
import com.google.gwt.dev.asm.ClassVisitor;
@@ -44,9 +45,7 @@
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -517,10 +516,7 @@
}
}
- @SuppressWarnings("unchecked")
- static final Set<Class<?>> VALUE_TYPES = Collections.unmodifiableSet(new HashSet<Class<?>>(
- Arrays.asList(Boolean.class, Character.class, Class.class, Date.class,
- Enum.class, Number.class, String.class, Void.class)));
+ static final Set<Class<?>> VALUE_TYPES = ValueCodex.getAllValueTypes();
public static void main(String[] args) {
if (args.length == 0) {
@@ -578,6 +574,10 @@
*/
private final Type entityProxyIntf = Type.getType(EntityProxy.class);
/**
+ * The type {@link Enum}.
+ */
+ private final Type enumType = Type.getType(Enum.class);
+ /**
* A placeholder type for client types that could not be resolved to a domain
* type.
*/
@@ -1361,12 +1361,8 @@
return true;
}
logger = logger.setType(type);
- List<Type> types = getSupertypes(logger, type);
- for (Type t : types) {
- if (valueTypes.contains(t)) {
- valueTypes.add(type);
- return true;
- }
+ if (isAssignable(logger, enumType, type)) {
+ return true;
}
return false;
}
diff --git a/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java b/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java
index 2a45831..839f4ee 100644
--- a/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java
+++ b/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java
@@ -434,7 +434,10 @@
if (properties.containsKey(propertyName)) {
Splittable raw = properties.get(propertyName);
Object decoded = ValueCodex.decode(ctx.getType(), raw);
- // Hack for Date, consider generalizing for "custom serializers"
+ /*
+ * Hack for Date subtypes, consider generalizing for
+ * "custom serializers"
+ */
if (decoded != null && Date.class.equals(ctx.getType())) {
decoded = new DatePoser((Date) decoded);
}
diff --git a/user/super/com/google/gwt/autobean/super/com/google/gwt/autobean/shared/ValueCodexHelper.java b/user/super/com/google/gwt/autobean/super/com/google/gwt/autobean/shared/ValueCodexHelper.java
new file mode 100644
index 0000000..42c87e3
--- /dev/null
+++ b/user/super/com/google/gwt/autobean/super/com/google/gwt/autobean/shared/ValueCodexHelper.java
@@ -0,0 +1,28 @@
+/*
+ * 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.autobean.shared;
+
+/**
+ * A no-op super-source version of ValueCodexHelper for web-mode compilations.
+ */
+class ValueCodexHelper {
+ /**
+ * Returns {@code false}.
+ */
+ static boolean canDecode(Class<?> clazz) {
+ return false;
+ }
+}
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
index 85e1cb7..5d0cb95 100644
--- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
@@ -32,11 +32,16 @@
import com.google.gwt.requestfactory.shared.Violation;
import com.google.gwt.requestfactory.shared.impl.SimpleEntityProxyId;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Time;
+import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -1801,20 +1806,71 @@
});
}
+ public void testPrimitiveListBigDecimalAsParameter() {
+ delayTestFinish(DELAY_TEST_FINISH);
+
+ // Keep these values in sync with SimpleFoo.processBigIntegerList
+ final List<BigDecimal> testList = new ArrayList<BigDecimal>();
+ testList.add(BigDecimal.TEN);
+ testList.add(new BigDecimal("12345.6789") {
+ // This is an anonymous subtype
+ });
+ simpleFooRequest().processBigDecimalList(testList).fire(
+ new Receiver<List<BigDecimal>>() {
+ @Override
+ public void onSuccess(List<BigDecimal> response) {
+ // Check upcasted values only
+ assertEquals(testList, response);
+ finishTestAndReset();
+ }
+ });
+ }
+
+ public void testPrimitiveListBigIntegerAsParameter() {
+ delayTestFinish(DELAY_TEST_FINISH);
+
+ // Keep these values in sync with SimpleFoo.processBigIntegerList
+ final List<BigInteger> testList = new ArrayList<BigInteger>();
+ testList.add(BigInteger.TEN);
+ testList.add(new BigInteger("12345") {
+ // This is an anonymous subtype
+ });
+ simpleFooRequest().processBigIntegerList(testList).fire(
+ new Receiver<List<BigInteger>>() {
+ @Override
+ public void onSuccess(List<BigInteger> response) {
+ // Check upcasted values only
+ assertEquals(testList, response);
+ finishTestAndReset();
+ }
+ });
+ }
+
+ @SuppressWarnings("deprecation")
public void testPrimitiveListDateAsParameter() {
delayTestFinish(DELAY_TEST_FINISH);
- @SuppressWarnings("deprecation")
- final Date date = new Date(90, 0, 1);
- Request<Date> procReq = simpleFooRequest().processDateList(
- Arrays.asList(date));
- procReq.fire(new Receiver<Date>() {
- @Override
- public void onSuccess(Date response) {
- assertEquals(date, response);
- finishTestAndReset();
- }
- });
+ // Keep these values in sync with SimpleFoo.processDateList
+ Date date = new Date(90, 0, 1);
+ java.sql.Date sqlDate = new java.sql.Date(90, 0, 2);
+ Time sqlTime = new Time(1, 2, 3);
+ Timestamp sqlTimestamp = new Timestamp(12345L);
+ final List<Date> testList = Arrays.asList(date, sqlDate, sqlTime,
+ sqlTimestamp);
+ simpleFooRequest().processDateList(testList).fire(
+ new Receiver<List<Date>>() {
+ @Override
+ public void onSuccess(List<Date> response) {
+ // Check upcasted values only
+ assertEquals(testList.size(), response.size());
+ Iterator<Date> expected = testList.iterator();
+ Iterator<Date> actual = response.iterator();
+ while (expected.hasNext()) {
+ assertEquals(expected.next().getTime(), actual.next().getTime());
+ }
+ finishTestAndReset();
+ }
+ });
}
public void testPrimitiveListEnumAsParameter() {
diff --git a/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java b/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java
index f6640da..1c6c003 100644
--- a/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java
+++ b/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java
@@ -87,6 +87,10 @@
int foo(int a) {
return 0;
}
+
+ java.sql.Date getSqlDate() {
+ return null;
+ }
}
@ProxyFor(Domain.class)
@@ -111,11 +115,17 @@
return 0;
}
}
+
@ProxyFor(DomainWithOverloads.class)
interface DomainWithOverloadsProxy extends EntityProxy {
void foo();
}
+ @ProxyFor(Domain.class)
+ interface DomainWithSqlDateProxy extends EntityProxy {
+ java.sql.Date getSqlDate();
+ }
+
class Foo {
}
@@ -270,6 +280,14 @@
};
/**
+ * Test that subclasses of {@code java.util.Date} are not transportable.
+ */
+ public void testDateSubclass() {
+ v.validateEntityProxy(DomainWithSqlDateProxy.class.getName());
+ assertTrue(v.isPoisoned());
+ }
+
+ /**
* Test the {@link FindRequest} context used to implement find().
*/
public void testFindRequestContext() {
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
index 4a1bfb7..1ac5987 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
@@ -19,11 +19,14 @@
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.sql.Time;
+import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -157,12 +160,72 @@
return foo;
}
+ /**
+ * Check client-side upcasting to BigDecimal and return a list of BigDecimals
+ * that should be upcast.
+ */
+ public static List<BigDecimal> processBigDecimalList(List<BigDecimal> values) {
+ List<BigDecimal> toReturn = new ArrayList<BigDecimal>();
+ toReturn.add(BigDecimal.TEN);
+ toReturn.add(new BigDecimal("12345.6789") {
+ // This is an anonymous subtype
+ });
+ if (!toReturn.equals(values)) {
+ throw new IllegalArgumentException(toReturn + " != " + values);
+ }
+ return toReturn;
+ }
+
+ /**
+ * Check client-side upcasting to BigInteger and return a list of BigIntegers
+ * that should be upcast.
+ */
+ public static List<BigInteger> processBigIntegerList(List<BigInteger> values) {
+ List<BigInteger> toReturn = new ArrayList<BigInteger>();
+ toReturn.add(BigInteger.TEN);
+ toReturn.add(new BigInteger("12345") {
+ // This is an anonymous subtype
+ });
+ if (!toReturn.equals(values)) {
+ throw new IllegalArgumentException(toReturn + " != " + values);
+ }
+ return toReturn;
+ }
+
public static Boolean processBooleanList(List<Boolean> values) {
return values.get(0);
}
- public static Date processDateList(List<Date> values) {
- return values.get(0);
+ /**
+ * Check client-side upcasting to Date and return a list of Dates that should
+ * be upcast.
+ */
+ @SuppressWarnings("deprecation")
+ public static List<Date> processDateList(List<Date> values) {
+ // Keep these values in sync with SimpleFoo.processDateList
+ Date date = new Date(90, 0, 1);
+ java.sql.Date sqlDate = new java.sql.Date(90, 0, 2);
+ Time sqlTime = new Time(1, 2, 3);
+ Timestamp sqlTimestamp = new Timestamp(12345L);
+ List<Date> toReturn = Arrays.asList(date, sqlDate, sqlTime, sqlTimestamp);
+
+ if (toReturn.size() != values.size()) {
+ throw new IllegalArgumentException("size");
+ }
+
+ Iterator<Date> expected = toReturn.iterator();
+ Iterator<Date> actual = values.iterator();
+ while (expected.hasNext()) {
+ Date expectedDate = expected.next();
+ long expectedTime = expectedDate.getTime();
+ long actualTime = actual.next().getTime();
+ if (expectedTime != actualTime) {
+ throw new IllegalArgumentException(expectedDate.getClass().getName()
+ + " " + expectedTime + " != " + actualTime);
+ }
+ }
+
+ return toReturn;
}
public static SimpleEnum processEnumList(List<SimpleEnum> values) {
@@ -278,7 +341,7 @@
public static String returnNullString() {
return null;
}
-
+
public static SimpleFoo returnSimpleFooSubclass() {
return new SimpleFoo() {
};
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
index cd174be..bbb4c6b 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.requestfactory.shared;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.Set;
@@ -61,9 +63,13 @@
InstanceRequest<SimpleFooProxy, SimpleFooProxy> persistCascadingAndReturnSelf();
+ Request<List<BigInteger>> processBigIntegerList(List<BigInteger> values);
+
+ Request<List<BigDecimal>> processBigDecimalList(List<BigDecimal> values);
+
Request<Boolean> processBooleanList(List<Boolean> values);
- Request<Date> processDateList(List<Date> values);
+ Request<List<Date>> processDateList(List<Date> values);
Request<SimpleEnum> processEnumList(List<SimpleEnum> values);