Index: xstream/src/java/com/thoughtworks/xstream/annotations/Annotations.java =================================================================== --- xstream/src/java/com/thoughtworks/xstream/annotations/Annotations.java (revision 844) +++ xstream/src/java/com/thoughtworks/xstream/annotations/Annotations.java (working copy) @@ -5,7 +5,9 @@ import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import com.thoughtworks.xstream.XStream; @@ -114,9 +116,10 @@ } } - //Do Member Level Alias and XStreamContainedType - Field[] fields = configurableClass.getDeclaredFields(); - for (Field field : fields) { + //Do Member Level Alias and XStreamContainedType + Map fields = new HashMap(); + getAllFields(configurableClass, fields); + for (Field field : fields.values()) { if(field.isSynthetic()) continue; //Alias the member's Type @@ -149,7 +152,14 @@ } } - + private static void getAllFields(Class configurableClass, Map fields) { + Class superClass = configurableClass.getSuperclass(); + if (superClass != null && !Object.class.equals(superClass)) + getAllFields(superClass, fields); + for (Field field : configurableClass.getDeclaredFields()) + fields.put(field.getName(),field); // if a field hides another, any annotation on the hidden field will be ignored + } + private static void registerConverter(XStream xstream, Class converterType) { Converter converter; if(configuredTypes.contains(converterType)) Index: xstream/src/test/com/thoughtworks/acceptance/annotations/AnnotationsFieldTest.java =================================================================== --- xstream/src/test/com/thoughtworks/acceptance/annotations/AnnotationsFieldTest.java (revision 0) +++ xstream/src/test/com/thoughtworks/acceptance/annotations/AnnotationsFieldTest.java (revision 0) @@ -0,0 +1,116 @@ +package com.thoughtworks.acceptance.annotations; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.thoughtworks.acceptance.AbstractAcceptanceTest; +import com.thoughtworks.xstream.annotations.Annotations; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamContainedType; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * Simple tests for field annotations + * + */ +public class AnnotationsFieldTest extends AbstractAcceptanceTest { + + public void testAnnotations() { + Annotations.configureAliases(xstream, Person.class); + List nickNames = new ArrayList(); + nickNames.add("johnny"); + nickNames.add("jack"); + Person person = new Person("john", "doe", 25, nickNames); + String xml = + "\n"+ + " john\n" + + " doe\n" + + " 25\n" + + " \n" + + " johnny\n" + + " jack\n" + + " \n" + + ""; + assertBothWays(person, xml); + } + + public void testAnnotationsInSuperclass() { + Annotations.configureAliases(xstream, GenderedPerson.class); + List nickNames = new ArrayList(); + nickNames.add("johnny"); + nickNames.add("jack"); + GenderedPerson person = new GenderedPerson("john", "doe", 25, nickNames, "male"); + String xml = + "\n"+ + " male\n" + + " john\n" + + " doe\n" + + " 25\n" + + " \n" + + " johnny\n" + + " jack\n" + + " \n" + + ""; + assertBothWays(person, xml); + } + + @XStreamAlias("person") + public static class Person { + @XStreamAlias("first-name") + String firstName; + @XStreamAlias("last-name") + String lastName; + @XStreamAlias("age-in-years") + int ageInYears; + @XStreamAlias("nick-names") + List nickNames; + + public Person(String firstName, String lastName, int ageInYears, List nickNames) { + this.firstName = firstName; + this.lastName = lastName; + this.ageInYears = ageInYears; + this.nickNames = nickNames; + } + + public boolean equals(Object obj) { + if((obj == null) || !(obj instanceof Person)) return false; + return toString().equals(obj.toString()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("firstName:").append(firstName) + .append(",lastName:").append(lastName) + .append(",ageInYears:").append(ageInYears) + .append(",nickNames:").append(nickNames); + return sb.toString(); + } + + } + + @XStreamAlias("gendered-person") + public static class GenderedPerson extends Person { + @XStreamAlias("gender") + String sex; + + public GenderedPerson(String firstName, String lastName, int ageInYears, List nickNames, String sex) { + super(firstName, lastName, ageInYears, nickNames); + this.sex = sex; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(super.toString()); + sb.append(",sex:").append(sex); + return sb.toString(); + } + } +}