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
- trunk/xstream/src/java/com/thoughtworks/xstream/mapper/ImplicitCollectionMapper.java
- trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitArrayTest.java
- trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitCollectionTest.java
- trunk/xstream/src/test/com/thoughtworks/acceptance/ImplicitMapTest.java
- trunk/xstream-distribution/src/content/changes.html
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:
