XStream 1.3 Code Analysis


The main class:
public class XStream {
    public XStream(
            ReflectionProvider reflectionProvider, HierarchicalStreamDriver driver,  
            ClassLoader classLoader, Mapper mapper, ConverterLookup converterLookup,
            ConverterRegistry converterRegistry) {
        jvm = new JVM();
        if (reflectionProvider == null) {
            reflectionProvider = jvm.bestReflectionProvider();
        }
        this.reflectionProvider = reflectionProvider;
        this.hierarchicalStreamDriver = driver;
        this.classLoaderReference = classLoader instanceof ClassLoaderReference ? (ClassLoaderReference)classLoader : new ClassLoaderReference(classLoader);
        this.converterLookup = converterLookup;
        this.converterRegistry = converterRegistry != null
            ? converterRegistry
            : (converterLookup instanceof ConverterRegistry ? (ConverterRegistry)converterLookup : null);
        this.mapper = mapper == null ? buildMapper() : mapper;
        setupMappers();
        setupAliases();
        setupDefaultImplementations();
        setupConverters();
        setupImmutableTypes();
        setMode(XPATH_RELATIVE_REFERENCES);
    }
    // toXML method is the start for parsing java object to xml
    public String toXML(Object obj) {
        Writer writer = new StringWriter();
        toXML(obj, writer);
        return writer.toString();
    }
    
    public void toXML(Object obj, Writer out) {
        HierarchicalStreamWriter writer = hierarchicalStreamDriver.createWriter(out);
        marshal(obj, writer);
        writer.flush();
    }
   
    public void marshal(Object obj, HierarchicalStreamWriter writer) {
        marshal(obj, writer, null);
    }

    public void marshal(Object obj, HierarchicalStreamWriter writer, DataHolder dataHolder) {
        marshallingStrategy.marshal(writer, obj, converterLookup, mapper, dataHolder);
    }
    // the marshallingStrategy is initial by setMode method.
    public void setMode(int mode) {
        switch (mode) {
        case NO_REFERENCES:
            setMarshallingStrategy(new TreeMarshallingStrategy());
            break;
        case ID_REFERENCES:
            setMarshallingStrategy(new ReferenceByIdMarshallingStrategy());
            break;
        // ReferenceByXPathMarshallingStrategy is the default strategy
        case XPATH_RELATIVE_REFERENCES:
            setMarshallingStrategy(new ReferenceByXPathMarshallingStrategy(
                    ReferenceByXPathMarshallingStrategy.RELATIVE));
            break;
        case XPATH_ABSOLUTE_REFERENCES:
            setMarshallingStrategy(new ReferenceByXPathMarshallingStrategy(
                    ReferenceByXPathMarshallingStrategy.ABSOLUTE));
            break;
        default:
            throw new IllegalArgumentException("Unknown mode : " + mode);
        }
    }
}
 
public class ReferenceByXPathMarshallingStrategy extends AbstractTreeMarshallingStrategy {
 
    public ReferenceByXPathMarshallingStrategy(int mode) {
        this.mode = mode;
    }
    protected TreeUnmarshaller createUnmarshallingContext(Object root,
        HierarchicalStreamReader reader, ConverterLookup converterLookup, Mapper mapper) {
        return new ReferenceByXPathUnmarshaller(root, reader, converterLookup, mapper);
    }
    // Override the createMarshallingContext method in AbstractTreeMarshallingStrategy
    protected TreeMarshaller createMarshallingContext(
        HierarchicalStreamWriter writer, ConverterLookup converterLookup, Mapper mapper) {
        return new ReferenceByXPathMarshaller(writer, converterLookup, mapper, mode);
    }
}
 
public abstract class AbstractTreeMarshallingStrategy implements MarshallingStrategy {
    public void marshal(HierarchicalStreamWriter writer, Object obj, ConverterLookup converterLookup, Mapper mapper, DataHolder dataHolder) {
        TreeMarshaller context = createMarshallingContext(writer, converterLookup, mapper);
        context.start(obj, dataHolder);

    }
    protected abstract TreeMarshaller createMarshallingContext(
        HierarchicalStreamWriter writer, ConverterLookup converterLookup, Mapper mapper);
}
 
public class ReferenceByXPathMarshaller extends AbstractReferenceMarshaller {
    public ReferenceByXPathMarshaller(HierarchicalStreamWriter writer, ConverterLookup converterLookup, Mapper mapper, int mode) {
        super(writer, converterLookup, mapper);
        this.mode = mode;
    }
}
 
