Index: src/test/com/thoughtworks/acceptance/FieldAliasTest.java
===================================================================
--- src/test/com/thoughtworks/acceptance/FieldAliasTest.java (revision 0)
+++ src/test/com/thoughtworks/acceptance/FieldAliasTest.java (revision 0)
@@ -0,0 +1,81 @@
+package com.thoughtworks.acceptance;
+
+import com.thoughtworks.acceptance.objects.Software;
+import com.thoughtworks.acceptance.objects.OpenSourceSoftware;
+
+import java.util.ArrayList;
+
+/**
+ * @author David Blevins
+ */
+public class FieldAliasTest extends AbstractAcceptanceTest {
+
+ public void testAllowsIndividualFieldsToBeAliased() {
+ Software in = new Software("ms", "word");
+ xstream.alias("software", Software.class);
+ xstream.aliasField("CUSTOM-VENDOR", Software.class, "vendor");
+ xstream.aliasField("CUSTOM-NAME", Software.class, "name");
+
+ String expectedXml = "" +
+ "\n" +
+ " ms\n" +
+ " word\n" +
+ "";
+
+ assertBothWays(in, expectedXml);
+ }
+
+
+ public void testInheritsFieldAliasFromSuperclass() {
+ ArrayList software = new ArrayList();
+ software.add(new Software("ms", "word"));
+ software.add(new OpenSourceSoftware("apache", "geronimo", "asl 2.0"));
+
+ xstream.alias("oss", OpenSourceSoftware.class);
+ xstream.alias("software", Software.class);
+ xstream.aliasField("CUSTOM-VENDOR", Software.class, "vendor");
+ xstream.aliasField("CUSTOM-NAME", Software.class, "name");
+
+ String expectedXml = "" +
+ "\n" +
+ " \n" +
+ " ms\n" +
+ " word\n" +
+ " \n" +
+ " \n" +
+ " asl 2.0\n" +
+ " apache\n" +
+ " geronimo\n" +
+ " \n" +
+ "
";
+
+ assertBothWays(software, expectedXml);
+ }
+
+ public void testAllowsSubclassToOverrideFieldAliasInSuperclass() {
+ ArrayList software = new ArrayList();
+ software.add(new Software("ms", "word"));
+ software.add(new OpenSourceSoftware("apache", "geronimo", "asl 2.0"));
+
+ xstream.alias("oss", OpenSourceSoftware.class);
+ xstream.aliasField("ORGANIZATION", OpenSourceSoftware.class, "vendor");
+ xstream.alias("software", Software.class);
+ xstream.aliasField("CUSTOM-VENDOR", Software.class, "vendor");
+ xstream.aliasField("CUSTOM-NAME", Software.class, "name");
+
+ String expectedXml = "" +
+ "\n" +
+ " \n" +
+ " ms\n" +
+ " word\n" +
+ " \n" +
+ " \n" +
+ " asl 2.0\n" +
+ " apache\n" +
+ " geronimo\n" +
+ " \n" +
+ "
";
+
+ assertBothWays(software, expectedXml);
+ }
+}
Index: src/java/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java
===================================================================
--- src/java/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java (revision 847)
+++ src/java/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java (working copy)
@@ -12,6 +12,7 @@
* entirely.
*
* @author Joe Walnes
+ * @author David Blevins
*/
public class FieldAliasingMapper extends MapperWrapper {
@@ -35,12 +36,12 @@
aliasToFieldMap.put(key(type, alias), fieldName);
}
- private Object key(Class type, String value) {
- return type.getName() + '.' + value;
+ private Key key(Class type, String value) {
+ return new Key(type, value);
}
public String serializedMember(Class type, String memberName) {
- String alias = (String) fieldToAliasMap.get(key(type, memberName));
+ String alias = get(key(type, memberName), fieldToAliasMap);
if (alias == null) {
return super.serializedMember(type, memberName);
} else {
@@ -49,7 +50,7 @@
}
public String realMember(Class type, String serialized) {
- String real = (String) aliasToFieldMap.get(key(type, serialized));
+ String real = get(key(type, serialized), aliasToFieldMap);
if (real == null) {
return super.realMember(type, serialized);
} else {
@@ -64,4 +65,66 @@
public void omitField(Class type, String fieldName) {
fieldsToOmit.add(key(type, fieldName));
}
+
+ private String get(Key key, Map map){
+ String value = (String) map.get(key);
+ if (value != null){
+ return value;
+ }
+
+ Class superclass = key.getType().getSuperclass();
+
+ if (superclass == null || superclass == Object.class){
+ return null;
+ }
+
+ value = get(new Key(superclass, key.getName()), map);
+
+ if (value != null){
+ map.put(key, value);
+ }
+
+ return value;
+ }
+
+ private static class Key {
+ private final Class type;
+ private final String name;
+
+ public Key(Class type, String name) {
+ this.type = type;
+ this.name = name;
+ }
+
+ public Class getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final Key key = (Key) o;
+
+ if (name != null ? !name.equals(key.name) : key.name != null) return false;
+ if (type != null ? !type.equals(key.type) : key.type != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = (type != null ? type.hashCode() : 0);
+ result = 29 * result + (name != null ? name.hashCode() : 0);
+ return result;
+ }
+
+ public String toString() {
+ return "key("+type.getName()+", "+name+")";
+ }
+ }
}
Index: src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java
===================================================================
--- src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java (revision 847)
+++ src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java (working copy)
@@ -71,13 +71,13 @@
Collection list = (Collection) newObj;
for (Iterator iter = list.iterator(); iter.hasNext();) {
Object obj = iter.next();
- writeField(fieldName, mapping.getItemFieldName(), mapping.getItemType(), definedIn, obj);
+ writeField(fieldName, mapping.getItemFieldName(), mapping.getItemType(), source.getClass(), obj);
}
} else {
context.convertAnother(newObj);
}
} else {
- writeField(fieldName, fieldName, fieldType, definedIn, newObj);
+ writeField(fieldName, fieldName, fieldType, source.getClass(), newObj);
seenFields.add(fieldName);
}
}