Reviewers: bobv,

Description:
LinkedHashMap_CustomFieldSerializer currently uses reflection to access
a private field, which fails in AppEngine.  This patch provides a
(possibly slower) alternative approach that does not require reflection,
which is used as a fallback when reflection fails.


Please review this at http://gwt-code-reviews.appspot.com/54816

Affected files:
    
user/src/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java


Index:  
user/src/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java
===================================================================
---  
user/src/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java
  
(revision 5867)
+++  
user/src/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java
  
(working copy)
@@ -49,21 +49,68 @@
    }

    @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);
    }
+
+  /**
+   * 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 requires iterating over all of the keys in the instance, which  
could
+   * be slow.
+   *
+   * @param instance the instance to check
+   * @return the value of instance.accessOrder
+   */
+  @SuppressWarnings("unchecked") // raw LinkedHashMap
+  private static boolean getAccessOrderNoReflection(LinkedHashMap  
instance) {
+    /*
+     * 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;
+      }
+    }
+    // Clean up
+    instance.remove(key1);
+    instance.remove(key2);
+
+    return accessOrder;
+  }
  }



--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to