Custom Field Serializer for EnumMap
Contributed by: bradley
Fixes Issue 1634804
Review at http://codereview.appspot.com/6174044/
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@11050 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/util/EnumMap_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/util/EnumMap_CustomFieldSerializer.java
new file mode 100644
index 0000000..b25b509
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/util/EnumMap_CustomFieldSerializer.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2012 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.user.client.rpc.core.java.util;
+
+import com.google.gwt.user.client.rpc.CustomFieldSerializer;
+import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamReader;
+import com.google.gwt.user.client.rpc.SerializationStreamWriter;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.util.EnumMap;
+
+/**
+ * The super source version is used in web mode. This is only called in hosted mode.
+ * Custom field serializer for {@link java.util.EnumMap}.
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public final class EnumMap_CustomFieldSerializer extends CustomFieldSerializer<EnumMap> {
+
+ public static void deserialize(SerializationStreamReader streamReader, EnumMap instance)
+ throws SerializationException {
+ Map_CustomFieldSerializerBase.deserialize(streamReader, instance);
+ }
+
+ /**
+ * EnumMap has no empty constructor; you must provide the class literal to the constructor.
+ * However GWT doesn't emulate java.lang.Class.forName() nor is java.util.Class GWT-RPC
+ * serializable. In order to get the type across the wire, one enum of the appropriate class is
+ * serialized at the beginning of the stream. Upon deserialization this enum's type is
+ * introspected and used in the constructor for the new EnumMap.
+ */
+ public static EnumMap instantiate(SerializationStreamReader streamReader)
+ throws SerializationException {
+ Object exemplar = streamReader.readObject();
+ Class clazz = exemplar.getClass();
+ return new EnumMap(clazz);
+ }
+
+ /**
+ * Since this code is only run in hosted mode, reflection can be used.
+ */
+ public static void serialize(SerializationStreamWriter streamWriter, EnumMap instance)
+ throws SerializationException {
+ Class c = instance.getClass();
+ Field keyUniverseField;
+ Object keyUniverse = null;
+
+ try {
+ keyUniverseField = c.getDeclaredField("keyUniverse");
+ keyUniverseField.setAccessible(true);
+ keyUniverse = keyUniverseField.get(instance);
+ } catch (IllegalArgumentException e) {
+ throw new SerializationException(e);
+ } catch (IllegalAccessException e) {
+ throw new SerializationException(e);
+ } catch (SecurityException e) {
+ throw new SerializationException(e);
+ } catch (NoSuchFieldException e) {
+ throw new SerializationException(e);
+ }
+ Object exemplar = Array.get(keyUniverse, 0);
+ streamWriter.writeObject(exemplar);
+ Map_CustomFieldSerializerBase.serialize(streamWriter, instance);
+ }
+
+ @Override
+ public void deserializeInstance(SerializationStreamReader streamReader, EnumMap instance)
+ throws SerializationException {
+ deserialize(streamReader, instance);
+ }
+
+ @Override
+ public boolean hasCustomInstantiateInstance() {
+ return true;
+ }
+
+ @Override
+ public EnumMap instantiateInstance(SerializationStreamReader streamReader)
+ throws SerializationException {
+ return instantiate(streamReader);
+ }
+
+ @Override
+ public void serializeInstance(SerializationStreamWriter streamWriter, EnumMap instance)
+ throws SerializationException {
+ serialize(streamWriter, instance);
+ }
+}
diff --git a/user/src/com/google/gwt/user/server/rpc/core/java/util/EnumMap_ServerCustomFieldSerializer.java b/user/src/com/google/gwt/user/server/rpc/core/java/util/EnumMap_ServerCustomFieldSerializer.java
new file mode 100644
index 0000000..dfe6b2d
--- /dev/null
+++ b/user/src/com/google/gwt/user/server/rpc/core/java/util/EnumMap_ServerCustomFieldSerializer.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2012 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.user.server.rpc.core.java.util;
+
+import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamReader;
+import com.google.gwt.user.client.rpc.SerializationStreamWriter;
+import com.google.gwt.user.client.rpc.core.java.util.EnumMap_CustomFieldSerializer;
+import com.google.gwt.user.client.rpc.core.java.util.Map_CustomFieldSerializerBase;
+import com.google.gwt.user.server.rpc.ServerCustomFieldSerializer;
+import com.google.gwt.user.server.rpc.impl.DequeMap;
+import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.EnumMap;
+
+/**
+ * Custom field serializer for {@link java.util.EnumMap} for the server.
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public final class EnumMap_ServerCustomFieldSerializer extends ServerCustomFieldSerializer<EnumMap>
+{
+
+ public static void deserialize(ServerSerializationStreamReader streamReader, EnumMap instance,
+ Type[] expectedParameterTypes, DequeMap<TypeVariable< ? >, Type> resolvedTypes)
+ throws SerializationException {
+ Map_ServerCustomFieldSerializerBase.deserialize(streamReader, instance,
+ expectedParameterTypes, resolvedTypes);
+ }
+
+ @Override
+ public void deserializeInstance(SerializationStreamReader streamReader, EnumMap instance)
+ throws SerializationException {
+ EnumMap_CustomFieldSerializer.deserialize(streamReader, instance);
+ }
+
+ @Override
+ public void deserializeInstance(ServerSerializationStreamReader streamReader, EnumMap instance,
+ Type[] expectedParameterTypes, DequeMap<TypeVariable< ? >, Type> resolvedTypes)
+ throws SerializationException {
+ deserialize(streamReader, instance, expectedParameterTypes, resolvedTypes);
+ }
+
+ @Override
+ public boolean hasCustomInstantiateInstance() {
+ return true;
+ }
+
+ @Override
+ public EnumMap instantiateInstance(SerializationStreamReader streamReader)
+ throws SerializationException {
+ return EnumMap_CustomFieldSerializer.instantiate(streamReader);
+ }
+
+ @Override
+ public EnumMap instantiateInstance(ServerSerializationStreamReader streamReader,
+ Type[] expectedParameterTypes, DequeMap<TypeVariable< ? >, Type> resolvedTypes)
+ throws SerializationException {
+ return EnumMap_CustomFieldSerializer.instantiate(streamReader);
+ }
+
+ @Override
+ public void serializeInstance(SerializationStreamWriter streamWriter, EnumMap instance)
+ throws SerializationException {
+ Class c = instance.getClass();
+ Field keyUniverseField;
+ Object keyUniverse = null;
+ try {
+ keyUniverseField = c.getDeclaredField("keyUniverse");
+ keyUniverseField.setAccessible(true);
+ keyUniverse = keyUniverseField.get(instance);
+ } catch (Exception e) {
+ throw new SerializationException(e);
+ }
+ Object exemplar = Array.get(keyUniverse, 0);
+ streamWriter.writeObject(exemplar);
+ Map_CustomFieldSerializerBase.serialize(streamWriter, instance);
+ }
+}
diff --git a/user/super/com/google/gwt/user/translatable/com/google/gwt/user/client/rpc/core/java/util/EnumMap_CustomFieldSerializer.java b/user/super/com/google/gwt/user/translatable/com/google/gwt/user/client/rpc/core/java/util/EnumMap_CustomFieldSerializer.java
new file mode 100644
index 0000000..9324037
--- /dev/null
+++ b/user/super/com/google/gwt/user/translatable/com/google/gwt/user/client/rpc/core/java/util/EnumMap_CustomFieldSerializer.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012 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.user.client.rpc.core.java.util;
+
+import com.google.gwt.core.client.GwtScriptOnly;
+import com.google.gwt.user.client.rpc.CustomFieldSerializer;
+import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamReader;
+import com.google.gwt.user.client.rpc.SerializationStreamWriter;
+
+import java.util.EnumMap;
+import java.util.EnumSet;
+
+/**
+ * Custom field serializer for {@link java.util.EnumMap}.
+ */
+@GwtScriptOnly
+@SuppressWarnings({"unchecked", "rawtypes"})
+public final class EnumMap_CustomFieldSerializer extends CustomFieldSerializer<EnumMap> {
+
+ public static void deserialize(SerializationStreamReader streamReader, EnumMap instance)
+ throws SerializationException {
+ Map_CustomFieldSerializerBase.deserialize(streamReader, instance);
+ }
+
+ /**
+ * EnumMap has no empty constructor; you must provide the class literal to the constructor.
+ * However GWT doesn't emulate java.lang.Class.forName() nor is java.util.Class GWT-RPC
+ * serializable. In order to get the type across the wire, one enum of the appropriate class is
+ * serialized at the beginning of the stream. Upon deserialization this enum's type is
+ * introspected and used in the constructor for the new EnumMap.
+ */
+ public static EnumMap instantiate(SerializationStreamReader streamReader)
+ throws SerializationException {
+ Object exemplar = streamReader.readObject();
+ Class clazz = exemplar.getClass();
+ return new EnumMap(clazz);
+ }
+
+ public static native <E> E[] getKeyUniverse(EnumMap<?, ?> map) /*-{
+ return map.@java.util.EnumMap::keySet.@java.util.EnumSet$EnumSetImpl::all;
+ }-*/;
+
+ /**
+ * A jsni method is used to access the private keySet field of the EnumMap instance.
+ * This EnumSet field is filled with the universe of allowed enums even if the instance is empty.
+ * The first enum is pulled from the set and serialized to the stream in order to allow the other
+ * side to instantiate the correct type of EnumMap.
+ */
+ public static void serialize(SerializationStreamWriter streamWriter, EnumMap instance)
+ throws SerializationException {
+ Object exemplar;
+ Object [] keyUniverse = getKeyUniverse(instance);
+ exemplar = keyUniverse[0];
+ streamWriter.writeObject(exemplar);
+ Map_CustomFieldSerializerBase.serialize(streamWriter, instance);
+ }
+
+ @Override
+ public void deserializeInstance(SerializationStreamReader streamReader, EnumMap instance)
+ throws SerializationException {
+ deserialize(streamReader, instance);
+ }
+
+ @Override
+ public boolean hasCustomInstantiateInstance() {
+ return true;
+ }
+
+ @Override
+ public EnumMap instantiateInstance(SerializationStreamReader streamReader)
+ throws SerializationException {
+ return instantiate(streamReader);
+ }
+
+ @Override
+ public void serializeInstance(SerializationStreamWriter streamWriter, EnumMap instance)
+ throws SerializationException {
+ serialize(streamWriter, instance);
+ }
+}
\ No newline at end of file
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
index b01ed5e..220efe0 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
@@ -23,9 +23,10 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptySet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnumMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapKey;
-import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapKey;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapKey;
@@ -42,8 +43,9 @@
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
-import java.util.HashMap;
+import java.util.EnumMap;
import java.util.HashSet;
+import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -247,6 +249,25 @@
});
}
+ public void testEmptyEnumMap() {
+ CollectionsTestServiceAsync service = getServiceAsync();
+ final EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> expected =
+ TestSetFactory.createEmptyEnumMap();
+ delayTestFinishForRpc();
+ service.echoEmptyEnumMap(expected, new AsyncCallback<EnumMap<MarkerTypeEnum,
+ MarkerTypeEnumMapValue>>() {
+ public void onFailure(Throwable caught) {
+ TestSetValidator.rethrowException(caught);
+ }
+
+ public void onSuccess(EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> result) {
+ assertNotNull(result);
+ assertTrue(TestSetValidator.isValid(expected, result));
+ finishTest();
+ }
+ });
+ }
+
public void testEmptyList() {
CollectionsTestServiceAsync service = getServiceAsync();
delayTestFinishForRpc();
@@ -320,6 +341,44 @@
});
}
+ public void testEnumMapEnumKey() {
+ CollectionsTestServiceAsync service = getServiceAsync();
+ final EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> expected =
+ TestSetFactory.createEnumMapEnumKey();
+ delayTestFinishForRpc();
+ service.echoEnumKey(expected,
+ new AsyncCallback<EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue>>() {
+ public void onFailure(Throwable caught) {
+ TestSetValidator.rethrowException(caught);
+ }
+
+ public void onSuccess(EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> result) {
+ assertNotNull(result);
+ assertTrue(TestSetValidator.isValidEnumKey(expected, result));
+ finishTest();
+ }
+ });
+ }
+
+ public void testEnumMap() {
+ CollectionsTestServiceAsync service = getServiceAsync();
+ final EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> expected =
+ TestSetFactory.createEnumMap();
+ delayTestFinishForRpc();
+ service.echo(expected,
+ new AsyncCallback<EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue>>() {
+ public void onFailure(Throwable caught) {
+ TestSetValidator.rethrowException(caught);
+ }
+
+ public void onSuccess(EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> result) {
+ assertNotNull(result);
+ assertTrue(TestSetValidator.isValid(expected, result));
+ finishTest();
+ }
+ });
+ }
+
public void testFloatArray() {
CollectionsTestServiceAsync service = getServiceAsync();
final Float[] expected = TestSetFactory.createFloatArray();
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
index a82b60b..6e70c33 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
@@ -22,9 +22,10 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptySet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnumMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapKey;
-import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapKey;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapKey;
@@ -40,8 +41,9 @@
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
-import java.util.HashMap;
+import java.util.EnumMap;
import java.util.HashSet;
+import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -110,6 +112,10 @@
Float[] echo(Float[] value) throws CollectionsTestServiceException;
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> echo(
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> value)
+ throws CollectionsTestServiceException;
+
HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> echo(
HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> value)
throws CollectionsTestServiceException;
@@ -171,7 +177,15 @@
List<MarkerTypeArraysAsList> echoArraysAsList(
List<MarkerTypeArraysAsList> value)
throws CollectionsTestServiceException;
+
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> echoEmptyEnumMap(
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> value)
+ throws CollectionsTestServiceException;
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> echoEnumKey(
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> value)
+ throws CollectionsTestServiceException;
+
IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> echoEnumKey(
IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> value)
throws CollectionsTestServiceException;
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
index 226d03f..599c8d0 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
@@ -21,8 +21,9 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyList;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptySet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyValue;
-import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapKey;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnumMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapKey;
@@ -40,6 +41,7 @@
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
@@ -96,6 +98,9 @@
void echo(Float[] value, AsyncCallback<Float[]> callback);
+ void echo(EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> value,
+ AsyncCallback<EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue>> callback);
+
void echo(HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> value,
AsyncCallback<HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue>> callback);
@@ -151,6 +156,12 @@
void echoArraysAsList(List<MarkerTypeArraysAsList> value,
AsyncCallback<List<MarkerTypeArraysAsList>> callback);
+ void echoEmptyEnumMap(EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> expected,
+ AsyncCallback<EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue>> asyncCallback);
+
+ void echoEnumKey(EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> value,
+ AsyncCallback<EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue>> callback);
+
void echoEnumKey(IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> value,
AsyncCallback<IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue>> callback);
diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
index cae6954..6e98e2f 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
@@ -24,6 +24,7 @@
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
@@ -153,6 +154,21 @@
public static enum MarkerTypeEnum {
A, B, C;
}
+
+ /**
+ * A single-use marker type to independently check type parameter exposure in
+ * various collections.
+ */
+ public static final class MarkerTypeEnumMapValue extends MarkerBase {
+
+ public MarkerTypeEnumMapValue(String value) {
+ super(value);
+ }
+
+ MarkerTypeEnumMapValue() {
+ super(null);
+ }
+ }
/**
* A single-use marker type to independently check type parameter exposure in
@@ -556,7 +572,37 @@
new Float(Float.MIN_VALUE)};
}
+ public static EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> createEmptyEnumMap() {
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> map =
+ new EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue>(MarkerTypeEnum.class);
+ return map;
+ }
+
+ public static EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> createEnumMap() {
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> map =
+ new EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue>(MarkerTypeEnum.class);
+ map.put(MarkerTypeEnum.A, new MarkerTypeEnumMapValue("A"));
+ map.put(MarkerTypeEnum.B, new MarkerTypeEnumMapValue("B"));
+ map.put(MarkerTypeEnum.C, new MarkerTypeEnumMapValue("C"));
+ return map;
+ }
+
+ public static EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue>
+ createEnumMapEnumKey() {
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> map =
+ new EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue>(MarkerTypeEnum.class);
+ /*
+ * An EnumMap lets us check that references to Enums remain constant
+ * across RPC send-receive cycles.
+ */
+ map.put(MarkerTypeEnum.A, new MarkerTypeEnumMapValue("A"));
+ map.put(MarkerTypeEnum.B, new MarkerTypeEnumMapValue("B"));
+ map.put(MarkerTypeEnum.C, new MarkerTypeEnumMapValue("C"));
+ return map;
+ }
+
public static HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> createHashMap() {
+
HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> map =
new HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue>();
map.put(new MarkerTypeHashMapKey("foo"), new MarkerTypeHashMapValue("foo"));
diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
index 5c68518..f5601b0 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
@@ -21,6 +21,7 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptySet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnumMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapKey;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
@@ -40,6 +41,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.EnumMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -326,6 +328,60 @@
return set != null && set.size() == 0;
}
+ public static boolean isValidEnumKey(
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> expected,
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> map) {
+ if (map == null) {
+ return false;
+ }
+
+ Set<?> entries = expected.entrySet();
+ Iterator<?> entryIter = entries.iterator();
+ while (entryIter.hasNext()) {
+ Entry<?, ?> entry = (Entry<?, ?>) entryIter.next();
+
+ Object value = map.get(entry.getKey());
+
+ if (value != entry.getValue()) {
+ if (value == null || entry.getValue() == null) {
+ return false;
+ }
+
+ if (!map.get(entry.getKey()).equals(entry.getValue())) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean isValid(EnumMap<?, ?> expected, EnumMap<?, ?> map) {
+ if (map == null) {
+ return false;
+ }
+
+ Set<?> entries = expected.entrySet();
+ Iterator<?> entryIter = entries.iterator();
+ while (entryIter.hasNext()) {
+ Entry<?, ?> entry = (Entry<?, ?>) entryIter.next();
+
+ Object value = map.get(entry.getKey());
+
+ if (value != entry.getValue()) {
+ if (value == null || entry.getValue() == null) {
+ return false;
+ }
+
+ if (!map.get(entry.getKey()).equals(entry.getValue())) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
public static boolean isValid(HashMap<?, ?> expected, HashMap<?, ?> map) {
if (map == null) {
return false;
diff --git a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
index 3a7e2b6..cb07bd8 100644
--- a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
@@ -24,9 +24,10 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeArrayList;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeArraysAsList;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnum;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEnumMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapKey;
-import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapKey;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeIdentityHashMapValue;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMapKey;
@@ -44,6 +45,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
@@ -190,6 +192,18 @@
return actual;
}
+ public EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> echo(
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> actual)
+ throws CollectionsTestServiceException {
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> expected = TestSetFactory.createEnumMap();
+ if (!TestSetValidator.isValid(expected, actual)) {
+ throw new CollectionsTestServiceException("expected: "
+ + expected.toString() + " actual: " + actual.toString());
+ }
+
+ return actual;
+ }
+
public Float[] echo(Float[] actual) throws CollectionsTestServiceException {
Float[] expected = TestSetFactory.createFloatArray();
if (!TestSetValidator.equals(expected, actual)) {
@@ -464,6 +478,18 @@
return value;
}
+ public EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> echoEmptyEnumMap(
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> actual)
+ throws CollectionsTestServiceException {
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> expected = TestSetFactory.createEmptyEnumMap();
+ if (!TestSetValidator.isValid(expected, actual)) {
+ throw new CollectionsTestServiceException("expected: "
+ + expected.toString() + " actual: " + actual.toString());
+ }
+
+ return actual;
+ }
+
public IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> echoEnumKey(
IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> actual)
throws CollectionsTestServiceException {
@@ -476,6 +502,19 @@
return actual;
}
+ public EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> echoEnumKey(
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> actual)
+ throws CollectionsTestServiceException {
+ EnumMap<MarkerTypeEnum, MarkerTypeEnumMapValue> expected =
+ TestSetFactory.createEnumMapEnumKey();
+ if (!TestSetValidator.isValidEnumKey(expected, actual)) {
+ throw new CollectionsTestServiceException("expected: "
+ + expected.toString() + " actual: " + actual.toString());
+ }
+
+ return actual;
+ }
+
public List<MarkerTypeSingleton> echoSingletonList(
List<MarkerTypeSingleton> value) throws CollectionsTestServiceException {
if (!TestSetValidator.isValidSingletonList(value)) {