Index: /home/guilherme/workspace/xstreamold/jdk-1.5-specific.txt
===================================================================
--- /home/guilherme/workspace/xstreamold/jdk-1.5-specific.txt (revision 704)
+++ /home/guilherme/workspace/xstreamold/jdk-1.5-specific.txt (working copy)
@@ -3,3 +3,6 @@
com/thoughtworks/xstream/converters/enums/**
com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider15Test.*
+com/thoughtworks/xstream/annotations/AnnotationProvider
+com/thoughtworks/xstream/annotations/Java15ReflectionConverter
+
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/XStream.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/XStream.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/XStream.java (working copy)
@@ -1,5 +1,43 @@
package com.thoughtworks.xstream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.NotActiveException;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputValidation;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URL;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+
import com.thoughtworks.xstream.alias.ClassMapper;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.ConverterLookup;
@@ -77,44 +115,6 @@
import com.thoughtworks.xstream.mapper.OuterClassMapper;
import com.thoughtworks.xstream.mapper.XmlFriendlyMapper;
-import java.io.EOFException;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.NotActiveException;
-import java.io.ObjectInputStream;
-import java.io.ObjectInputValidation;
-import java.io.ObjectOutputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.net.URL;
-import java.sql.Time;
-import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Vector;
-
/**
* Simple facade to XStream library, a Java-XML serialization tool.
*
@@ -391,10 +391,10 @@
}
protected void setupConverters() {
- ReflectionConverter reflectionConverter = new ReflectionConverter(mapper, reflectionProvider);
+ ReflectionConverter reflectionConverter = jvm.getReflectionConverter(mapper, reflectionProvider);
registerConverter(reflectionConverter, PRIORITY_VERY_LOW);
- registerConverter(new SerializableConverter(mapper, reflectionProvider), PRIORITY_LOW);
+ registerConverter(new SerializableConverter(mapper, reflectionProvider, jvm), PRIORITY_LOW);
registerConverter(new ExternalizableConverter(mapper), PRIORITY_LOW);
registerConverter(new NullConverter(), PRIORITY_VERY_HIGH);
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/annotations/AnnotationProvider.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/annotations/AnnotationProvider.java (revision 0)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/annotations/AnnotationProvider.java (revision 0)
@@ -0,0 +1,29 @@
+package com.thoughtworks.xstream.annotations;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+
+/**
+ * A pure java annotation provider.
+ *
+ * @author Guilherme Silveira
+ */
+public class AnnotationProvider {
+
+ /**
+ * Returns a field annotation based on an annotation type
+ *
+ * @param
+ * annotation type
+ * @param field
+ * field annotation
+ * @param annotationClass
+ * annotation class
+ * @return
+ */
+ public T getAnnotation(Field field,
+ Class annotationClass) {
+ return (T) field.getAnnotation(annotationClass);
+ }
+
+}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/annotations/Java15ReflectionConverter.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/annotations/Java15ReflectionConverter.java (revision 0)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/annotations/Java15ReflectionConverter.java (revision 0)
@@ -0,0 +1,52 @@
+package com.thoughtworks.xstream.annotations;
+
+import java.lang.reflect.Field;
+
+import com.thoughtworks.xstream.converters.Converter;
+import com.thoughtworks.xstream.converters.MarshallingContext;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
+import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
+import com.thoughtworks.xstream.mapper.Mapper;
+
+public class Java15ReflectionConverter extends ReflectionConverter {
+
+ private final AnnotationProvider annotationProvider;
+
+ public Java15ReflectionConverter(Mapper mapper,
+ ReflectionProvider reflectionProvider,
+ AnnotationProvider annotationProvider) {
+ super(mapper, reflectionProvider);
+ // should I keep a copy of reflectionprovider here? both ways are not
+ // cute, I believe I should... I didn't think about any other simple
+ // 'callback' way to implement it, only creating another class...
+ this.annotationProvider = annotationProvider;
+ }
+
+ protected void fieldMarshall(final MarshallingContext context,
+ Object newObj, Field field, ReflectionProvider reflectionProvider) {
+ XStreamConverter annotation = (XStreamConverter) annotationProvider
+ .getAnnotation(field, XStreamConverter.class);
+ if (annotation != null) {
+ context.convertAnother(newObj, (Converter) reflectionProvider
+ .newInstance(annotation.value()));
+ } else {
+ context.convertAnother(newObj);
+ }
+ }
+
+ protected Object fieldUnmarshall(final UnmarshallingContext context,
+ final Object result, Class type, Field field,
+ ReflectionProvider reflectionProvider) {
+ XStreamConverter annotation = (XStreamConverter) annotationProvider
+ .getAnnotation(field, XStreamConverter.class);
+ if (annotation != null) {
+ return context.convertAnother(result, type,
+ (Converter) reflectionProvider.newInstance(annotation
+ .value()));
+ } else {
+ return context.convertAnother(result, type);
+ }
+ }
+
+}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/annotations/XStreamConverter.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/annotations/XStreamConverter.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/annotations/XStreamConverter.java (working copy)
@@ -1,5 +1,6 @@
package com.thoughtworks.xstream.annotations;
+import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -12,7 +13,8 @@
* @author Chung-Onn Cheong
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
+@Target({ElementType.TYPE, ElementType.FIELD})
+@Documented
public @interface XStreamConverter {
Class extends Converter> value();
}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/MarshallingContext.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/MarshallingContext.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/MarshallingContext.java (working copy)
@@ -1,8 +1,18 @@
package com.thoughtworks.xstream.converters;
-
public interface MarshallingContext extends DataHolder {
+ /**
+ * Converts another object searching for the default converter
+ * @param nextItem the next item to convert
+ */
void convertAnother(Object nextItem);
+
+ /**
+ * Converts another object using the specified converter
+ * @param nextItem the next item to convert
+ * @param converter the converter to use
+ */
+ void convertAnother(Object nextItem, Converter converter);
}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/UnmarshallingContext.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/UnmarshallingContext.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/UnmarshallingContext.java (working copy)
@@ -4,6 +4,8 @@
Object convertAnother(Object current, Class type);
+ Object convertAnother(Object current, Class type, Converter converter);
+
Object currentObject();
Class getRequiredType();
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java (working copy)
@@ -9,6 +9,10 @@
import java.util.Iterator;
import java.util.Map;
+/**
+ * A field dictionary instance caches information about classes fields.
+ *
+ */
public class FieldDictionary {
private final Map keyedByFieldNameCache = Collections.synchronizedMap(new HashMap());
@@ -14,6 +18,11 @@
private final Map keyedByFieldNameCache = Collections.synchronizedMap(new HashMap());
private final Map keyedByFieldKeyCache = Collections.synchronizedMap(new HashMap());
+ /**
+ * Returns an iterator for all serializable fields for some class
+ * @param cls the class you are interested on
+ * @return an iterator for its serializable fields
+ */
public Iterator serializableFieldsFor(Class cls) {
return buildMap(cls, true).values().iterator();
}
@@ -18,6 +27,15 @@
return buildMap(cls, true).values().iterator();
}
+ /**
+ * Returns an specific field of some class. If definedIn is null, it searchs for the field named 'name' inside the class cls.
+ * If definedIn is different than null, tries to find the specified field name in the specified class cls which should be defined in
+ * class definedIn (either equals cls or a one of it's superclasses)
+ * @param cls the class where the field is to be searched
+ * @param name the field name
+ * @param definedIn the superclass (or the class itself) of cls where the field was defined
+ * @return the field itself
+ */
public Field field(Class cls, String name, Class definedIn) {
Map fields = buildMap(cls, definedIn != null);
Field field = (Field) fields.get(definedIn != null ? (Object) new FieldKey(name, definedIn, 0) : (Object) name);
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java (working copy)
@@ -1,7 +1,5 @@
package com.thoughtworks.xstream.converters.reflection;
-import com.thoughtworks.xstream.core.JVM;
-
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
@@ -19,6 +17,8 @@
import java.util.Iterator;
import java.util.Map;
+import com.thoughtworks.xstream.core.JVM;
+
/**
* Pure Java ObjectFactory that instantiates objects using standard Java reflection, however the types of objects
* that can be constructed are limited.
@@ -32,7 +32,7 @@
public class PureJavaReflectionProvider implements ReflectionProvider {
private final Map serializedDataCache = Collections.synchronizedMap(new HashMap());
-
+
protected FieldDictionary fieldDictionary = new FieldDictionary();
public Object newInstance(Class type) {
@@ -157,4 +157,8 @@
}
}
+ public Field getField(Class definedIn, String fieldName) {
+ return fieldDictionary.field(definedIn, fieldName, null);
+ }
+
}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/ReflectionConverter.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/ReflectionConverter.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/ReflectionConverter.java (working copy)
@@ -1,5 +1,6 @@
package com.thoughtworks.xstream.converters.reflection;
+import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -64,7 +65,7 @@
Collection list = (Collection) newObj;
for (Iterator iter = list.iterator(); iter.hasNext();) {
Object obj = iter.next();
- writeField(mapping.getItemFieldName(), mapping.getItemType(), definedIn, obj);
+ writeField(fieldName, mapping.getItemFieldName(), mapping.getItemType(), definedIn, obj);
}
} else {
context.convertAnother(newObj);
@@ -70,7 +71,7 @@
context.convertAnother(newObj);
}
} else {
- writeField(fieldName, fieldType, definedIn, newObj);
+ writeField(fieldName, fieldName, fieldType, definedIn, newObj);
seenFields.add(fieldName);
}
}
@@ -76,11 +77,11 @@
}
}
- private void writeField(String fieldName, Class fieldType, Class definedIn, Object newObj) {
- if (!mapper.shouldSerializeMember(definedIn, fieldName)) {
+ private void writeField(String fieldName, String aliasName, Class fieldType, Class definedIn, Object newObj) {
+ if (!mapper.shouldSerializeMember(definedIn, aliasName)) {
return;
}
- writer.startNode(mapper.serializedMember(definedIn, fieldName));
+ writer.startNode(mapper.serializedMember(definedIn, aliasName));
Class actualType = newObj.getClass();
@@ -89,7 +90,7 @@
writer.addAttribute(mapper.attributeForImplementationClass(), mapper.serializedClass(actualType));
}
- if (seenFields.contains(fieldName)) {
+ if (seenFields.contains(aliasName)) {
writer.addAttribute(mapper.attributeForClassDefiningField(), mapper.serializedClass(definedIn));
}
@@ -94,7 +95,8 @@
}
if (source != newObj) {
- context.convertAnother(newObj);
+ Field field = reflectionProvider.getField(definedIn,fieldName);
+ fieldMarshall(context, newObj, field, reflectionProvider);
} else {
writer.addAttribute("self", "");
}
@@ -104,7 +106,11 @@
});
}
- public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
+ protected void fieldMarshall(final MarshallingContext context, Object newObj, Field field, ReflectionProvider reflectionProvider) {
+ context.convertAnother(newObj);
+ }
+
+ public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
final Object result = instantiateNewInstance(context, reader.getAttribute(mapper.attributeForReadResolveField()));
final SeenFields seenFields = new SeenFields();
Iterator it = reader.getAttributeNames();
@@ -137,7 +143,12 @@
final Object value;
String self = reader.getAttribute("self");
if (self == null) {
- value = context.convertAnother(result, type);
+ if (fieldExistsInClass) {
+ Field field = reflectionProvider.getField(result.getClass(),fieldName);
+ value = fieldUnmarshall(context, result, type, field, reflectionProvider);
+ } else {
+ value = context.convertAnother(result, type);
+ }
} else {
value = result;
}
@@ -155,6 +166,9 @@
return serializationMethodInvoker.callReadResolve(result);
}
+ protected Object fieldUnmarshall(final UnmarshallingContext context, final Object result, Class type, Field field, ReflectionProvider reflectionProvider) {
+ return context.convertAnother(result, type);
+ }
private Map writeValueToImplicitCollection(UnmarshallingContext context, Object value, Map implicitCollections, Object result, String itemFieldName) {
String fieldName = mapper.getFieldNameForItemTypeAndName(context.getRequiredType(), value.getClass(), itemFieldName);
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/ReflectionProvider.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/ReflectionProvider.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/ReflectionProvider.java (working copy)
@@ -1,5 +1,7 @@
package com.thoughtworks.xstream.converters.reflection;
+import java.lang.reflect.Field;
+
/**
* Provides core reflection services.
*/
@@ -5,6 +7,11 @@
*/
public interface ReflectionProvider {
+ /**
+ * Creates a new instance of the specified type using the default (null) constructor.
+ * @param type the type to instantiate
+ * @return a new instance of this type
+ */
Object newInstance(Class type);
void visitSerializableFields(Object object, Visitor visitor);
@@ -15,7 +22,28 @@
boolean fieldDefinedInClass(String fieldName, Class type);
+ /**
+ * A visitor interface for serializable fields defined in a class.
+ *
+ */
interface Visitor {
+
+ /**
+ * Callback for each visit
+ * @param name field name
+ * @param type field type
+ * @param definedIn where the field was defined
+ * @param value field value
+ */
void visit(String name, Class type, Class definedIn, Object value);
}
+
+ /**
+ * Returns a field defined in some class.
+ * @param definedIn class where the field was defined
+ * @param fieldName field name
+ * @return the field itself
+ */
+ Field getField(Class definedIn, String fieldName);
+
}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java (working copy)
@@ -1,15 +1,5 @@
package com.thoughtworks.xstream.converters.reflection;
-import com.thoughtworks.xstream.converters.ConversionException;
-import com.thoughtworks.xstream.converters.Converter;
-import com.thoughtworks.xstream.converters.MarshallingContext;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.core.util.CustomObjectInputStream;
-import com.thoughtworks.xstream.core.util.CustomObjectOutputStream;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-import com.thoughtworks.xstream.mapper.Mapper;
-
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
@@ -26,6 +16,17 @@
import java.util.List;
import java.util.Map;
+import com.thoughtworks.xstream.converters.ConversionException;
+import com.thoughtworks.xstream.converters.Converter;
+import com.thoughtworks.xstream.converters.MarshallingContext;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.core.JVM;
+import com.thoughtworks.xstream.core.util.CustomObjectInputStream;
+import com.thoughtworks.xstream.core.util.CustomObjectOutputStream;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import com.thoughtworks.xstream.mapper.Mapper;
+
/**
* Emulates the mechanism used by standard Java Serialization for classes that implement java.io.Serializable AND
* implement a custom readObject()/writeObject() method.
@@ -63,10 +64,10 @@
private static final String ELEMENT_FIELD = "field";
private static final String ATTRIBUTE_NAME = "name";
- public SerializableConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
+ public SerializableConverter(Mapper mapper, ReflectionProvider reflectionProvider, JVM jvm) {
this.mapper = mapper;
this.reflectionProvider = reflectionProvider;
- this.reflectionConverter = new ReflectionConverter(mapper, new UnserializableParentsReflectionProvider(reflectionProvider));
+ this.reflectionConverter = jvm.getReflectionConverter(mapper, new UnserializableParentsReflectionProvider(reflectionProvider));
}
public boolean canConvert(Class type) {
@@ -407,6 +408,10 @@
return context.keys();
}
+ public Object convertAnother(Object current, Class type, Converter converter) {
+ return context.convertAnother(current, type, converter);
+ }
+
});
} else {
currentType[0] = mapper.defaultImplementationOf(mapper.realClass(nodeName));
@@ -461,5 +466,9 @@
return reflectionProvider.fieldDefinedInClass(fieldName, type);
}
+ public Field getField(Class definedIn, String fieldName) {
+ return reflectionProvider.getField(definedIn, fieldName);
+ }
+
}
}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/JVM.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/JVM.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/JVM.java (working copy)
@@ -1,7 +1,11 @@
package com.thoughtworks.xstream.core;
+import com.thoughtworks.xstream.annotations.AnnotationProvider;
+import com.thoughtworks.xstream.annotations.Java15ReflectionConverter;
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
+import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
+import com.thoughtworks.xstream.mapper.Mapper;
import java.lang.reflect.Field;
import java.security.AccessControlException;
@@ -106,4 +110,19 @@
public static synchronized boolean reverseMemberDefinition() {
return reverseMemberOrder;
}
+
+ /**
+ * Returns the a new reflection converter, either java 1.5 or 1.3 compatible.
+ * @param mapper the mapper to use
+ * @param provider the provider to use
+ * @return
+ */
+ public ReflectionConverter getReflectionConverter(Mapper mapper, ReflectionProvider provider) {
+ if (JVM.is15()) {
+ // need a provider.newInstance(class, args)
+ return new Java15ReflectionConverter(mapper, provider, (AnnotationProvider) provider.newInstance(loadClass("com.thoughtworks.xstream.annotations.AnnotationProvider")));
+ } else {
+ return new ReflectionConverter(mapper, provider);
+ }
+ }
}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByIdMarshaller.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByIdMarshaller.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByIdMarshaller.java (working copy)
@@ -50,9 +50,7 @@
this(writer, converterLookup, classMapper, new SequenceGenerator(1));
}
- public void convertAnother(Object item) {
- Converter converter = converterLookup.lookupConverterForType(item.getClass());
-
+ public void convert(Object item, Converter converter) {
if (getMapper().isImmutableValueType(item.getClass())) {
// strings, ints, dates, etc... don't bother using references.
converter.marshal(item, writer, this);
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByIdUnmarshaller.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByIdUnmarshaller.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByIdUnmarshaller.java (working copy)
@@ -1,6 +1,10 @@
package com.thoughtworks.xstream.core;
+import java.util.HashMap;
+import java.util.Map;
+
import com.thoughtworks.xstream.alias.ClassMapper;
+import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.ConverterLookup;
import com.thoughtworks.xstream.core.util.FastStack;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
@@ -6,9 +10,6 @@
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.mapper.Mapper;
-import java.util.HashMap;
-import java.util.Map;
-
public class ReferenceByIdUnmarshaller extends TreeUnmarshaller {
private Map values = new HashMap();
@@ -27,7 +28,7 @@
super(root, reader, converterLookup, classMapper);
}
- public Object convertAnother(Object parent, Class type) {
+ protected Object convert(Object parent, Class type, Converter converter) {
if (parentIdStack.size() > 0) { // handles circular references
Object parentId = parentIdStack.peek();
if (!values.containsKey(parentId)) { // see AbstractCircularReferenceTest.testWeirdCircularReference()
@@ -40,7 +41,7 @@
} else {
String currentId = reader.getAttribute("id");
parentIdStack.push(currentId);
- Object result = super.convertAnother(parent, type);
+ Object result = super.convert(parent, type, converter);
values.put(currentId, result);
parentIdStack.popSilently();
return result;
@@ -47,4 +48,5 @@
}
}
+
}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByXPathMarshaller.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByXPathMarshaller.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByXPathMarshaller.java (working copy)
@@ -27,9 +27,7 @@
this(writer, converterLookup, (Mapper)classMapper);
}
- public void convertAnother(Object item) {
- Converter converter = converterLookup.lookupConverterForType(item.getClass());
-
+ protected void convert(Object item, Converter converter) {
if (getMapper().isImmutableValueType(item.getClass())) {
// strings, ints, dates, etc... don't bother using references.
converter.marshal(item, writer, this);
@@ -45,5 +43,4 @@
}
}
}
-
}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByXPathUnmarshaller.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByXPathUnmarshaller.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/ReferenceByXPathUnmarshaller.java (working copy)
@@ -1,6 +1,10 @@
package com.thoughtworks.xstream.core;
+import java.util.HashMap;
+import java.util.Map;
+
import com.thoughtworks.xstream.alias.ClassMapper;
+import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.ConverterLookup;
import com.thoughtworks.xstream.core.util.FastStack;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
@@ -9,9 +13,6 @@
import com.thoughtworks.xstream.io.path.PathTrackingReader;
import com.thoughtworks.xstream.mapper.Mapper;
-import java.util.HashMap;
-import java.util.Map;
-
public class ReferenceByXPathUnmarshaller extends TreeUnmarshaller {
private Map values = new HashMap();
@@ -32,7 +33,7 @@
this(root, reader, converterLookup, (Mapper)classMapper);
}
- public Object convertAnother(Object parent, Class type) {
+ protected Object convert(Object parent, Class type, Converter converter) {
if (parentPathStack.size() > 0) { // handles circular references
Object parentPath = parentPathStack.peek();
if (!values.containsKey(parentPath)) { // see AbstractCircularReferenceTest.testWeirdCircularReference()
@@ -45,7 +46,7 @@
return values.get(currentPath.apply(new Path(relativePathOfReference)));
} else {
parentPathStack.push(currentPath);
- Object result = super.convertAnother(parent, type);
+ Object result = super.convert(parent, type, converter);
values.put(currentPath, result);
parentPathStack.popSilently();
return result;
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/TreeMarshaller.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/TreeMarshaller.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/TreeMarshaller.java (working copy)
@@ -45,6 +45,15 @@
}
public void convertAnother(Object item) {
+ Converter converter = converterLookup.lookupConverterForType(item.getClass());
+ convert(item, converter);
+ }
+
+ public void convertAnother(Object item, Converter converter) {
+ convert(item, converter);
+ }
+
+ protected void convert(Object item, Converter converter) {
if (parentObjects.containsId(item)) {
throw new CircularReferenceException();
}
@@ -49,7 +58,6 @@
throw new CircularReferenceException();
}
parentObjects.associateId(item, "");
- Converter converter = converterLookup.lookupConverterForType(item.getClass());
converter.marshal(item, writer, this);
parentObjects.removeId(item);
}
Index: /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/TreeUnmarshaller.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/TreeUnmarshaller.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/java/com/thoughtworks/xstream/core/TreeUnmarshaller.java (working copy)
@@ -40,9 +40,18 @@
this(root, reader, converterLookup, (Mapper)classMapper);
}
+
public Object convertAnother(Object parent, Class type) {
- try {
- Converter converter = converterLookup.lookupConverterForType(type);
+ Converter converter = converterLookup.lookupConverterForType(type);
+ return convert(parent, type,converter);
+ }
+
+ public Object convertAnother(Object parent, Class type, Converter converter) {
+ return convert(parent, type, converter);
+ }
+
+ protected Object convert(Object parent, Class type, Converter converter) {
+ try {
types.push(mapper.defaultImplementationOf(type));
Object result = converter.unmarshal(reader, this);
types.popSilently();
@@ -55,7 +64,7 @@
addInformationTo(conversionException, type);
throw conversionException;
}
- }
+ }
private void addInformationTo(ErrorWriter errorWriter, Class type) {
errorWriter.add("class", type.getName());
Index: /home/guilherme/workspace/xstreamold/src/test/com/thoughtworks/acceptance/annotations/AnnotationsTest.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/test/com/thoughtworks/acceptance/annotations/AnnotationsTest.java (revision 704)
+++ /home/guilherme/workspace/xstreamold/src/test/com/thoughtworks/acceptance/annotations/AnnotationsTest.java (working copy)
@@ -17,6 +17,7 @@
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
/**
+ * Simple tests for class annotations
*
* @author Chung-Onn Cheong
* @author Mauro Talevi
@@ -23,7 +24,7 @@
*/
public class AnnotationsTest extends AbstractAcceptanceTest {
- public void testAnnotations() {
+ public void testAnnotations() {
Annotations.configureAliases(xstream, Person.class, AddressBookInfo.class);
Map map = new HashMap();
map.put("first person", new Person("john doe"));
Index: /home/guilherme/workspace/xstreamold/src/test/com/thoughtworks/acceptance/annotations/DepthOverridingTest.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/test/com/thoughtworks/acceptance/annotations/DepthOverridingTest.java (revision 0)
+++ /home/guilherme/workspace/xstreamold/src/test/com/thoughtworks/acceptance/annotations/DepthOverridingTest.java (revision 0)
@@ -0,0 +1,83 @@
+package com.thoughtworks.acceptance.annotations;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import com.thoughtworks.acceptance.AbstractAcceptanceTest;
+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;
+
+/**
+ * Tests for depth converter overriding
+ *
+ * @author Guilherme Silveira
+ */
+public class DepthOverridingTest extends AbstractAcceptanceTest {
+
+ public static class Task {
+
+ @XStreamConverter(GregorianTimeConverter.class)
+ private Calendar date;
+
+ @XStreamConverter(GregorianTimeConverter.class)
+ private Calendar time;
+
+ public Task(Calendar date, Calendar time) {
+ this.date = date;
+ this.time = time;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null && Task.class.equals(obj.getClass())
+ && ((Task) obj).date.equals(date)
+ && ((Task) obj).time.equals(time);
+ }
+
+ }
+
+ public void testConverterOverriding() {
+ Task task = new Task(new GregorianCalendar(1981, 9, 18),
+ new GregorianCalendar(0, 0, 0, 30, 20));
+ String xml = "\n"
+ + " \n"
+ + " 372222000000\n"
+ + " \n"
+ + " \n"
+ + "";
+ assertBothWays(task, xml);
+ }
+
+ public static class GregorianTimeConverter implements Converter {
+
+ public void marshal(Object source, HierarchicalStreamWriter writer,
+ MarshallingContext context) {
+ Calendar calendar = (Calendar) source;
+ writer.startNode("cal");
+ writer.setValue(String.valueOf(calendar.getTime().getTime()));
+ writer.endNode();
+ }
+
+ public Object unmarshal(HierarchicalStreamReader reader,
+ UnmarshallingContext context) {
+ reader.moveDown();
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(new Date(Long.parseLong(reader.getValue())));
+ reader.moveUp();
+ return calendar;
+ }
+
+ public boolean canConvert(Class type) {
+ return type.equals(Calendar.class);
+ }
+
+ }
+
+}
Index: /home/guilherme/workspace/xstreamold/src/test/com/thoughtworks/acceptance/annotations/SimpleOverridingTest.java
===================================================================
--- /home/guilherme/workspace/xstreamold/src/test/com/thoughtworks/acceptance/annotations/SimpleOverridingTest.java (revision 0)
+++ /home/guilherme/workspace/xstreamold/src/test/com/thoughtworks/acceptance/annotations/SimpleOverridingTest.java (revision 0)
@@ -0,0 +1,75 @@
+package com.thoughtworks.acceptance.annotations;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import com.thoughtworks.acceptance.AbstractAcceptanceTest;
+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;
+
+/**
+ * Tests for converter overriding
+ *
+ * @author Guilherme Silveira
+ */
+public class SimpleOverridingTest extends AbstractAcceptanceTest {
+
+ public static class Task {
+
+ @XStreamConverter(GregorianTimeConverter.class)
+ private Calendar date;
+
+ @XStreamConverter(GregorianTimeConverter.class)
+ private Calendar time;
+
+ public Task(Calendar date, Calendar time) {
+ this.date = date;
+ this.time = time;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null && Task.class.equals(obj.getClass())
+ && ((Task) obj).date.equals(date)
+ && ((Task) obj).time.equals(time);
+ }
+
+ }
+
+ public void testConverterOverriding() {
+ Task task = new Task(new GregorianCalendar(1981, 9, 18),
+ new GregorianCalendar(0, 0, 0, 30, 20));
+ String xml = "\n"
+ + " 372222000000\n"
+ + " \n"
+ + "";
+ assertBothWays(task, xml);
+ }
+
+ public static class GregorianTimeConverter implements Converter {
+
+ public void marshal(Object source, HierarchicalStreamWriter writer,
+ MarshallingContext context) {
+ Calendar calendar = (Calendar) source;
+ writer.setValue(String.valueOf(calendar.getTime().getTime()));
+ }
+
+ public Object unmarshal(HierarchicalStreamReader reader,
+ UnmarshallingContext context) {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(new Date(Long.parseLong(reader.getValue())));
+ return calendar;
+ }
+
+ public boolean canConvert(Class type) {
+ return type.equals(Calendar.class);
+ }
+
+ }
+
+}