Title: [2358] branches/v-1.4.x: Merge solution for compiler dependent synthetic field names from trunk (XSTR-769).
Revision
2358
Author
joehni
Date
2015-02-24 12:40:47 -0600 (Tue, 24 Feb 2015)

Log Message

Merge solution for compiler dependent synthetic field names from trunk (XSTR-769).

Modified Paths

Property Changed

Diff

Property changes: branches/v-1.4.x


Modified: svn:mergeinfo

+ /trunk:2151-2152,2154-2156,2158-2163,2165,2172,2175,2177,2188-2189,2197,2199-2201,2204,2206,2210,2212,2214-2217,2226,2229,2231,2233-2234,2236-2238,2247-2249,2279-2280,2285,2291-2292,2294,2298-2299,2301,2303,2306-2310,2312,2314,2316-2318,2320,2322,2324,2326,2329,2333,2335,2339,2341,2353,2355,2357

Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/mapper/OuterClassMapper.java (2357 => 2358)


--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/mapper/OuterClassMapper.java	2015-02-24 01:17:13 UTC (rev 2357)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/mapper/OuterClassMapper.java	2015-02-24 18:40:47 UTC (rev 2358)
@@ -1,24 +1,34 @@
 /*
  * Copyright (C) 2005 Joe Walnes.
- * Copyright (C) 2006, 2007, 2009 XStream Committers.
+ * Copyright (C) 2006, 2007, 2009, 2015 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
  * style license a copy of which has been included with this distribution in
  * the LICENSE.txt file.
- * 
+ *
  * Created on 31. January 2005 by Joe Walnes
  */
 package com.thoughtworks.xstream.mapper;
 
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.thoughtworks.xstream.core.Caching;
+
+
 /**
  * Mapper that uses a more meaningful alias for the field in an inner class (this$0) that refers to the outer class.
  *
  * @author Joe Walnes
  */