public class TreeMarshaller implements MarshallingContext {
    public void convertAnother(Object item) {
        convertAnother(item, null);
    }
    public void convertAnother(Object item, Converter converter) {
        if (converter == null) {
            converter = converterLookup.lookupConverterForType(item.getClass());
        } else {
            if (!converter.canConvert(item.getClass())) {
                ConversionException e = new ConversionException(
                    "Explicit selected converter cannot handle item");
                e.add("item-type", item.getClass().getName());
                e.add("converter-type", converter.getClass().getName());
                throw e;
            }
        }
        convert(item, converter);
    }
    protected void convert(Object item, Converter converter) {
        if (parentObjects.containsId(item)) {
            throw new CircularReferenceException();
        }
        parentObjects.associateId(item, "");
        converter.marshal(item, writer, this);
        parentObjects.removeId(item);
    }
    public void start(Object item, DataHolder dataHolder) {
        this.dataHolder = dataHolder;
        if (item == null) {
            writer.startNode(mapper.serializedClass(null));
            writer.endNode();
        } else {
            ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper
                .serializedClass(item.getClass()), item.getClass());
            convertAnother(item);
            writer.endNode();
        }
    }

}
public class PureJavaReflectionProvider implements ReflectionProvider {
 
     public void visitSerializableFields(Object object, ReflectionProvider.Visitor visitor) {
        for (Iterator iterator = fieldDictionary.fieldsFor(object.getClass()); iterator.hasNext();) {
            Field field = (Field) iterator.next();
            if (!fieldModifiersSupported(field)) {
                continue;
            }
            validateFieldAccess(field);
            try {
                Object value = field.get(object);
                visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(), value);
            } catch (IllegalArgumentException e) {
                throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
            } catch (IllegalAccessException e) {
                throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
            }
        }
    }
    public void writeField(Object object, String fieldName, Object value, Class definedIn) {
        Field field = fieldDictionary.field(object.getClass(), fieldName, definedIn);
        validateFieldAccess(field);
        try {
            field.set(object, value);
        } catch (IllegalArgumentException e) {
            throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e);
        } catch (IllegalAccessException e) {
            throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e);
        }
    }
    public Class getFieldType(Object object, String fieldName, Class definedIn) {
        return fieldDictionary.field(object.getClass(), fieldName, definedIn).getType();
    }
    public boolean fieldDefinedInClass(String fieldName, Class type) {
        try {
            Field field = fieldDictionary.field(type, fieldName, null);
            return fieldModifiersSupported(field) || Modifier.isTransient(field.getModifiers());
        } catch (ObjectAccessException e) {
            return false;
        }
    }
    protected boolean fieldModifiersSupported(Field field) {
        return !(Modifier.isStatic(field.getModifiers())
                || Modifier.isTransient(field.getModifiers()));
    }
    protected void validateFieldAccess(Field field) {
        if (Modifier.isFinal(field.getModifiers())) {
            if (JVM.is15()) {
                field.setAccessible(true);
            } else {
                throw new ObjectAccessException("Invalid final field "
                        + field.getDeclaringClass().getName() + "." + field.getName());
            }
        }
    }
    public Field getField(Class definedIn, String fieldName) {
        return fieldDictionary.field(definedIn, fieldName, null);
    }
    public void setFieldDictionary(FieldDictionary dictionary) {
        this.fieldDictionary = dictionary;
    }
    protected Object readResolve() {
        serializedDataCache = Collections.synchronizedMap(new HashMap());
        return this;
    }
}

 
Need to append object class type to output xml
public abstract class AbstractReflectionConverter implements Converter {
     protected void doMarshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) {
        final Set seenFields = new HashSet();
        final Map defaultFieldDefinition = new HashMap();
        // Attributes might be preferred to child elements ...
         reflectionProvider.visitSerializableFields(source, new ReflectionProvider.Visitor() {
        ... ...   
        });
        // Child elements not covered already processed as attributes ...
        reflectionProvider.visitSerializableFields(source, new ReflectionProvider.Visitor() {
            ... ...
            private void writeField(String fieldName, String aliasName, Class fieldType, Class definedIn, Object newObj) {
                ... ...
                Field field = reflectionProvider.getField(definedIn,fieldName);
                writer.addAttribute("type", field.getType.getName);
                marshallField(context, newObj, field);
                writer.endNode();
            }
        });
    }
}

Comments

wang yibin
wang yibin
Software Engineer
北京
Article rating:
Your rating:

Categories

Based on community consensus.

Activity for this knol

This week:

22pageviews

Totals:

782pageviews