Re-introduces c5957, because the build succeeded with it. git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5963 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java index 250f4fb..cfa4728 100644 --- a/user/src/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java +++ b/user/src/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java
@@ -34,6 +34,54 @@ Map_CustomFieldSerializerBase.deserialize(streamReader, instance); } + /** + * Infers the value of the private accessOrder field of instance by examining + * its behavior on a set of test inputs, without using reflection. Note that + * this implementation clones the instance, which could be slow. + * + * @param instance the instance to check + * @return the value of instance.accessOrder + */ + @SuppressWarnings("unchecked") // raw LinkedHashMap + public static boolean getAccessOrderNoReflection(LinkedHashMap instance) { + /* + * Clone the instance so our modifications won't affect the original. + * In particular, if the original overrides removeEldestEntry, adding + * elements to the map could cause existing elements to be removed. + */ + instance = (LinkedHashMap) instance.clone(); + instance.clear(); + + /* + * We insert key1, then key2, after which we access key1. We then iterate + * over the key set and observe the order in which keys are returned. The + * iterator will return keys in the order of least recent insertion or + * access, depending on the value of the accessOrder field within the + * LinkedHashMap instance. If the iterator is ordered by least recent + * insertion (accessOrder = false), we will encounter key1 first since key2 + * has been inserted more recently. If it is ordered by least recent access + * (accessOrder = true), we will encounter key2 first, since key1 has been + * accessed more recently. + */ + Object key1 = new Object(); + Object key2 = new Object(); + instance.put(key1, key1); // INSERT key1 + instance.put(key2, key2); // INSERT key2 + instance.get(key1); // ACCESS key1 + boolean accessOrder = false; + for (Object key : instance.keySet()) { + if (key == key1) { + break; + } + if (key == key2) { + accessOrder = true; + break; + } + } + + return accessOrder; + } + @SuppressWarnings("unchecked") // raw LinkedHashMap public static LinkedHashMap instantiate(SerializationStreamReader streamReader) throws SerializationException { @@ -49,21 +97,23 @@ } @SuppressWarnings("unchecked") // raw LinkedHashMap - private static boolean getAccessOrder(LinkedHashMap instance) - throws SerializationException { + private static boolean getAccessOrder(LinkedHashMap instance) { Field accessOrderField; try { accessOrderField = LinkedHashMap.class.getDeclaredField("accessOrder"); accessOrderField.setAccessible(true); return ((Boolean) accessOrderField.get(instance)).booleanValue(); } catch (SecurityException e) { - throw new SerializationException("Can't get accessOrder field", e); + // fall through } catch (NoSuchFieldException e) { - throw new SerializationException("Can't get accessOrder field", e); + // fall through } catch (IllegalArgumentException e) { - throw new SerializationException("Can't get accessOrder field", e); + // fall through } catch (IllegalAccessException e) { - throw new SerializationException("Can't get accessOrder field", e); + // fall through } + + // Use a (possibly slower) technique that does not require reflection. + return getAccessOrderNoReflection(instance); } }
diff --git a/user/super/com/google/gwt/user/translatable/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java b/user/super/com/google/gwt/user/translatable/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java index 1129ce4..eee075b 100644 --- a/user/super/com/google/gwt/user/translatable/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java +++ b/user/super/com/google/gwt/user/translatable/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java
@@ -31,6 +31,12 @@ LinkedHashMap instance) throws SerializationException { Map_CustomFieldSerializerBase.deserialize(streamReader, instance); } + + @SuppressWarnings("unchecked") // raw LinkedHashMap + // Included for testability + public static boolean getAccessOrderNoReflection(LinkedHashMap instance) { + return getAccessOrder(instance); + } public static LinkedHashMap instantiate(SerializationStreamReader streamReader) throws SerializationException { @@ -44,6 +50,7 @@ Map_CustomFieldSerializerBase.serialize(streamWriter, instance); } + @SuppressWarnings("unchecked") // raw LinkedHashMap private static native boolean getAccessOrder(LinkedHashMap instance) /*-{ return instance.@java.util.LinkedHashMap::accessOrder; }-*/;
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 6513cb2..6cfb9e5 100644 --- a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java +++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
@@ -25,6 +25,7 @@ import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap; import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet; import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector; +import com.google.gwt.user.client.rpc.core.java.util.LinkedHashMap_CustomFieldSerializer; import java.sql.Time; import java.sql.Timestamp; @@ -304,6 +305,7 @@ CollectionsTestServiceAsync service = getServiceAsync(); final LinkedHashMap<String, MarkerTypeLinkedHashMap> expected = TestSetFactory.createLinkedHashMap(); + assertFalse(LinkedHashMap_CustomFieldSerializer.getAccessOrderNoReflection(expected)); service.echo(expected, new AsyncCallback<LinkedHashMap<String, MarkerTypeLinkedHashMap>>() { @@ -327,6 +329,7 @@ CollectionsTestServiceAsync service = getServiceAsync(); final LinkedHashMap<String, MarkerTypeLinkedHashMap> expected = TestSetFactory.createLRULinkedHashMap(); + assertTrue(LinkedHashMap_CustomFieldSerializer.getAccessOrderNoReflection(expected)); service.echo(expected, new AsyncCallback<LinkedHashMap<String, MarkerTypeLinkedHashMap>>() {