-public class OuterClassMapper extends MapperWrapper {
+public class OuterClassMapper extends MapperWrapper implements Caching {
 
+    private static final String[] EMPTY_NAMES = new String[0];
     private final String alias;
+    private final Map innerFields;
 
     public OuterClassMapper(Mapper wrapped) {
         this(wrapped, "outer-class");
@@ -27,21 +37,61 @@
     public OuterClassMapper(Mapper wrapped, String alias) {
         super(wrapped);
         this.alias = alias;
+        innerFields = Collections.synchronizedMap(new HashMap());
+        innerFields.put(Object.class.getName(), EMPTY_NAMES);
     }
 
     public String serializedMember(Class type, String memberName) {
-        if (memberName.equals("this$0")) {
-            return alias;
-        } else {
-            return super.serializedMember(type, memberName);
+        if (memberName.startsWith("this$")) {
+            final String[] innerFieldNames = getInnerFieldNames(type);
+            for (int i = 0; i < innerFieldNames.length; ++i) {
+                if (innerFieldNames[i].equals(memberName)) {
+                    return i == 0 ? alias : alias + '-' + i;
+                }
+            }
         }
+        return super.serializedMember(type, memberName);
     }
 
     public String realMember(Class type, String serialized) {
-        if (serialized.equals(alias)) {
-            return "this$0";
-        } else {
-            return super.realMember(type, serialized);
+        if (serialized.startsWith(alias)) {
+            int idx = -1;
+            final int len = alias.length();
+            if (len == serialized.length()) {
+                idx = 0;
+            } else if (serialized.length() > len + 1 && serialized.charAt(len) == '-') {
+                idx = Integer.valueOf(serialized.substring(len + 1));
+            }
+            if (idx >= 0) {
+                final String[] innerFieldNames = getInnerFieldNames(type);
+                if (idx < innerFieldNames.length) {
+                    return innerFieldNames[idx];
+                }
+            }
         }
+        return super.realMember(type, serialized);
     }
+
+    private String[] getInnerFieldNames(final Class type) {
+        String[] innerFieldNames = (String[])innerFields.get(type.getName());
+        if (innerFieldNames == null) {
+            innerFieldNames = getInnerFieldNames(type.getSuperclass());
+            Field[] declaredFields = type.getDeclaredFields();
+            for (int i = 0; i < declaredFields.length; i++) {
+                final Field field = declaredFields[i];
+                if (field.getName().startsWith("this$")) {
+                    String[] temp = new String[innerFieldNames.length+1];
+                    System.arraycopy(innerFieldNames, 0, temp, 0, innerFieldNames.length);
+                    innerFieldNames = temp;
+                    innerFieldNames[innerFieldNames.length - 1] = field.getName();
+                }
+            }
+            innerFields.put(type.getName(), innerFieldNames);
+        }
+        return innerFieldNames;
+    }
+
+    public void flushCache() {
+        innerFields.keySet().retainAll(Collections.singletonList(Object.class.getName()));
+    }
 }

Modified: branches/v-1.4.x/xstream/src/test/com/thoughtworks/acceptance/InnerClassesTest.java (2357 => 2358)


--- branches/v-1.4.x/xstream/src/test/com/thoughtworks/acceptance/InnerClassesTest.java	2015-02-24 01:17:13 UTC (rev 2357)
+++ branches/v-1.4.x/xstream/src/test/com/thoughtworks/acceptance/InnerClassesTest.java	2015-02-24 18:40:47 UTC (rev 2358)
@@ -1,12 +1,12 @@
 /*
  * Copyright (C) 2005, 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2014 XStream Committers.
+ * Copyright (C) 2006, 2007, 2014, 2015 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
  * style license a copy of which has been included with this distribution in
  * the LICENSE.txt file.
- * 
+ *
  * Created on 31. January 2005 by Joe Walnes
  */
 package com.thoughtworks.acceptance;
@@ -16,14 +16,14 @@
     public void testSerializedInnerClassMaintainsReferenceToOuterClass() {
         xstream.allowTypes(new Class[]{Outer.class, Outer.Inner.class});
 
-        Outer outer = new Outer("THE-OUTER-NAME", "THE-INNER-NAME");
-        Outer.Inner inner = outer.getInner();
+        final Outer outer = new Outer("THE-OUTER-NAME", "THE-INNER-NAME");
+        final Outer.Inner inner = outer.getInner();
 
         assertEquals("Hello from THE-INNER-NAME (inside THE-OUTER-NAME)", inner.getMessage());
 
-        String xml = xstream.toXML(inner);
+        final String xml = xstream.toXML(inner);
 
-        String expectedXml = ""
+        final String expectedXml = ""
                 + "<com.thoughtworks.acceptance.Outer_-Inner>\n"
                 + "  <innerName>THE-INNER-NAME</innerName>\n"
                 + "  <outer-class>\n"
@@ -33,18 +33,99 @@
                 + "</com.thoughtworks.acceptance.Outer_-Inner>";
         assertEquals(expectedXml, xml);
 
-        Outer.Inner newInner = (Outer.Inner) xstream.fromXML(xml);
+        final Outer.Inner newInner = (Outer.Inner)xstream.fromXML(xml);
 
         assertEquals("Hello from THE-INNER-NAME (inside THE-OUTER-NAME)", newInner.getMessage());
     }
+
+    public static class OuterType {
+        private final String outerName = "Outer Name";
+        public InnerType inner = new InnerType();
+        private final InnerType.Dynamic1 dyn1 = inner.new Dynamic1();
+        private final InnerType.Dynamic1.Dynamic2 dyn2 = dyn1.new Dynamic2();
+        private final InnerType.Dynamic3 dyn3 = inner.new Dynamic3(dyn1);
+
+        public class InnerType {
+            private final String innerName = "Inner Name";
+
+            public class Dynamic1 {
+                private final String name1 = "Name 1";
+
+                public class Dynamic2 {
+                    private final String name2 = "Name 2";
+                }
+            }
+
+            public class Dynamic3 extends Dynamic1.Dynamic2 {
+                private final String name3 = "Name 3";
+                private final Dynamic1.Dynamic2 dyn4;
+
+                public Dynamic3(final Dynamic1 outer) {
+                    outer.super();
+                    class Dynamic4 extends Dynamic1.Dynamic2 {
+                        private final String name4 = "Name 4";
+                        private final Dynamic5 dyn5 = new Dynamic5();
+                        class Dynamic5 {
+                            private final String name5 = "Name 5";
+                        }
+                        Dynamic4(Dynamic1 outer) {
+                            outer.super();
+                        }
+                    }
+                    dyn4 = new Dynamic4(outer);
+                }
+            }
+        }
+    }
+
+    public void testNestedDynamicTypes() {
+        xstream.alias("inner", OuterType.InnerType.class);
+
+        final OuterType outer = new OuterType();
+
+        final String expectedXml = ""
+                + "<inner>\n"
+                + "  <innerName>Inner Name</innerName>\n"
+                + "  <outer-class>\n"
+                + "    <outerName>Outer Name</outerName>\n"
+                + "    <inner reference=\"../..\"/>\n"
+                + "    <dyn1>\n"
+                + "      <name1>Name 1</name1>\n"
+                + "      <outer-class reference=\"../../..\"/>\n"
+                + "    </dyn1>\n"
+                + "    <dyn2>\n"
+                + "      <name2>Name 2</name2>\n"
+                + "      <outer-class reference=\"../../dyn1\"/>\n"
+                + "    </dyn2>\n"
+                + "    <dyn3>\n"
+                + "      <name2>Name 2</name2>\n"
+                + "      <outer-class reference=\"../../dyn1\"/>\n"
+                + "      <name3>Name 3</name3>\n"
+                + "      <dyn4 class=\"com.thoughtworks.acceptance.InnerClassesTest$OuterType$InnerType$Dynamic3$1Dynamic4\">\n"
+                + "        <name2>Name 2</name2>\n"
+                + "        <outer-class defined-in=\"com.thoughtworks.acceptance.InnerClassesTest$OuterType$InnerType$Dynamic1$Dynamic2\" reference=\"../../../dyn1\"/>\n"
+                + "        <name4>Name 4</name4>\n"
+                + "        <dyn5>\n"
+                + "          <name5>Name 5</name5>\n"
+                + "          <outer-class reference=\"../..\"/>\n"
+                + "        </dyn5>\n"
+                + "        <outer-class reference=\"../..\"/>\n"
+                + "      </dyn4>\n"
+                + "      <outer-class-1 reference=\"../../..\"/>\n"
+                + "    </dyn3>\n"
+                + "  </outer-class>\n"
+                + "</inner>";
+
+        assertBothWays(outer.inner, expectedXml);
+    }
 }
 
 class Outer {
 
-    private Inner inner;
-    private String outerName;
+    private final Inner inner;
+    private final String outerName;
 
-    public Outer(String outerName, String innerName) {
+    public Outer(final String outerName, final String innerName) {
         inner = new Inner(innerName);
         this.outerName = outerName;
     }
@@ -54,9 +135,9 @@
     }
 
     public class Inner {
-        private String innerName;
+        private final String innerName;
 
-        public Inner(String innerName) {
+        public Inner(final String innerName) {
             this.innerName = innerName;
         }
 
@@ -65,5 +146,3 @@
         }
     }
 }
-
-

Modified: branches/v-1.4.x/xstream-distribution/src/content/changes.html (2357 => 2358)


--- branches/v-1.4.x/xstream-distribution/src/content/changes.html	2015-02-24 01:17:13 UTC (rev 2357)
+++ branches/v-1.4.x/xstream-distribution/src/content/changes.html	2015-02-24 18:40:47 UTC (rev 2358)
@@ -35,6 +35,7 @@
     <h2>Minor changes</h2>
 
     <ul>
+    	<li>JIRA:XSTR-769: Synthetic fields with references to outer class use compiler dependent names.</li>
     	<li>UUID is an immutable type by default.</li>
     </ul>
 

To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to