Title: [1963] trunk: Inheritance of implicit collections, arrays or maps is dependent on declaration sequence (XSTR-683).
Revision
1963
Author
joehni
Date
2012-03-19 16:40:30 -0500 (Mon, 19 Mar 2012)

Log Message

Inheritance of implicit collections, arrays or maps is dependent on declaration sequence (XSTR-683).
Inherited implicit collections, arrays or maps can be overwritten with own definition in subtype.

Modified Paths

Diff

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/mapper/ImplicitCollectionMapper.java (1962 => 1963)


--- trunk/xstream/src/java/com/thoughtworks/xstream/mapper/ImplicitCollectionMapper.java	2012-03-08 23:54:40 UTC (rev 1962)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/mapper/ImplicitCollectionMapper.java	2012-03-19 21:40:30 UTC (rev 1963)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2005 Joe Walnes.
- * Copyright (C) 2006, 2007, 2009, 2011 XStream Committers.
+ * Copyright (C) 2006, 2007, 2009, 2011, 2012 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -43,9 +43,10 @@
     }
 
     private ImplicitCollectionMapperForClass getOrCreateMapper(Class definedIn) {
-        ImplicitCollectionMapperForClass mapper = getMapper(definedIn);
+        ImplicitCollectionMapperForClass mapper = (ImplicitCollectionMapperForClass)classNameToMapper
+            .get(definedIn);
         if (mapper == null) {
-            mapper = new ImplicitCollectionMapperForClass();
+            mapper = new ImplicitCollectionMapperForClass(definedIn);
             classNameToMapper.put(definedIn, mapper);
         }
         return mapper;
@@ -90,15 +91,16 @@
 
     public void add(Class definedIn, String fieldName, String itemFieldName, Class itemType, String keyFieldName) {
         Field field = null;
-        while (definedIn != Object.class) {
+        Class declaredIn = definedIn;
+        while (declaredIn != Object.class) {
             try {
-                field = definedIn.getDeclaredField(fieldName);
+                field = declaredIn.getDeclaredField(fieldName);
                 break;
             } catch (SecurityException e) {
                 throw new InitializationException(
                     "Access denied for field with implicit collection", e);
             } catch (NoSuchFieldException e) {
-                definedIn = definedIn.getSuperclass();
+                declaredIn = declaredIn.getSuperclass();
             }
         }
         if (field == null) {
@@ -135,7 +137,8 @@
         mapper.add(new ImplicitCollectionMappingImpl(fieldName, itemType, itemFieldName, keyFieldName));
     }
 
-    private static class ImplicitCollectionMapperForClass {
+    private class ImplicitCollectionMapperForClass {
+        private Class definedIn;
         // { (NamedItemType) -> (ImplicitCollectionDefImpl) }
         private Map namedItemTypeToDef = new HashMap();
         // { itemFieldName (String) -> (ImplicitCollectionDefImpl) }
@@ -143,6 +146,10 @@
         // { fieldName (String) -> (ImplicitCollectionDefImpl) }
         private Map fieldNameToDef = new HashMap();
 
+        ImplicitCollectionMapperForClass(Class definedIn) {
+            this.definedIn = definedIn;
+        }
+
         public String getFieldNameForItemTypeAndName(Class itemType, String itemFieldName) {
             ImplicitCollectionMappingImpl unnamed = null;
             for (Iterator iterator = namedItemTypeToDef.keySet().iterator(); iterator.hasNext();) {
@@ -165,7 +172,12 @@
                     }
                 }
             }
-            return unnamed != null ? unnamed.getFieldName() : null;
+            if (unnamed != null) {
+                return unnamed.getFieldName();
+            } else {
+                ImplicitCollectionMapperForClass mapper = ImplicitCollectionMapper.this.getMapper(definedIn.getSuperclass());
+                return mapper != null ? mapper.getFieldNameForItemTypeAndName(itemType, itemFieldName) : null;
+            }
         }
 
         public Class getItemTypeForItemFieldName(String itemFieldName) {
@@ -173,7 +185,8 @@
             if (def != null) {
                 return def.getItemType();
             } else {
-                return null;
+                ImplicitCollectionMapperForClass mapper = ImplicitCollectionMapper.this.getMapper(definedIn.getSuperclass());
+                return mapper != null ? mapper.getItemTypeForItemFieldName(itemFieldName) : null;
             }
         }
 
@@ -182,12 +195,24 @@
             if (itemFieldName == null) {
                 return null;
             } else {
-                return (ImplicitCollectionMappingImpl)itemFieldNameToDef.get(itemFieldName);
+                ImplicitCollectionMappingImpl mapping = (ImplicitCollectionMappingImpl)itemFieldNameToDef.get(itemFieldName);
+                if (mapping != null) {
+                    return mapping;
+                } else {
+                    ImplicitCollectionMapperForClass mapper = ImplicitCollectionMapper.this.getMapper(definedIn.getSuperclass());
+                    return mapper != null ? mapper.getImplicitCollectionDefByItemFieldName(itemFieldName) : null;
+                }
             }
         }
 
         public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(String fieldName) {
-            return (ImplicitCollectionMapping)fieldNameToDef.get(fieldName);
+            ImplicitCollectionMapping mapping = (ImplicitCollectionMapping)fieldNameToDef.get(fieldName);
+            if (mapping != null) {
+                return mapping;
+            } else {
+                ImplicitCollectionMapperForClass mapper = ImplicitCollectionMapper.this.getMapper(definedIn.getSuperclass());
+                return mapper != null ? mapper.getImplicitCollectionDefForFieldName(fieldName) : null;
+            }
         }
 
         public void add(ImplicitCollectionMappingImpl def) {
@@ -213,36 +238,10 @@
             this.keyFieldName = keyFieldName;
         }
 
-        public boolean equals(Object obj) {
-            if (obj instanceof ImplicitCollectionMappingImpl) {
-                ImplicitCollectionMappingImpl b = (ImplicitCollectionMappingImpl)obj;
-                return fieldName.equals(b.fieldName)
-                    && isEquals(itemFieldName, b.itemFieldName);
-            } else {
-                return false;
-            }
-        }
-
         public NamedItemType createNamedItemType() {
             return new NamedItemType(itemType, itemFieldName);
         }
 
-        private static boolean isEquals(Object a, Object b) {
-            if (a == null) {
-                return b == null;
-            } else {
-                return a.equals(b);
-            }
-        }
-
-        public int hashCode() {
-            int hash = fieldName.hashCode();
-            if (itemFieldName != null) {
-                hash += itemFieldName.hashCode() << 7;
-            }
-            return hash;
-        }
-
         public String getFieldName() {
             return fieldName;
         }

Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitArrayTest.java (1962 => 1963)


--- trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitArrayTest.java	2012-03-08 23:54:40 UTC (rev 1962)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitArrayTest.java	2012-03-19 21:40:30 UTC (rev 1963)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 XStream Committers.
+ * Copyright (C) 2011, 2012 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -10,6 +10,7 @@
  */
 package com.thoughtworks.acceptance;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -119,6 +120,34 @@
         assertBothWays(farm, expected);
     }
 
+    public void testInheritedAndDirectDeclaredImplicitArraysAtOnceIsNotDeclarationSequenceDependent() {
+        MegaFarm farm = new MegaFarm(); // subclass
+        farm.animals = new Animal[] {
+            new Animal("Cow"),
+            new Animal("Sheep")
+        };
+        farm.names = new String[] {
+            "McDonald",
+            "Ponte Rosa"
+        };
+        
+        String expected = "" +
+                "<MEGA-farm>\n" +
+                "  <animal>\n" +
+                "    <name>Cow</name>\n" +
+                "  </animal>\n" +
+                "  <animal>\n" +
+                "    <name>Sheep</name>\n" +
+                "  </animal>\n" +
+                "  <name>McDonald</name>\n" +
+                "  <name>Ponte Rosa</name>\n" +
+                "</MEGA-farm>";
+
+        xstream.addImplicitArray(MegaFarm.class, "names", "name");
+        xstream.addImplicitArray(Farm.class, "animals");
+        assertBothWays(farm, expected);
+    }
+
     public void testAllowsSubclassToOverrideImplicitCollectionInSuperclass() {
         Farm farm = new MegaFarm(); // subclass
         farm.animals = new Animal[] {
@@ -140,6 +169,53 @@
         assertBothWays(farm, expected);
     }
 
+    public void testAllowDifferentImplicitArrayDefinitionsInSubclass() {
+        Farm farm = new Farm();
+        farm.animals = new Animal[] {
+           new Animal("Cod"), 
+           new Animal("Salmon") 
+        };
+        MegaFarm megaFarm = new MegaFarm(); // subclass
+        megaFarm.animals = new Animal[] {
+            new Animal("Cow"),
+            new Animal("Sheep")
+        };
+        megaFarm.names = new String[] {
+            "McDonald",
+            "Ponte Rosa"
+        };
+        
+        List list = new ArrayList();
+        list.add(farm);
+        list.add(megaFarm);
+        String expected = "" +
+                "<list>\n" +
+                "  <farm>\n" +
+                "    <fish>\n" +
+                "      <name>Cod</name>\n" +
+                "    </fish>\n" +
+                "    <fish>\n" +
+                "      <name>Salmon</name>\n" +
+                "    </fish>\n" +
+                "  </farm>\n" +
+                "  <MEGA-farm>\n" +
+                "    <animal>\n" +
+                "      <name>Cow</name>\n" +
+                "    </animal>\n" +
+                "    <animal>\n" +
+                "      <name>Sheep</name>\n" +
+                "    </animal>\n" +
+                "    <name>McDonald</name>\n" +
+                "    <name>Ponte Rosa</name>\n" +
+                "  </MEGA-farm>\n" +
+                "</list>";
+
+        xstream.addImplicitArray(Farm.class, "animals", "fish");
+        xstream.addImplicitArray(MegaFarm.class, "animals");
+        xstream.addImplicitArray(MegaFarm.class, "names", "name");
+        assertBothWays(list, expected);
+    }
+
     public static class House extends StandardObject {
         private Room[] rooms;
         private Person[] people;

Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitCollectionTest.java (1962 => 1963)


--- trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitCollectionTest.java	2012-03-08 23:54:40 UTC (rev 1962)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitCollectionTest.java	2012-03-19 21:40:30 UTC (rev 1963)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004, 2005 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2009, 2011 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -157,6 +157,34 @@
         assertBothWays(farm, expected);
     }
 
+    public void testInheritedAndDirectDeclaredImplicitCollectionAtOnceIsNotDeclarationSequenceDependent() {
+        xstream.alias("MEGA-farm", MegaFarm.class);
+
+        MegaFarm farm = new MegaFarm(100); // subclass
+        farm.add(new Animal("Cow"));
+        farm.add(new Animal("Sheep"));
+        farm.names = new ArrayList();
+        farm.names.add("McDonald");
+        farm.names.add("Ponte Rosa");
+        
+        String expected = "" +
+                "<MEGA-farm>\n" +
+                "  <size>100</size>\n" +
+                "  <animal>\n" +
+                "    <name>Cow</name>\n" +
+                "  </animal>\n" +
+                "  <animal>\n" +
+                "    <name>Sheep</name>\n" +
+                "  </animal>\n" +
+                "  <name>McDonald</name>\n" +
+                "  <name>Ponte Rosa</name>\n" +
+                "</MEGA-farm>";
+
+        xstream.addImplicitCollection(MegaFarm.class, "names", "name", String.class);
+        xstream.addImplicitCollection(Farm.class, "animals");
+        assertBothWays(farm, expected);
+    }
+
     public void testAllowsSubclassToOverrideImplicitCollectionInSuperclass() {
         xstream.alias("MEGA-farm", MegaFarm.class);
 
@@ -179,6 +207,52 @@
         assertBothWays(farm, expected);
     }
 
+    public void testAllowDifferentImplicitCollectionDefinitionsInSubclass() {
+        xstream.alias("MEGA-farm", MegaFarm.class);
+
+        Farm farm = new Farm(10);
+        farm.add(new Animal("Cod"));
+        farm.add(new Animal("Salmon"));
+        MegaFarm megaFarm = new MegaFarm(100); // subclass
+        megaFarm.add(new Animal("Cow"));
+        megaFarm.add(new Animal("Sheep"));
+        megaFarm.names = new ArrayList();
+        megaFarm.names.add("McDonald");
+        megaFarm.names.add("Ponte Rosa");
+        
+        List list = new ArrayList();
+        list.add(farm);
+        list.add(megaFarm);
+        String expected = "" +
+                "<list>\n" +
+                "  <farm>\n" +
+                "    <size>10</size>\n" +
+                "    <fish>\n" +
+                "      <name>Cod</name>\n" +
+                "    </fish>\n" +
+                "    <fish>\n" +
+                "      <name>Salmon</name>\n" +
+                "    </fish>\n" +
+                "  </farm>\n" +
+                "  <MEGA-farm>\n" +
+                "    <size>100</size>\n" +
+                "    <animal>\n" +
+                "      <name>Cow</name>\n" +
+                "    </animal>\n" +
+                "    <animal>\n" +
+                "      <name>Sheep</name>\n" +
+                "    </animal>\n" +
+                "    <name>McDonald</name>\n" +
+                "    <name>Ponte Rosa</name>\n" +
+                "  </MEGA-farm>\n" +
+                "</list>";
+
+        xstream.addImplicitCollection(Farm.class, "animals", "fish", Animal.class);
+        xstream.addImplicitCollection(MegaFarm.class, "animals");
+        xstream.addImplicitCollection(MegaFarm.class, "names", "name", String.class);
+        assertBothWays(list, expected);
+    }
+
     public static class House extends StandardObject {
         private List rooms = new ArrayList();
         private List people = new ArrayList();

Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitMapTest.java (1962 => 1963)


--- trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitMapTest.java	2012-03-08 23:54:40 UTC (rev 1962)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitMapTest.java	2012-03-19 21:40:30 UTC (rev 1963)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 XStream Committers.
+ * Copyright (C) 2011, 2012 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -181,6 +181,36 @@
         assertBothWays(sample, expected);
     }
 
+    public void testInheritedAndDirectDeclaredImplicitMapAtOnceIsNotDeclarationSequenceDependent() {
+        xstream.alias("MEGA-sample", MegaSampleMaps.class);
+
+        MegaSampleMaps sample = new MegaSampleMaps(); // subclass
+        sample.good.put("Windows", new Software("Microsoft", "Windows"));
+        sample.good.put("Linux", new Software("Red Hat", "Linux"));
+        sample.other.put("i386", new Hardware("i386", "Intel"));
+        
+        String expected = "" +
+                "<MEGA-sample>\n" +
+                "  <software>\n" +
+                "    <vendor>Microsoft</vendor>\n" +
+                "    <name>Windows</name>\n" +
+                "  </software>\n" +
+                "  <software>\n" +
+                "    <vendor>Red Hat</vendor>\n" +
+                "    <name>Linux</name>\n" +
+                "  </software>\n" +
+                "  <bad/>\n" +
+                "  <hardware>\n" +
+                "    <arch>i386</arch>\n" +
+                "    <name>Intel</name>\n" +
+                "  </hardware>\n" +
+                "</MEGA-sample>";
+
+        xstream.addImplicitMap(MegaSampleMaps.class, "other", Hardware.class, "arch");
+        xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name");
+        assertBothWays(sample, expected);
+    }
+
     public void testAllowsSubclassToOverrideImplicitMapInSuperclass() {
         xstream.alias("MEGA-sample", MegaSampleMaps.class);
 
@@ -206,6 +236,51 @@
         assertBothWays(sample, expected);
     }
 
+    public void testAllowDifferentImplicitMapDefinitionsInSubclass() {
+        xstream.alias("MEGA-sample", MegaSampleMaps.class);
+
+        SampleMaps sample = new SampleMaps();
+        sample.good.put("Google", new Software("Google", "Android"));
+        MegaSampleMaps megaSample = new MegaSampleMaps(); // subclass
+        megaSample.good.put("Windows", new Software("Microsoft", "Windows"));
+        megaSample.good.put("Linux", new Software("Red Hat", "Linux"));
+        megaSample.other.put("i386", new Hardware("i386", "Intel"));
+        
+        List list = new ArrayList();
+        list.add(sample);
+        list.add(megaSample);
+        String expected = "" +
+                "<list>\n" +
+                "  <sample>\n" +
+                "    <mobile>\n" +
+                "      <vendor>Google</vendor>\n" +
+                "      <name>Android</name>\n" +
+                "    </mobile>\n" +
+                "    <bad/>\n" +
+                "  </sample>\n" +
+                "  <MEGA-sample>\n" +
+                "    <software>\n" +
+                "      <vendor>Microsoft</vendor>\n" +
+                "      <name>Windows</name>\n" +
+                "    </software>\n" +
+                "    <software>\n" +
+                "      <vendor>Red Hat</vendor>\n" +
+                "      <name>Linux</name>\n" +
+                "    </software>\n" +
+                "    <bad/>\n" +
+                "    <hardware>\n" +
+                "      <arch>i386</arch>\n" +
+                "      <name>Intel</name>\n" +
+                "    </hardware>\n" +
+                "  </MEGA-sample>\n" +
+                "</list>";
+
+        xstream.addImplicitMap(SampleMaps.class, "good", "mobile", Software.class, "vendor");
+        xstream.addImplicitMap(MegaSampleMaps.class, "good", Software.class, "name");
+        xstream.addImplicitMap(MegaSampleMaps.class, "other", Hardware.class, "arch");
+        assertBothWays(list, expected);
+    }
+
     public void testDefaultMapBasedOnType() {
         xstream.alias("MEGA-sample", MegaSampleMaps.class);
 

Modified: trunk/xstream-distribution/src/content/changes.html (1962 => 1963)


--- trunk/xstream-distribution/src/content/changes.html	2012-03-08 23:54:40 UTC (rev 1962)
+++ trunk/xstream-distribution/src/content/changes.html	2012-03-19 21:40:30 UTC (rev 1963)
@@ -32,9 +32,16 @@
 
     <p>Not yet released.</p>
 
+    <h2>Major changes</h2>
+    
+    <ul>
+    </ul>
+
     <h2>Minor changes</h2>
     
     <ul>
+    	<li>JIRA:XSTR-683: Inheritance of implicit collections, arrays or maps is dependent on declaration sequence.</li>
+    	<li>Inherited implicit collections, arrays or maps can be overwritten with own definition in subtype.</li>
     	<li>JIRA:XSTR-688: Cannot omit XML elements from derived fields.</li>
     	<li>JIRA:XSTR-685: Deserialization from file or URL keeps stream open.</li>
     	<li>JIRA:XSTR-684: XML 1.0 character validation fails for characters from 0x10 to 0x1f.</li>

To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to