/* * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes. * Copyright (C) 2006, 2007, 2008 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. * * Created on 26. September 2003 by Joe Walnes */ 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.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; 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; import com.thoughtworks.xstream.converters.ConverterRegistry; import com.thoughtworks.xstream.converters.DataHolder; import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.SingleValueConverterWrapper; import com.thoughtworks.xstream.converters.basic.BigDecimalConverter; import com.thoughtworks.xstream.converters.basic.BigIntegerConverter; import com.thoughtworks.xstream.converters.basic.BooleanConverter; import com.thoughtworks.xstream.converters.basic.ByteConverter; import com.thoughtworks.xstream.converters.basic.CharConverter; import com.thoughtworks.xstream.converters.basic.DateConverter; import com.thoughtworks.xstream.converters.basic.DoubleConverter; import com.thoughtworks.xstream.converters.basic.FloatConverter; import com.thoughtworks.xstream.converters.basic.IntConverter; import com.thoughtworks.xstream.converters.basic.LongConverter; import com.thoughtworks.xstream.converters.basic.NullConverter; import com.thoughtworks.xstream.converters.basic.ShortConverter; import com.thoughtworks.xstream.converters.basic.StringBufferConverter; import com.thoughtworks.xstream.converters.basic.StringConverter; import com.thoughtworks.xstream.converters.basic.URLConverter; import com.thoughtworks.xstream.converters.collections.ArrayConverter; import com.thoughtworks.xstream.converters.collections.BitSetConverter; import com.thoughtworks.xstream.converters.collections.CharArrayConverter; import com.thoughtworks.xstream.converters.collections.CollectionConverter; import com.thoughtworks.xstream.converters.collections.MapConverter; import com.thoughtworks.xstream.converters.collections.PropertiesConverter; import com.thoughtworks.xstream.converters.collections.TreeMapConverter; import com.thoughtworks.xstream.converters.collections.TreeSetConverter; import com.thoughtworks.xstream.converters.extended.ColorConverter; import com.thoughtworks.xstream.converters.extended.DynamicProxyConverter; import com.thoughtworks.xstream.converters.extended.EncodedByteArrayConverter; import com.thoughtworks.xstream.converters.extended.FileConverter; import com.thoughtworks.xstream.converters.extended.FontConverter; import com.thoughtworks.xstream.converters.extended.GregorianCalendarConverter; import com.thoughtworks.xstream.converters.extended.JavaClassConverter; import com.thoughtworks.xstream.converters.extended.JavaMethodConverter; import com.thoughtworks.xstream.converters.extended.LocaleConverter; import com.thoughtworks.xstream.converters.extended.LookAndFeelConverter; import com.thoughtworks.xstream.converters.extended.SqlDateConverter; import com.thoughtworks.xstream.converters.extended.SqlTimeConverter; import com.thoughtworks.xstream.converters.extended.SqlTimestampConverter; import com.thoughtworks.xstream.converters.extended.TextAttributeConverter; import com.thoughtworks.xstream.converters.reflection.ExternalizableConverter; import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; import com.thoughtworks.xstream.converters.reflection.SelfStreamingInstanceChecker; import com.thoughtworks.xstream.converters.reflection.SerializableConverter; import com.thoughtworks.xstream.core.DefaultConverterLookup; import com.thoughtworks.xstream.core.JVM; import com.thoughtworks.xstream.core.MapBackedDataHolder; import com.thoughtworks.xstream.core.ReferenceByIdMarshallingStrategy; import com.thoughtworks.xstream.core.ReferenceByXPathMarshallingStrategy; import com.thoughtworks.xstream.core.TreeMarshallingStrategy; import com.thoughtworks.xstream.core.util.ClassLoaderReference; import com.thoughtworks.xstream.core.util.CompositeClassLoader; import com.thoughtworks.xstream.core.util.CustomObjectInputStream; import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.StatefulWriter; import com.thoughtworks.xstream.io.xml.XppDriver; import com.thoughtworks.xstream.mapper.AnnotationConfiguration; import com.thoughtworks.xstream.mapper.ArrayMapper; import com.thoughtworks.xstream.mapper.AttributeAliasingMapper; import com.thoughtworks.xstream.mapper.AttributeMapper; import com.thoughtworks.xstream.mapper.CachingMapper; import com.thoughtworks.xstream.mapper.ClassAliasingMapper; import com.thoughtworks.xstream.mapper.DefaultImplementationsMapper; import com.thoughtworks.xstream.mapper.DefaultMapper; import com.thoughtworks.xstream.mapper.DynamicProxyMapper; import com.thoughtworks.xstream.mapper.FieldAliasingMapper; import com.thoughtworks.xstream.mapper.ImmutableTypesMapper; import com.thoughtworks.xstream.mapper.ImplicitCollectionMapper; import com.thoughtworks.xstream.mapper.LocalConversionMapper; import com.thoughtworks.xstream.mapper.Mapper; import com.thoughtworks.xstream.mapper.MapperWrapper; import com.thoughtworks.xstream.mapper.OuterClassMapper; import com.thoughtworks.xstream.mapper.PackageAliasingMapper; import com.thoughtworks.xstream.mapper.SystemAttributeAliasingMapper; import com.thoughtworks.xstream.mapper.XStream11XmlFriendlyMapper; /** * Simple facade to XStream library, a Java-XML serialization tool. <p/> * <p> * <hr> * <b>Example</b><blockquote> * * <pre> * XStream xstream = new XStream(); * String xml = xstream.toXML(myObject); // serialize to XML * Object myObject2 = xstream.fromXML(xml); // deserialize from XML * </pre> * * </blockquote> * <hr> * <p/> * <h3>Aliasing classes</h3> * <p/> * <p> * To create shorter XML, you can specify aliases for classes using the <code>alias()</code> * method. For example, you can shorten all occurrences of element * <code><com.blah.MyThing></code> to <code><my-thing></code> by registering an * alias for the class. * <p> * <hr> * <blockquote> * * <pre> * xstream.alias("my-thing", MyThing.class); * </pre> * * </blockquote> * <hr> * <p/> * <h3>Converters</h3> * <p/> * <p> * XStream contains a map of {@link com.thoughtworks.xstream.converters.Converter} instances, each * of which acts as a strategy for converting a particular type of class to XML and back again. Out * of the box, XStream contains converters for most basic types (String, Date, int, boolean, etc) * and collections (Map, List, Set, Properties, etc). For other objects reflection is used to * serialize each field recursively. * </p> * <p/> * <p> * Extra converters can be registered using the <code>registerConverter()</code> method. Some * non-standard converters are supplied in the {@link com.thoughtworks.xstream.converters.extended} * package and you can create your own by implementing the * {@link com.thoughtworks.xstream.converters.Converter} interface. * </p> * <p/> * <p> * <hr> * <b>Example</b><blockquote> * * <pre> * xstream.registerConverter(new SqlTimestampConverter()); * xstream.registerConverter(new DynamicProxyConverter()); * </pre> * * </blockquote> * <hr> * <p> * The converters can be registered with an explicit priority. By default they are registered with * XStream.PRIORITY_NORMAL. Converters of same priority will be used in the reverse sequence * they have been registered. The default converter, i.e. the converter which will be used if * no other registered converter is suitable, can be registered with priority * XStream.PRIORITY_VERY_LOW. XStream uses by default the * {@link com.thoughtworks.xstream.converters.reflection.ReflectionConverter} as the fallback * converter. * </p> * <p/> * <p> * <hr> * <b>Example</b><blockquote> * * <pre> * xstream.registerConverter(new CustomDefaultConverter(), XStream.PRIORITY_VERY_LOW); * </pre> * * </blockquote> * <hr> * <p/> * <h3>Object graphs</h3> * <p/> * <p> * XStream has support for object graphs; a deserialized object graph will keep references intact, * including circular references. * </p> * <p/> * <p> * XStream can signify references in XML using either relative/absolute XPath or IDs. The mode can be changed using * <code>setMode()</code>: * </p> * <p/> * <table border='1'> * <tr> * <td><code>xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES);</code></td> * <td><i>(Default)</i> Uses XPath relative references to signify duplicate references. This produces XML * with the least clutter.</td> * </tr> * <tr> * <td><code>xstream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES);</code></td> * <td>Uses XPath absolute references to signify duplicate * references. This produces XML with the least clutter.</td> * </tr> * <tr> * <td><code>xstream.setMode(XStream.ID_REFERENCES);</code></td> * <td>Uses ID references to signify duplicate references. In some scenarios, such as when using * hand-written XML, this is easier to work with.</td> * </tr> * <tr> * <td><code>xstream.setMode(XStream.NO_REFERENCES);</code></td> * <td>This disables object graph support and treats the object structure like a tree. Duplicate * references are treated as two separate objects and circular references cause an exception. This * is slightly faster and uses less memory than the other two modes.</td> * </tr> * </table> * <h3>Thread safety</h3> * <p> * The XStream instance is thread-safe. That is, once the XStream instance has been created and * configured, it may be shared across multiple threads allowing objects to be * serialized/deserialized concurrently. <em>Note, that this only applies if annotations are not * auto-detected on -the-fly.</em> * </p> * <h3>Implicit collections</h3> * <p/> * <p> * To avoid the need for special tags for collections, you can define implicit collections using one * of the <code>addImplicitCollection</code> methods. * </p> * * @author Joe Walnes * @author Jörg Schaible * @author Mauro Talevi * @author Guilherme Silveira */ public class XStream { // CAUTION: The sequence of the fields is intentional for an optimal XML output of a // self-serialization! private ReflectionProvider reflectionProvider; private HierarchicalStreamDriver hierarchicalStreamDriver; private ClassLoaderReference classLoaderReference; private MarshallingStrategy marshallingStrategy; private ConverterLookup converterLookup; private ConverterRegistry converterRegistry; private Mapper mapper; private PackageAliasingMapper packageAliasingMapper; private ClassAliasingMapper classAliasingMapper; private FieldAliasingMapper fieldAliasingMapper; private AttributeAliasingMapper attributeAliasingMapper; private SystemAttributeAliasingMapper systemAttributeAliasingMapper; private AttributeMapper attributeMapper; private DefaultImplementationsMapper defaultImplementationsMapper; private ImmutableTypesMapper immutableTypesMapper; private ImplicitCollectionMapper implicitCollectionMapper; private LocalConversionMapper localConversionMapper; private AnnotationConfiguration annotationConfiguration; private transient JVM jvm = new JVM(); public static final int NO_REFERENCES = 1001; public static final int ID_REFERENCES = 1002; public static final int XPATH_RELATIVE_REFERENCES = 1003; public static final int XPATH_ABSOLUTE_REFERENCES = 1004; /** * @deprecated since 1.2, use {@link #XPATH_RELATIVE_REFERENCES} or * {@link #XPATH_ABSOLUTE_REFERENCES} instead. */ public static final int XPATH_REFERENCES = XPATH_RELATIVE_REFERENCES; public static final int PRIORITY_VERY_HIGH = 10000; public static final int PRIORITY_NORMAL = 0; public static final int PRIORITY_LOW = -10; public static final int PRIORITY_VERY_LOW = -20; private static final String ANNOTATION_MAPPER_TYPE = "com.thoughtworks.xstream.mapper.AnnotationMapper"; /** * Constructs a default XStream. The instance will use the {@link XppDriver} as default and tries to determine the best * match for the {@link ReflectionProvider} on its own. * * @throws InitializationException in case of an initialization problem */ public XStream() { this(null, (Mapper)null, new XppDriver()); } /** * Constructs an XStream with a special {@link ReflectionProvider}. The instance will use the {@link XppDriver} as default. * * @throws InitializationException in case of an initialization problem */ public XStream(ReflectionProvider reflectionProvider) { this(reflectionProvider, (Mapper)null, new XppDriver()); } /** * Constructs an XStream with a special {@link HierarchicalStreamDriver}. The instance will tries to determine the best * match for the {@link ReflectionProvider} on its own. * * @throws InitializationException in case of an initialization problem */ public XStream(HierarchicalStreamDriver hierarchicalStreamDriver) { this(null, (Mapper)null, hierarchicalStreamDriver); } /** * Constructs an XStream with a special {@link HierarchicalStreamDriver} and {@link ReflectionProvider}. * * @throws InitializationException in case of an initialization problem */ public XStream( ReflectionProvider reflectionProvider, HierarchicalStreamDriver hierarchicalStreamDriver) { this(reflectionProvider, (Mapper)null, hierarchicalStreamDriver); } /** * @deprecated As of 1.2, use * {@link #XStream(ReflectionProvider, Mapper, HierarchicalStreamDriver)} */ public XStream( ReflectionProvider reflectionProvider, ClassMapper classMapper, HierarchicalStreamDriver driver) { this(reflectionProvider, (Mapper)classMapper, driver); } /** * @deprecated As of 1.2, use * {@link #XStream(ReflectionProvider, Mapper, HierarchicalStreamDriver)} and * register classAttributeIdentifier as alias */ public XStream( ReflectionProvider reflectionProvider, ClassMapper classMapper, HierarchicalStreamDriver driver, String classAttributeIdentifier) { this(reflectionProvider, (Mapper)classMapper, driver); aliasAttribute(classAttributeIdentifier, "class"); } /** * Constructs an XStream with a special {@link HierarchicalStreamDriver} and {@link ReflectionProvider} and additionally with a prepared {@link Mapper}. * * @throws InitializationException in case of an initialization problem * @deprecated since 1.3, use {@link #XStream(ReflectionProvider, HierarchicalStreamDriver, Mapper, ClassLoader)} instead */ public XStream( ReflectionProvider reflectionProvider, Mapper mapper, HierarchicalStreamDriver driver) { this(reflectionProvider, driver, new ClassLoaderReference(new CompositeClassLoader()), mapper, new DefaultConverterLookup(), null); } /** * Constructs an XStream with a special {@link HierarchicalStreamDriver} and {@link ReflectionProvider} and additionally with a prepared * {@link ClassLoader} to use. * * @throws InitializationException in case of an initialization problem * @since 1.3 */ public XStream( ReflectionProvider reflectionProvider, HierarchicalStreamDriver driver, ClassLoader classLoader) { this(reflectionProvider, driver, classLoader, null); } /** * Constructs an XStream with a special {@link HierarchicalStreamDriver} and {@link ReflectionProvider} and additionally with a prepared {@link Mapper} * and the {@link ClassLoader} in use. * * <p>Note, if the class loader should be changed later again, you should provide a {@link ClassLoaderReference} as {@link ClassLoader} that is also * use in the {@link Mapper} chain.</p> * * @throws InitializationException in case of an initialization problem * @since 1.3 */ public XStream( ReflectionProvider reflectionProvider, HierarchicalStreamDriver driver, ClassLoader classLoader, Mapper mapper) { this(reflectionProvider, driver, classLoader, mapper, new DefaultConverterLookup(), null); } /** * Constructs an XStream with a special {@link HierarchicalStreamDriver}, {@link ReflectionProvider}, a prepared {@link Mapper} * and the {@link ClassLoader} in use and an own {@link ConverterRegistry}. * * <p>Note, if the class loader should be changed later again, you should provide a {@link ClassLoaderReference} as {@link ClassLoader} that is also * use in the {@link Mapper} chain.</p> * * @throws InitializationException in case of an initialization problem * @since 1.3 */ 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); } private Mapper buildMapper() { Mapper mapper = new DefaultMapper(classLoaderReference); if ( useXStream11XmlFriendlyMapper() ){ mapper = new XStream11XmlFriendlyMapper(mapper); } mapper = new DynamicProxyMapper(mapper); mapper = new PackageAliasingMapper(mapper); mapper = new ClassAliasingMapper(mapper); mapper = new FieldAliasingMapper(mapper); mapper = new AttributeAliasingMapper(mapper); mapper = new SystemAttributeAliasingMapper(mapper); mapper = new ImplicitCollectionMapper(mapper); mapper = new OuterClassMapper(mapper); mapper = new ArrayMapper(mapper); mapper = new DefaultImplementationsMapper(mapper); mapper = new AttributeMapper(mapper, converterLookup); // Android対応 if (JVM.is09()) { mapper = buildMapperDynamically( "com.thoughtworks.xstream.mapper.EnumMapper", new Class[]{Mapper.class}, new Object[]{mapper}); } mapper = new LocalConversionMapper(mapper); mapper = new ImmutableTypesMapper(mapper); // Android対応 if (JVM.is09()) { mapper = buildMapperDynamically( ANNOTATION_MAPPER_TYPE, new Class[]{Mapper.class, ConverterRegistry.class, ClassLoader.class, ReflectionProvider.class, JVM.class}, new Object[]{mapper, converterLookup, classLoaderReference, reflectionProvider, jvm}); } mapper = wrapMapper((MapperWrapper)mapper); mapper = new CachingMapper(mapper); return mapper; } private Mapper buildMapperDynamically( String className, Class[] constructorParamTypes, Object[] constructorParamValues) { try { Class type = Class.forName(className, false, classLoaderReference.getReference()); Constructor constructor = type.getConstructor(constructorParamTypes); return (Mapper)constructor.newInstance(constructorParamValues); } catch (Exception e) { throw new InitializationException("Could not instantiate mapper : " + className, e); } } protected MapperWrapper wrapMapper(MapperWrapper next) { return next; } protected boolean useXStream11XmlFriendlyMapper() { return false; } private void setupMappers() { packageAliasingMapper = (PackageAliasingMapper)this.mapper .lookupMapperOfType(PackageAliasingMapper.class); classAliasingMapper = (ClassAliasingMapper)this.mapper .lookupMapperOfType(ClassAliasingMapper.class); fieldAliasingMapper = (FieldAliasingMapper)this.mapper .lookupMapperOfType(FieldAliasingMapper.class); attributeMapper = (AttributeMapper)this.mapper.lookupMapperOfType(AttributeMapper.class); attributeAliasingMapper = (AttributeAliasingMapper)this.mapper .lookupMapperOfType(AttributeAliasingMapper.class); systemAttributeAliasingMapper = (SystemAttributeAliasingMapper)this.mapper .lookupMapperOfType(SystemAttributeAliasingMapper.class); implicitCollectionMapper = (ImplicitCollectionMapper)this.mapper .lookupMapperOfType(ImplicitCollectionMapper.class); defaultImplementationsMapper = (DefaultImplementationsMapper)this.mapper .lookupMapperOfType(DefaultImplementationsMapper.class); immutableTypesMapper = (ImmutableTypesMapper)this.mapper .lookupMapperOfType(ImmutableTypesMapper.class); localConversionMapper = (LocalConversionMapper)this.mapper .lookupMapperOfType(LocalConversionMapper.class); annotationConfiguration = (AnnotationConfiguration)this.mapper .lookupMapperOfType(AnnotationConfiguration.class); } protected void setupAliases() { if (classAliasingMapper == null) { return; } alias("null", Mapper.Null.class); alias("int", Integer.class); alias("float", Float.class); alias("double", Double.class); alias("long", Long.class); alias("short", Short.class); alias("char", Character.class); alias("byte", Byte.class); alias("boolean", Boolean.class); alias("number", Number.class); alias("object", Object.class); alias("big-int", BigInteger.class); alias("big-decimal", BigDecimal.class); alias("string-buffer", StringBuffer.class); alias("string", String.class); alias("java-class", Class.class); alias("method", Method.class); alias("constructor", Constructor.class); alias("date", Date.class); alias("url", URL.class); alias("bit-set", BitSet.class); alias("map", Map.class); alias("entry", Map.Entry.class); alias("properties", Properties.class); alias("list", List.class); alias("set", Set.class); alias("linked-list", LinkedList.class); alias("vector", Vector.class); alias("tree-map", TreeMap.class); alias("tree-set", TreeSet.class); alias("hashtable", Hashtable.class); if (jvm.supportsAWT()) { // Instantiating these two classes starts the AWT system, which is undesirable. // Calling loadClass ensures a reference to the class is found but they are not // instantiated. // alias("awt-color", jvm.loadClass("java.awt.Color")); // alias("awt-font", jvm.loadClass("java.awt.Font")); // alias("awt-text-attribute", jvm.loadClass("java.awt.font.TextAttribute")); } if (jvm.supportsSQL()) { alias("sql-timestamp", jvm.loadClass("java.sql.Timestamp")); alias("sql-time", jvm.loadClass("java.sql.Time")); alias("sql-date", jvm.loadClass("java.sql.Date")); } alias("file", File.class); alias("locale", Locale.class); alias("gregorian-calendar", Calendar.class); if (JVM.is14()) { alias("auth-subject", jvm.loadClass("javax.security.auth.Subject")); alias("linked-hash-map", jvm.loadClass("java.util.LinkedHashMap")); alias("linked-hash-set", jvm.loadClass("java.util.LinkedHashSet")); alias("trace", jvm.loadClass("java.lang.StackTraceElement")); alias("currency", jvm.loadClass("java.util.Currency")); aliasType("charset", jvm.loadClass("java.nio.charset.Charset")); } // Android対応 if (JVM.is09()) { // alias("duration", jvm.loadClass("javax.xml.datatype.Duration")); alias("enum-set", jvm.loadClass("java.util.EnumSet")); alias("enum-map", jvm.loadClass("java.util.EnumMap")); alias("string-builder", jvm.loadClass("java.lang.StringBuilder")); alias("uuid", jvm.loadClass("java.util.UUID")); } } protected void setupDefaultImplementations() { if (defaultImplementationsMapper == null) { return; } addDefaultImplementation(HashMap.class, Map.class); addDefaultImplementation(ArrayList.class, List.class); addDefaultImplementation(HashSet.class, Set.class); addDefaultImplementation(GregorianCalendar.class, Calendar.class); } protected void setupConverters() { final ReflectionConverter reflectionConverter = new ReflectionConverter(mapper, reflectionProvider); registerConverter(reflectionConverter, PRIORITY_VERY_LOW); registerConverter(new SerializableConverter(mapper, reflectionProvider), PRIORITY_LOW); registerConverter(new ExternalizableConverter(mapper), PRIORITY_LOW); registerConverter(new NullConverter(), PRIORITY_VERY_HIGH); registerConverter(new IntConverter(), PRIORITY_NORMAL); registerConverter(new FloatConverter(), PRIORITY_NORMAL); registerConverter(new DoubleConverter(), PRIORITY_NORMAL); registerConverter(new LongConverter(), PRIORITY_NORMAL); registerConverter(new ShortConverter(), PRIORITY_NORMAL); registerConverter((Converter)new CharConverter(), PRIORITY_NORMAL); registerConverter(new BooleanConverter(), PRIORITY_NORMAL); registerConverter(new ByteConverter(), PRIORITY_NORMAL); registerConverter(new StringConverter(), PRIORITY_NORMAL); registerConverter(new StringBufferConverter(), PRIORITY_NORMAL); registerConverter(new DateConverter(), PRIORITY_NORMAL); registerConverter(new BitSetConverter(), PRIORITY_NORMAL); registerConverter(new URLConverter(), PRIORITY_NORMAL); registerConverter(new BigIntegerConverter(), PRIORITY_NORMAL); registerConverter(new BigDecimalConverter(), PRIORITY_NORMAL); registerConverter(new ArrayConverter(mapper), PRIORITY_NORMAL); registerConverter(new CharArrayConverter(), PRIORITY_NORMAL); registerConverter(new CollectionConverter(mapper), PRIORITY_NORMAL); registerConverter(new MapConverter(mapper), PRIORITY_NORMAL); registerConverter(new TreeMapConverter(mapper), PRIORITY_NORMAL); registerConverter(new TreeSetConverter(mapper), PRIORITY_NORMAL); registerConverter(new PropertiesConverter(), PRIORITY_NORMAL); registerConverter(new EncodedByteArrayConverter(), PRIORITY_NORMAL); registerConverter(new FileConverter(), PRIORITY_NORMAL); if(jvm.supportsSQL()) { registerConverter(new SqlTimestampConverter(), PRIORITY_NORMAL); registerConverter(new SqlTimeConverter(), PRIORITY_NORMAL); registerConverter(new SqlDateConverter(), PRIORITY_NORMAL); } registerConverter(new DynamicProxyConverter(mapper, classLoaderReference), PRIORITY_NORMAL); registerConverter(new JavaClassConverter(classLoaderReference), PRIORITY_NORMAL); registerConverter(new JavaMethodConverter(classLoaderReference), PRIORITY_NORMAL); if(jvm.supportsAWT()) { registerConverter(new FontConverter(), PRIORITY_NORMAL); registerConverter(new ColorConverter(), PRIORITY_NORMAL); registerConverter(new TextAttributeConverter(), PRIORITY_NORMAL); } if(jvm.supportsSwing()) { registerConverter(new LookAndFeelConverter(mapper, reflectionProvider), PRIORITY_NORMAL); } registerConverter(new LocaleConverter(), PRIORITY_NORMAL); registerConverter(new GregorianCalendarConverter(), PRIORITY_NORMAL); if (JVM.is14()) { // late bound converters - allows XStream to be compiled on earlier JDKs dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.extended.SubjectConverter", PRIORITY_NORMAL, new Class[]{Mapper.class}, new Object[]{mapper}); dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.extended.ThrowableConverter", PRIORITY_NORMAL, new Class[]{Converter.class}, new Object[]{reflectionConverter}); dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.extended.StackTraceElementConverter", PRIORITY_NORMAL, null, null); dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.extended.CurrencyConverter", PRIORITY_NORMAL, null, null); dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.extended.RegexPatternConverter", PRIORITY_NORMAL, new Class[]{Converter.class}, new Object[]{reflectionConverter}); dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.extended.CharsetConverter", PRIORITY_NORMAL, null, null); } // Android対応 if (JVM.is09()) { // late bound converters - allows XStream to be compiled on earlier JDKs dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.extended.DurationConverter", PRIORITY_NORMAL, null, null); dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.enums.EnumConverter", PRIORITY_NORMAL, null, null); dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.enums.EnumSetConverter", PRIORITY_NORMAL, new Class[]{Mapper.class}, new Object[]{mapper}); dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.enums.EnumMapConverter", PRIORITY_NORMAL, new Class[]{Mapper.class}, new Object[]{mapper}); dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.basic.StringBuilderConverter", PRIORITY_NORMAL, null, null); dynamicallyRegisterConverter( "com.thoughtworks.xstream.converters.basic.UUIDConverter", PRIORITY_NORMAL, null, null); } registerConverter(new SelfStreamingInstanceChecker(reflectionConverter, this), PRIORITY_NORMAL); } private void dynamicallyRegisterConverter( String className, int priority, Class[] constructorParamTypes, Object[] constructorParamValues) { try { Class type = Class.forName(className, false, classLoaderReference.getReference()); Constructor constructor = type.getConstructor(constructorParamTypes); Object instance = constructor.newInstance(constructorParamValues); if (instance instanceof Converter) { registerConverter((Converter)instance, priority); } else if (instance instanceof SingleValueConverter) { registerConverter((SingleValueConverter)instance, priority); } } catch (Exception e) { throw new InitializationException("Could not instantiate converter : " + className, e); } } protected void setupImmutableTypes() { if (immutableTypesMapper == null) { return; } // primitives are always immutable addImmutableType(boolean.class); addImmutableType(Boolean.class); addImmutableType(byte.class); addImmutableType(Byte.class); addImmutableType(char.class); addImmutableType(Character.class); addImmutableType(double.class); addImmutableType(Double.class); addImmutableType(float.class); addImmutableType(Float.class); addImmutableType(int.class); addImmutableType(Integer.class); addImmutableType(long.class); addImmutableType(Long.class); addImmutableType(short.class); addImmutableType(Short.class); // additional types addImmutableType(Mapper.Null.class); addImmutableType(BigDecimal.class); addImmutableType(BigInteger.class); addImmutableType(String.class); addImmutableType(URL.class); addImmutableType(File.class); addImmutableType(Class.class); if(jvm.supportsAWT()) { // addImmutableType(jvm.loadClass("java.awt.font.TextAttribute")); } if (JVM.is14()) { // late bound types - allows XStream to be compiled on earlier JDKs Class type = jvm.loadClass("com.thoughtworks.xstream.converters.extended.CharsetConverter"); addImmutableType(type); } } public void setMarshallingStrategy(MarshallingStrategy marshallingStrategy) { this.marshallingStrategy = marshallingStrategy; } /** * Serialize an object to a pretty-printed XML String. * @throws XStreamException if the object cannot be serialized */ public String toXML(Object obj) { Writer writer = new StringWriter(); toXML(obj, writer); return writer.toString(); } /** * Serialize an object to the given Writer as pretty-printed XML. * The Writer will be flushed afterwards and in case of an exception. * @throws XStreamException if the object cannot be serialized */ public void toXML(Object obj, Writer out) { HierarchicalStreamWriter writer = hierarchicalStreamDriver.createWriter(out); try { marshal(obj, writer); } finally { writer.flush(); } } /** * Serialize an object to the given OutputStream as pretty-printed XML. * The OutputStream will be flushed afterwards and in case of an exception. * @throws XStreamException if the object cannot be serialized */ public void toXML(Object obj, OutputStream out) { HierarchicalStreamWriter writer = hierarchicalStreamDriver.createWriter(out); try { marshal(obj, writer); } finally { writer.flush(); } } /** * Serialize and object to a hierarchical data structure (such as XML). * @throws XStreamException if the object cannot be serialized */ public void marshal(Object obj, HierarchicalStreamWriter writer) { marshal(obj, writer, null); } /** * Serialize and object to a hierarchical data structure (such as XML). * * @param dataHolder Extra data you can use to pass to your converters. Use this as you want. If * not present, XStream shall create one lazily as needed. * @throws XStreamException if the object cannot be serialized */ public void marshal(Object obj, HierarchicalStreamWriter writer, DataHolder dataHolder) { marshallingStrategy.marshal(writer, obj, converterLookup, mapper, dataHolder); } /** * Deserialize an object from an XML String. * @throws XStreamException if the object cannot be deserialized */ public Object fromXML(String xml) { return fromXML(new StringReader(xml)); } /** * Deserialize an object from an XML Reader. * @throws XStreamException if the object cannot be deserialized */ public Object fromXML(Reader xml) { return unmarshal(hierarchicalStreamDriver.createReader(xml), null); } /** * Deserialize an object from an XML InputStream. * @throws XStreamException if the object cannot be deserialized */ public Object fromXML(InputStream input) { return unmarshal(hierarchicalStreamDriver.createReader(input), null); } /** * Deserialize an object from an XML String, populating the fields of the given root object * instead of instantiating a new one. Note, that this is a special use case! With the ReflectionConverter * XStream will write directly into the raw memory area of the existing object. Use with care! * @throws XStreamException if the object cannot be deserialized */ public Object fromXML(String xml, Object root) { return fromXML(new StringReader(xml), root); } /** * Deserialize an object from an XML Reader, populating the fields of the given root object * instead of instantiating a new one. Note, that this is a special use case! With the ReflectionConverter * XStream will write directly into the raw memory area of the existing object. Use with care! * @throws XStreamException if the object cannot be deserialized */ public Object fromXML(Reader xml, Object root) { return unmarshal(hierarchicalStreamDriver.createReader(xml), root); } /** * Deserialize an object from an XML InputStream, populating the fields of the given root object * instead of instantiating a new one. Note, that this is a special use case! With the ReflectionConverter * XStream will write directly into the raw memory area of the existing object. Use with care! * @throws XStreamException if the object cannot be deserialized */ public Object fromXML(InputStream xml, Object root) { return unmarshal(hierarchicalStreamDriver.createReader(xml), root); } /** * Deserialize an object from a hierarchical data structure (such as XML). * @throws XStreamException if the object cannot be deserialized */ public Object unmarshal(HierarchicalStreamReader reader) { return unmarshal(reader, null, null); } /** * Deserialize an object from a hierarchical data structure (such as XML), populating the fields * of the given root object instead of instantiating a new one. Note, that this is a special use case! With the ReflectionConverter * XStream will write directly into the raw memory area of the existing object. Use with care! * @throws XStreamException if the object cannot be deserialized */ public Object unmarshal(HierarchicalStreamReader reader, Object root) { return unmarshal(reader, root, null); } /** * Deserialize an object from a hierarchical data structure (such as XML). * * @param root If present, the passed in object will have its fields populated, as opposed to * XStream creating a new instance. Note, that this is a special use case! With the ReflectionConverter * XStream will write directly into the raw memory area of the existing object. Use with care! * @param dataHolder Extra data you can use to pass to your converters. Use this as you want. If * not present, XStream shall create one lazily as needed. * @throws XStreamException if the object cannot be deserialized */ public Object unmarshal(HierarchicalStreamReader reader, Object root, DataHolder dataHolder) { return marshallingStrategy.unmarshal(root, reader, dataHolder, converterLookup, mapper); } /** * Alias a Class to a shorter name to be used in XML elements. * * @param name Short name * @param type Type to be aliased * @throws InitializationException if no {@link ClassAliasingMapper} is available */ public void alias(String name, Class type) { if (classAliasingMapper == null) { throw new InitializationException("No " + ClassAliasingMapper.class.getName() + " available"); } classAliasingMapper.addClassAlias(name, type); } /** * Alias a type to a shorter name to be used in XML elements. * Any class that is assignable to this type will be aliased to the same name. * * @param name Short name * @param type Type to be aliased * @since 1.2 * @throws InitializationException if no {@link ClassAliasingMapper} is available */ public void aliasType(String name, Class type) { if (classAliasingMapper == null) { throw new InitializationException("No " + ClassAliasingMapper.class.getName() + " available"); } classAliasingMapper.addTypeAlias(name, type); } /** * Alias a Class to a shorter name to be used in XML elements. * * @param name Short name * @param type Type to be aliased * @param defaultImplementation Default implementation of type to use if no other specified. * @throws InitializationException if no {@link DefaultImplementationsMapper} or no {@link ClassAliasingMapper} is available */ public void alias(String name, Class type, Class defaultImplementation) { alias(name, type); addDefaultImplementation(defaultImplementation, type); } /** * Alias a package to a shorter name to be used in XML elements. * * @param name Short name * @param pkgName package to be aliased * @throws InitializationException if no {@link DefaultImplementationsMapper} or no {@link PackageAliasingMapper} is available * @since 1.3.1 */ public void aliasPackage(String name, String pkgName) { if (packageAliasingMapper == null) { throw new InitializationException("No " + PackageAliasingMapper.class.getName() + " available"); } packageAliasingMapper.addPackageAlias(name, pkgName); } /** * Create an alias for a field name. * * @param alias the alias itself * @param definedIn the type that declares the field * @param fieldName the name of the field * @throws InitializationException if no {@link FieldAliasingMapper} is available */ public void aliasField(String alias, Class definedIn, String fieldName) { if (fieldAliasingMapper == null) { throw new InitializationException("No " + FieldAliasingMapper.class.getName() + " available"); } fieldAliasingMapper.addFieldAlias(alias, definedIn, fieldName); } /** * Create an alias for an attribute * * @param alias the alias itself * @param attributeName the name of the attribute * @throws InitializationException if no {@link AttributeAliasingMapper} is available */ public void aliasAttribute(String alias, String attributeName) { if (attributeAliasingMapper == null) { throw new InitializationException("No " + AttributeAliasingMapper.class.getName() + " available"); } attributeAliasingMapper.addAliasFor(attributeName, alias); } /** * Create an alias for a system attribute. * * XStream will not write a system attribute if its alias is set to <code>null</code>. However, * this is not reversible, i.e. deserialization of the result is likely to fail afterwards and will not * produce an object equal to the originally written one. * * @param alias the alias itself (may be <code>null</code>) * @param systemAttributeName the name of the system attribute * @throws InitializationException if no {@link SystemAttributeAliasingMapper} is available * @since 1.3.1 */ public void aliasSystemAttribute(String alias, String systemAttributeName) { if (systemAttributeAliasingMapper == null) { throw new InitializationException("No " + SystemAttributeAliasingMapper.class.getName() + " available"); } systemAttributeAliasingMapper.addAliasFor(systemAttributeName, alias); } /** * Create an alias for an attribute. * * @param definedIn the type where the attribute is defined * @param attributeName the name of the attribute * @param alias the alias itself * @throws InitializationException if no {@link AttributeAliasingMapper} is available * @since 1.2.2 */ public void aliasAttribute(Class definedIn, String attributeName, String alias) { aliasField(alias, definedIn, attributeName); useAttributeFor(definedIn, attributeName); } /** * Use an attribute for a field or a specific type. * * @param fieldName the name of the field * @param type the Class of the type to be rendered as XML attribute * @throws InitializationException if no {@link AttributeMapper} is available * @since 1.2 */ public void useAttributeFor(String fieldName, Class type) { if (attributeMapper == null) { throw new InitializationException("No " + AttributeMapper.class.getName() + " available"); } attributeMapper.addAttributeFor(fieldName, type); } /** * Use an attribute for a field declared in a specific type. * * @param fieldName the name of the field * @param definedIn the Class containing such field * @throws InitializationException if no {@link AttributeMapper} is available * @since 1.2.2 */ public void useAttributeFor(Class definedIn, String fieldName) { if (attributeMapper == null) { throw new InitializationException("No " + AttributeMapper.class.getName() + " available"); } attributeMapper.addAttributeFor(definedIn, fieldName); } /** * Use an attribute for an arbitrary type. * * @param type the Class of the type to be rendered as XML attribute * @throws InitializationException if no {@link AttributeMapper} is available * @since 1.2 */ public void useAttributeFor(Class type) { if (attributeMapper == null) { throw new InitializationException("No " + AttributeMapper.class.getName() + " available"); } attributeMapper.addAttributeFor(type); } /** * Associate a default implementation of a class with an object. Whenever XStream encounters an * instance of this type, it will use the default implementation instead. For example, * java.util.ArrayList is the default implementation of java.util.List. * * @param defaultImplementation * @param ofType * @throws InitializationException if no {@link DefaultImplementationsMapper} is available */ public void addDefaultImplementation(Class defaultImplementation, Class ofType) { if (defaultImplementationsMapper == null) { throw new InitializationException("No " + DefaultImplementationsMapper.class.getName() + " available"); } defaultImplementationsMapper.addDefaultImplementation(defaultImplementation, ofType); } /** * Add immutable types. The value of the instances of these types will always be written into * the stream even if they appear multiple times. * @throws InitializationException if no {@link ImmutableTypesMapper} is available */ public void addImmutableType(Class type) { if (immutableTypesMapper == null) { throw new InitializationException("No " + ImmutableTypesMapper.class.getName() + " available"); } immutableTypesMapper.addImmutableType(type); } public void registerConverter(Converter converter) { registerConverter(converter, PRIORITY_NORMAL); } public void registerConverter(Converter converter, int priority) { if (converterRegistry != null) { converterRegistry.registerConverter(converter, priority); } } public void registerConverter(SingleValueConverter converter) { registerConverter(converter, PRIORITY_NORMAL); } public void registerConverter(SingleValueConverter converter, int priority) { if (converterRegistry != null) { converterRegistry.registerConverter(new SingleValueConverterWrapper(converter), priority); } } /** * Register a local {@link Converter} for a field. * * @param definedIn the class type the field is defined in * @param fieldName the field name * @param converter the converter to use * @since 1.3 */ public void registerLocalConverter(Class definedIn, String fieldName, Converter converter) { if (localConversionMapper == null) { throw new InitializationException("No " + LocalConversionMapper.class.getName() + " available"); } localConversionMapper.registerLocalConverter(definedIn, fieldName, converter); } /** * Register a local {@link SingleValueConverter} for a field. * * @param definedIn the class type the field is defined in * @param fieldName the field name * @param converter the converter to use * @since 1.3 */ public void registerLocalConverter(Class definedIn, String fieldName, SingleValueConverter converter) { registerLocalConverter(definedIn, fieldName, (Converter)new SingleValueConverterWrapper(converter)); } /** * @throws ClassCastException if mapper is not really a deprecated {@link ClassMapper} instance * @deprecated As of 1.2, use {@link #getMapper} */ public ClassMapper getClassMapper() { if (mapper instanceof ClassMapper) { return (ClassMapper)mapper; } else { return (ClassMapper)Proxy.newProxyInstance(getClassLoader(), new Class[]{ClassMapper.class}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(mapper, args); } }); } } /** * Retrieve the {@link Mapper}. This is by default a chain of {@link MapperWrapper MapperWrappers}. * * @return the mapper * @since 1.2 */ public Mapper getMapper() { return mapper; } /** * Retrieve the {@link ReflectionProvider} in use. * * @return the mapper * @since 1.2.1 */ public ReflectionProvider getReflectionProvider() { return reflectionProvider; } public ConverterLookup getConverterLookup() { return converterLookup; } /** * Change mode for dealing with duplicate references. Valid values are * <code>XPATH_ABSOLUTE_REFERENCES</code>, <code>XPATH_RELATIVE_REFERENCES</code>, * <code>XStream.ID_REFERENCES</code> and <code>XStream.NO_REFERENCES</code>. * * @throws IllegalArgumentException if the mode is not one of the declared types * @see #XPATH_ABSOLUTE_REFERENCES * @see #XPATH_RELATIVE_REFERENCES * @see #ID_REFERENCES * @see #NO_REFERENCES */ public void setMode(int mode) { switch (mode) { case NO_REFERENCES: setMarshallingStrategy(new TreeMarshallingStrategy()); break; case ID_REFERENCES: setMarshallingStrategy(new ReferenceByIdMarshallingStrategy()); break; 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); } } /** * Adds a default implicit collection which is used for any unmapped XML tag. * * @param ownerType class owning the implicit collection * @param fieldName name of the field in the ownerType. This field must be a * concrete collection type or matching the default implementation type of the * collection type. */ public void addImplicitCollection(Class ownerType, String fieldName) { if (implicitCollectionMapper == null) { throw new InitializationException("No " + ImplicitCollectionMapper.class.getName() + " available"); } implicitCollectionMapper.add(ownerType, fieldName, null, null); } /** * Adds implicit collection which is used for all items of the given itemType. * * @param ownerType class owning the implicit collection * @param fieldName name of the field in the ownerType. This field must be a * concrete collection type or matching the default implementation type of the * collection type. * @param itemType type of the items to be part of this collection. * @throws InitializationException if no {@link ImplicitCollectionMapper} is available */ public void addImplicitCollection(Class ownerType, String fieldName, Class itemType) { if (implicitCollectionMapper == null) { throw new InitializationException("No " + ImplicitCollectionMapper.class.getName() + " available"); } implicitCollectionMapper.add(ownerType, fieldName, null, itemType); } /** * Adds implicit collection which is used for all items of the given element name defined by * itemFieldName. * * @param ownerType class owning the implicit collection * @param fieldName name of the field in the ownerType. This field must be a * concrete collection type or matching the default implementation type of the * collection type. * @param itemFieldName element name of the implicit collection * @param itemType item type to be aliases be the itemFieldName * @throws InitializationException if no {@link ImplicitCollectionMapper} is available */ public void addImplicitCollection( Class ownerType, String fieldName, String itemFieldName, Class itemType) { if (implicitCollectionMapper == null) { throw new InitializationException("No " + ImplicitCollectionMapper.class.getName() + " available"); } implicitCollectionMapper.add(ownerType, fieldName, itemFieldName, itemType); } /** * Create a DataHolder that can be used to pass data to the converters. The DataHolder is provided with a * call to {@link #marshal(Object, HierarchicalStreamWriter, DataHolder)} or * {@link #unmarshal(HierarchicalStreamReader, Object, DataHolder)}. * * @return a new {@link DataHolder} */ public DataHolder newDataHolder() { return new MapBackedDataHolder(); } /** * Creates an ObjectOutputStream that serializes a stream of objects to the writer using * XStream. * <p> * To change the name of the root element (from <object-stream>), use * {@link #createObjectOutputStream(java.io.Writer, String)}. * </p> * * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.0.3 */ public ObjectOutputStream createObjectOutputStream(Writer writer) throws IOException { return createObjectOutputStream(hierarchicalStreamDriver.createWriter(writer), "object-stream"); } /** * Creates an ObjectOutputStream that serializes a stream of objects to the writer using * XStream. * <p> * To change the name of the root element (from <object-stream>), use * {@link #createObjectOutputStream(java.io.Writer, String)}. * </p> * * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.0.3 */ public ObjectOutputStream createObjectOutputStream(HierarchicalStreamWriter writer) throws IOException { return createObjectOutputStream(writer, "object-stream"); } /** * Creates an ObjectOutputStream that serializes a stream of objects to the writer using * XStream. * * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.0.3 */ public ObjectOutputStream createObjectOutputStream(Writer writer, String rootNodeName) throws IOException { return createObjectOutputStream(hierarchicalStreamDriver.createWriter(writer), rootNodeName); } /** * Creates an ObjectOutputStream that serializes a stream of objects to the OutputStream using * XStream. * <p> * To change the name of the root element (from <object-stream>), use * {@link #createObjectOutputStream(java.io.Writer, String)}. * </p> * * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.3 */ public ObjectOutputStream createObjectOutputStream(OutputStream out) throws IOException { return createObjectOutputStream(hierarchicalStreamDriver.createWriter(out), "object-stream"); } /** * Creates an ObjectOutputStream that serializes a stream of objects to the OutputStream using * XStream. * * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.3 */ public ObjectOutputStream createObjectOutputStream(OutputStream out, String rootNodeName) throws IOException { return createObjectOutputStream(hierarchicalStreamDriver.createWriter(out), rootNodeName); } /** * Creates an ObjectOutputStream that serializes a stream of objects to the writer using * XStream. * <p> * Because an ObjectOutputStream can contain multiple items and XML only allows a single root * node, the stream must be written inside an enclosing node. * </p> * <p> * It is necessary to call ObjectOutputStream.close() when done, otherwise the stream will be * incomplete. * </p> * <h3>Example</h3> * * <pre> * ObjectOutputStream out = xstream.createObjectOutputStream(aWriter, "things"); * out.writeInt(123); * out.writeObject("Hello"); * out.writeObject(someObject) * out.close(); * </pre> * * @param writer The writer to serialize the objects to. * @param rootNodeName The name of the root node enclosing the stream of objects. * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.0.3 */ public ObjectOutputStream createObjectOutputStream( final HierarchicalStreamWriter writer, String rootNodeName) throws IOException { final StatefulWriter statefulWriter = new StatefulWriter(writer); statefulWriter.startNode(rootNodeName, null); return new CustomObjectOutputStream(new CustomObjectOutputStream.StreamCallback() { public void writeToStream(Object object) { marshal(object, statefulWriter); } public void writeFieldsToStream(Map fields) throws NotActiveException { throw new NotActiveException("not in call to writeObject"); } public void defaultWriteObject() throws NotActiveException { throw new NotActiveException("not in call to writeObject"); } public void flush() { statefulWriter.flush(); } public void close() { if (statefulWriter.state() != StatefulWriter.STATE_CLOSED) { statefulWriter.endNode(); statefulWriter.close(); } } }); } /** * Creates an ObjectInputStream that deserializes a stream of objects from a reader using * XStream. * * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) * @since 1.0.3 */ public ObjectInputStream createObjectInputStream(Reader xmlReader) throws IOException { return createObjectInputStream(hierarchicalStreamDriver.createReader(xmlReader)); } /** * Creates an ObjectInputStream that deserializes a stream of objects from an InputStream using * XStream. * * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) * @since 1.3 */ public ObjectInputStream createObjectInputStream(InputStream in) throws IOException { return createObjectInputStream(hierarchicalStreamDriver.createReader(in)); } /** * Creates an ObjectInputStream that deserializes a stream of objects from a reader using * XStream. * <h3>Example</h3> * * <pre> * ObjectInputStream in = xstream.createObjectOutputStream(aReader); * int a = out.readInt(); * Object b = out.readObject(); * Object c = out.readObject(); * </pre> * * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) * @since 1.0.3 */ public ObjectInputStream createObjectInputStream(final HierarchicalStreamReader reader) throws IOException { return new CustomObjectInputStream(new CustomObjectInputStream.StreamCallback() { public Object readFromStream() throws EOFException { if (!reader.hasMoreChildren()) { throw new EOFException(); } reader.moveDown(); Object result = unmarshal(reader); reader.moveUp(); return result; } public Map readFieldsFromStream() throws IOException { throw new NotActiveException("not in call to readObject"); } public void defaultReadObject() throws NotActiveException { throw new NotActiveException("not in call to readObject"); } public void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException { throw new NotActiveException("stream inactive"); } public void close() { reader.close(); } }); } /** * Change the ClassLoader XStream uses to load classes. * * Creating an XStream instance it will register for all kind of classes and types of the current JDK, * but not for any 3rd party type. To ensure that all other types are loaded with your classloader, * you should call this method as early as possible - or consider to provide the classloader directly * in the constructor. * * @since 1.1.1 */ public void setClassLoader(ClassLoader classLoader) { classLoaderReference.setReference(classLoader); } /** * Retrieve the ClassLoader XStream uses to load classes. * * @since 1.1.1 */ public ClassLoader getClassLoader() { return classLoaderReference.getReference(); } /** * Prevents a field from being serialized. To omit a field you must always provide the declaring * type and not necessarily the type that is converted. * * @since 1.1.3 * @throws InitializationException if no {@link FieldAliasingMapper} is available */ public void omitField(Class definedIn, String fieldName) { if (fieldAliasingMapper == null) { throw new InitializationException("No " + FieldAliasingMapper.class.getName() + " available"); } fieldAliasingMapper.omitField(definedIn, fieldName); } /** * Process the annotations of the given types and configure the XStream. * * @param types the types with XStream annotations * @since 1.3 */ public void processAnnotations(final Class[] types) { if (annotationConfiguration == null) { throw new InitializationException("No " + ANNOTATION_MAPPER_TYPE + " available"); } annotationConfiguration.processAnnotations(types); } /** * Process the annotations of the given type and configure the XStream. A call of this method * will automatically turn the auto-detection mode for annotations off. * * @param type the type with XStream annotations * @since 1.3 */ public void processAnnotations(final Class type) { processAnnotations(new Class[]{type}); } /** * Set the auto-detection mode of the AnnotationMapper. Note that auto-detection implies that * the XStream is configured while it is processing the XML steams. This is a potential concurrency * problem. Also is it technically not possible to detect all class aliases at deserialization. You have * been warned! * * @param mode <code>true</code> if annotations are auto-detected * @since 1.3 */ public void autodetectAnnotations(boolean mode) { if (annotationConfiguration != null) { annotationConfiguration.autodetectAnnotations(mode); } } /** * @deprecated since 1.3, use {@link InitializationException} instead */ public static class InitializationException extends XStreamException { public InitializationException(String message, Throwable cause) { super(message, cause); } public InitializationException(String message) { super(message); } } private Object readResolve() { jvm = new JVM(); return this; } }