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)) {