0001: /*
0002: * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes.
0003: * Copyright (C) 2006, 2007, 2008 XStream Committers.
0004: * All rights reserved.
0005: *
0006: * The software in this package is published under the terms of the BSD
0007: * style license a copy of which has been included with this distribution in
0008: * the LICENSE.txt file.
0009: *
0010: * Created on 26. September 2003 by Joe Walnes
0011: */
0012: package com.thoughtworks.xstream;
0013:
0014: import com.thoughtworks.xstream.alias.ClassMapper;
0015: import com.thoughtworks.xstream.converters.Converter;
0016: import com.thoughtworks.xstream.converters.ConverterLookup;
0017: import com.thoughtworks.xstream.converters.ConverterRegistry;
0018: import com.thoughtworks.xstream.converters.DataHolder;
0019: import com.thoughtworks.xstream.converters.SingleValueConverter;
0020: import com.thoughtworks.xstream.converters.SingleValueConverterWrapper;
0021: import com.thoughtworks.xstream.converters.basic.BigDecimalConverter;
0022: import com.thoughtworks.xstream.converters.basic.BigIntegerConverter;
0023: import com.thoughtworks.xstream.converters.basic.BooleanConverter;
0024: import com.thoughtworks.xstream.converters.basic.ByteConverter;
0025: import com.thoughtworks.xstream.converters.basic.CharConverter;
0026: import com.thoughtworks.xstream.converters.basic.DateConverter;
0027: import com.thoughtworks.xstream.converters.basic.DoubleConverter;
0028: import com.thoughtworks.xstream.converters.basic.FloatConverter;
0029: import com.thoughtworks.xstream.converters.basic.IntConverter;
0030: import com.thoughtworks.xstream.converters.basic.LongConverter;
0031: import com.thoughtworks.xstream.converters.basic.NullConverter;
0032: import com.thoughtworks.xstream.converters.basic.ShortConverter;
0033: import com.thoughtworks.xstream.converters.basic.StringBufferConverter;
0034: import com.thoughtworks.xstream.converters.basic.StringConverter;
0035: import com.thoughtworks.xstream.converters.basic.URLConverter;
0036: import com.thoughtworks.xstream.converters.collections.ArrayConverter;
0037: import com.thoughtworks.xstream.converters.collections.BitSetConverter;
0038: import com.thoughtworks.xstream.converters.collections.CharArrayConverter;
0039: import com.thoughtworks.xstream.converters.collections.CollectionConverter;
0040: import com.thoughtworks.xstream.converters.collections.MapConverter;
0041: import com.thoughtworks.xstream.converters.collections.PropertiesConverter;
0042: import com.thoughtworks.xstream.converters.collections.TreeMapConverter;
0043: import com.thoughtworks.xstream.converters.collections.TreeSetConverter;
0044: import com.thoughtworks.xstream.converters.extended.ColorConverter;
0045: import com.thoughtworks.xstream.converters.extended.DynamicProxyConverter;
0046: import com.thoughtworks.xstream.converters.extended.EncodedByteArrayConverter;
0047: import com.thoughtworks.xstream.converters.extended.FileConverter;
0048: import com.thoughtworks.xstream.converters.extended.FontConverter;
0049: import com.thoughtworks.xstream.converters.extended.GregorianCalendarConverter;
0050: import com.thoughtworks.xstream.converters.extended.JavaClassConverter;
0051: import com.thoughtworks.xstream.converters.extended.JavaMethodConverter;
0052: import com.thoughtworks.xstream.converters.extended.LocaleConverter;
0053: import com.thoughtworks.xstream.converters.extended.LookAndFeelConverter;
0054: import com.thoughtworks.xstream.converters.extended.SqlDateConverter;
0055: import com.thoughtworks.xstream.converters.extended.SqlTimeConverter;
0056: import com.thoughtworks.xstream.converters.extended.SqlTimestampConverter;
0057: import com.thoughtworks.xstream.converters.extended.TextAttributeConverter;
0058: import com.thoughtworks.xstream.converters.reflection.ExternalizableConverter;
0059: import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
0060: import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
0061: import com.thoughtworks.xstream.converters.reflection.SelfStreamingInstanceChecker;
0062: import com.thoughtworks.xstream.converters.reflection.SerializableConverter;
0063: import com.thoughtworks.xstream.core.DefaultConverterLookup;
0064: import com.thoughtworks.xstream.core.JVM;
0065: import com.thoughtworks.xstream.core.MapBackedDataHolder;
0066: import com.thoughtworks.xstream.core.ReferenceByIdMarshallingStrategy;
0067: import com.thoughtworks.xstream.core.ReferenceByXPathMarshallingStrategy;
0068: import com.thoughtworks.xstream.core.TreeMarshallingStrategy;
0069: import com.thoughtworks.xstream.core.util.ClassLoaderReference;
0070: import com.thoughtworks.xstream.core.util.CompositeClassLoader;
0071: import com.thoughtworks.xstream.core.util.CustomObjectInputStream;
0072: import com.thoughtworks.xstream.core.util.CustomObjectOutputStream;
0073: import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
0074: import com.thoughtworks.xstream.io.HierarchicalStreamReader;
0075: import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
0076: import com.thoughtworks.xstream.io.StatefulWriter;
0077: import com.thoughtworks.xstream.io.xml.XppDriver;
0078: import com.thoughtworks.xstream.mapper.AnnotationConfiguration;
0079: import com.thoughtworks.xstream.mapper.ArrayMapper;
0080: import com.thoughtworks.xstream.mapper.AttributeAliasingMapper;
0081: import com.thoughtworks.xstream.mapper.AttributeMapper;
0082: import com.thoughtworks.xstream.mapper.CachingMapper;
0083: import com.thoughtworks.xstream.mapper.ClassAliasingMapper;
0084: import com.thoughtworks.xstream.mapper.DefaultImplementationsMapper;
0085: import com.thoughtworks.xstream.mapper.DefaultMapper;
0086: import com.thoughtworks.xstream.mapper.DynamicProxyMapper;
0087: import com.thoughtworks.xstream.mapper.FieldAliasingMapper;
0088: import com.thoughtworks.xstream.mapper.ImmutableTypesMapper;
0089: import com.thoughtworks.xstream.mapper.ImplicitCollectionMapper;
0090: import com.thoughtworks.xstream.mapper.LocalConversionMapper;
0091: import com.thoughtworks.xstream.mapper.Mapper;
0092: import com.thoughtworks.xstream.mapper.MapperWrapper;
0093: import com.thoughtworks.xstream.mapper.OuterClassMapper;
0094: import com.thoughtworks.xstream.mapper.XStream11XmlFriendlyMapper;
0095:
0096: import java.io.EOFException;
0097: import java.io.File;
0098: import java.io.IOException;
0099: import java.io.InputStream;
0100: import java.io.NotActiveException;
0101: import java.io.ObjectInputStream;
0102: import java.io.ObjectInputValidation;
0103: import java.io.ObjectOutputStream;
0104: import java.io.OutputStream;
0105: import java.io.Reader;
0106: import java.io.StringReader;
0107: import java.io.StringWriter;
0108: import java.io.Writer;
0109: import java.lang.reflect.Constructor;
0110: import java.lang.reflect.InvocationHandler;
0111: import java.lang.reflect.Method;
0112: import java.lang.reflect.Proxy;
0113: import java.math.BigDecimal;
0114: import java.math.BigInteger;
0115: import java.net.URL;
0116: import java.util.ArrayList;
0117: import java.util.BitSet;
0118: import java.util.Calendar;
0119: import java.util.Date;
0120: import java.util.GregorianCalendar;
0121: import java.util.HashMap;
0122: import java.util.HashSet;
0123: import java.util.Hashtable;
0124: import java.util.LinkedList;
0125: import java.util.List;
0126: import java.util.Locale;
0127: import java.util.Map;
0128: import java.util.Properties;
0129: import java.util.Set;
0130: import java.util.TreeMap;
0131: import java.util.TreeSet;
0132: import java.util.Vector;
0133:
0134: /**
0135: * Simple facade to XStream library, a Java-XML serialization tool. <p/>
0136: * <p>
0137: * <hr>
0138: * <b>Example</b><blockquote>
0139: *
0140: * <pre>
0141: * XStream xstream = new XStream();
0142: * String xml = xstream.toXML(myObject); // serialize to XML
0143: * Object myObject2 = xstream.fromXML(xml); // deserialize from XML
0144: * </pre>
0145: *
0146: * </blockquote>
0147: * <hr>
0148: * <p/>
0149: * <h3>Aliasing classes</h3>
0150: * <p/>
0151: * <p>
0152: * To create shorter XML, you can specify aliases for classes using the <code>alias()</code>
0153: * method. For example, you can shorten all occurrences of element
0154: * <code><com.blah.MyThing></code> to <code><my-thing></code> by registering an
0155: * alias for the class.
0156: * <p>
0157: * <hr>
0158: * <blockquote>
0159: *
0160: * <pre>
0161: * xstream.alias("my-thing", MyThing.class);
0162: * </pre>
0163: *
0164: * </blockquote>
0165: * <hr>
0166: * <p/>
0167: * <h3>Converters</h3>
0168: * <p/>
0169: * <p>
0170: * XStream contains a map of {@link com.thoughtworks.xstream.converters.Converter} instances, each
0171: * of which acts as a strategy for converting a particular type of class to XML and back again. Out
0172: * of the box, XStream contains converters for most basic types (String, Date, int, boolean, etc)
0173: * and collections (Map, List, Set, Properties, etc). For other objects reflection is used to
0174: * serialize each field recursively.
0175: * </p>
0176: * <p/>
0177: * <p>
0178: * Extra converters can be registered using the <code>registerConverter()</code> method. Some
0179: * non-standard converters are supplied in the {@link com.thoughtworks.xstream.converters.extended}
0180: * package and you can create your own by implementing the
0181: * {@link com.thoughtworks.xstream.converters.Converter} interface.
0182: * </p>
0183: * <p/>
0184: * <p>
0185: * <hr>
0186: * <b>Example</b><blockquote>
0187: *
0188: * <pre>
0189: * xstream.registerConverter(new SqlTimestampConverter());
0190: * xstream.registerConverter(new DynamicProxyConverter());
0191: * </pre>
0192: *
0193: * </blockquote>
0194: * <hr>
0195: * <p>
0196: * The default converter, ie the converter which will be used if no other registered converter is
0197: * suitable, can be configured by either one of the constructors or can be changed using the
0198: * <code>changeDefaultConverter()</code> method. If not set, XStream uses
0199: * {@link com.thoughtworks.xstream.converters.reflection.ReflectionConverter} as the initial default
0200: * converter.
0201: * </p>
0202: * <p/>
0203: * <p>
0204: * <hr>
0205: * <b>Example</b><blockquote>
0206: *
0207: * <pre>
0208: * xstream.changeDefaultConverter(new ACustomDefaultConverter());
0209: * </pre>
0210: *
0211: * </blockquote>
0212: * <hr>
0213: * <p/>
0214: * <h3>Object graphs</h3>
0215: * <p/>
0216: * <p>
0217: * XStream has support for object graphs; a deserialized object graph will keep references intact,
0218: * including circular references.
0219: * </p>
0220: * <p/>
0221: * <p>
0222: * XStream can signify references in XML using either relative/absolute XPath or IDs. The mode can be changed using
0223: * <code>setMode()</code>:
0224: * </p>
0225: * <p/> <table border="1">
0226: * <tr>
0227: * <td><code>xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES);</code></td>
0228: * <td><i>(Default)</i> Uses XPath relative references to signify duplicate references. This produces XML
0229: * with the least clutter.</td>
0230: * </tr>
0231: * <tr>
0232: * <td><code>xstream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES);</code></td>
0233: * <td>Uses XPath absolute references to signify duplicate
0234: * references. This produces XML with the least clutter.</td>
0235: * </tr>
0236: * <tr>
0237: * <td><code>xstream.setMode(XStream.ID_REFERENCES);</code></td>
0238: * <td>Uses ID references to signify duplicate references. In some scenarios, such as when using
0239: * hand-written XML, this is easier to work with.</td>
0240: * </tr>
0241: * <tr>
0242: * <td><code>xstream.setMode(XStream.NO_REFERENCES);</code></td>
0243: * <td>This disables object graph support and treats the object structure like a tree. Duplicate
0244: * references are treated as two separate objects and circular references cause an exception. This
0245: * is slightly faster and uses less memory than the other two modes.</td>
0246: * </tr>
0247: * </table>
0248: * <h3>Thread safety</h3>
0249: * <p>
0250: * The XStream instance is thread-safe. That is, once the XStream instance has been created and
0251: * configured, it may be shared across multiple threads allowing objects to be
0252: * serialized/deserialized concurrently.
0253: * <h3>Implicit collections</h3>
0254: * <p/>
0255: * <p>
0256: * To avoid the need for special tags for collections, you can define implicit collections using one
0257: * of the <code>addImplicitCollection</code> methods.
0258: * </p>
0259: *
0260: * @author Joe Walnes
0261: * @author Jörg Schaible
0262: * @author Mauro Talevi
0263: * @author Guilherme Silveira
0264: */
0265: public class XStream {
0266:
0267: // CAUTION: The sequence of the fields is intentional for an optimal XML output of a
0268: // self-serialization!
0269: private ReflectionProvider reflectionProvider;
0270: private HierarchicalStreamDriver hierarchicalStreamDriver;
0271: private ClassLoaderReference classLoaderReference;
0272: private MarshallingStrategy marshallingStrategy;
0273: private ConverterLookup converterLookup;
0274: private ConverterRegistry converterRegistry;
0275: private Mapper mapper;
0276:
0277: private ClassAliasingMapper classAliasingMapper;
0278: private FieldAliasingMapper fieldAliasingMapper;
0279: private AttributeAliasingMapper attributeAliasingMapper;
0280: private AttributeMapper attributeMapper;
0281: private DefaultImplementationsMapper defaultImplementationsMapper;
0282: private ImmutableTypesMapper immutableTypesMapper;
0283: private ImplicitCollectionMapper implicitCollectionMapper;
0284: private LocalConversionMapper localConversionMapper;
0285: private AnnotationConfiguration annotationConfiguration;
0286:
0287: private transient JVM jvm = new JVM();
0288:
0289: public static final int NO_REFERENCES = 1001;
0290: public static final int ID_REFERENCES = 1002;
0291: public static final int XPATH_RELATIVE_REFERENCES = 1003;
0292: public static final int XPATH_ABSOLUTE_REFERENCES = 1004;
0293: /**
0294: * @deprecated since 1.2, use {@link #XPATH_RELATIVE_REFERENCES} or
0295: * {@link #XPATH_ABSOLUTE_REFERENCES} instead.
0296: */
0297: public static final int XPATH_REFERENCES = XPATH_RELATIVE_REFERENCES;
0298:
0299: public static final int PRIORITY_VERY_HIGH = 10000;
0300: public static final int PRIORITY_NORMAL = 0;
0301: public static final int PRIORITY_LOW = -10;
0302: public static final int PRIORITY_VERY_LOW = -20;
0303:
0304: private static final String ANNOTATION_MAPPER_TYPE = "com.thoughtworks.xstream.mapper.AnnotationMapper";
0305:
0306: /**
0307: * Constructs a default XStream. The instance will use the {@link XppDriver} as default and tries to determine the best
0308: * match for the {@link ReflectionProvider} on its own.
0309: *
0310: * @throws InitializationException in case of an initialization problem
0311: */
0312: public XStream() {
0313: this (null, (Mapper) null, new XppDriver());
0314: }
0315:
0316: /**
0317: * Constructs an XStream with a special {@link ReflectionProvider}. The instance will use the {@link XppDriver} as default.
0318: *
0319: * @throws InitializationException in case of an initialization problem
0320: */
0321: public XStream(ReflectionProvider reflectionProvider) {
0322: this (reflectionProvider, (Mapper) null, new XppDriver());
0323: }
0324:
0325: /**
0326: * Constructs an XStream with a special {@link HierarchicalStreamDriver}. The instance will tries to determine the best
0327: * match for the {@link ReflectionProvider} on its own.
0328: *
0329: * @throws InitializationException in case of an initialization problem
0330: */
0331: public XStream(HierarchicalStreamDriver hierarchicalStreamDriver) {
0332: this (null, (Mapper) null, hierarchicalStreamDriver);
0333: }
0334:
0335: /**
0336: * Constructs an XStream with a special {@link HierarchicalStreamDriver} and {@link ReflectionProvider}.
0337: *
0338: * @throws InitializationException in case of an initialization problem
0339: */
0340: public XStream(ReflectionProvider reflectionProvider,
0341: HierarchicalStreamDriver hierarchicalStreamDriver) {
0342: this (reflectionProvider, (Mapper) null,
0343: hierarchicalStreamDriver);
0344: }
0345:
0346: /**
0347: * @deprecated As of 1.2, use
0348: * {@link #XStream(ReflectionProvider, Mapper, HierarchicalStreamDriver)}
0349: */
0350: public XStream(ReflectionProvider reflectionProvider,
0351: ClassMapper classMapper, HierarchicalStreamDriver driver) {
0352: this (reflectionProvider, (Mapper) classMapper, driver);
0353: }
0354:
0355: /**
0356: * @deprecated As of 1.2, use
0357: * {@link #XStream(ReflectionProvider, Mapper, HierarchicalStreamDriver)} and
0358: * register classAttributeIdentifier as alias
0359: */
0360: public XStream(ReflectionProvider reflectionProvider,
0361: ClassMapper classMapper, HierarchicalStreamDriver driver,
0362: String classAttributeIdentifier) {
0363: this (reflectionProvider, (Mapper) classMapper, driver);
0364: aliasAttribute(classAttributeIdentifier, "class");
0365: }
0366:
0367: /**
0368: * Constructs an XStream with a special {@link HierarchicalStreamDriver} and {@link ReflectionProvider} and additionally with a prepared {@link Mapper}.
0369: *
0370: * @throws InitializationException in case of an initialization problem
0371: * @deprecated since 1.3, use {@link #XStream(ReflectionProvider, HierarchicalStreamDriver, Mapper, ClassLoader)} instead
0372: */
0373: public XStream(ReflectionProvider reflectionProvider,
0374: Mapper mapper, HierarchicalStreamDriver driver) {
0375: this (reflectionProvider, driver, new ClassLoaderReference(
0376: new CompositeClassLoader()), mapper,
0377: new DefaultConverterLookup(), null);
0378: }
0379:
0380: /**
0381: * Constructs an XStream with a special {@link HierarchicalStreamDriver} and {@link ReflectionProvider} and additionally with a prepared
0382: * {@link ClassLoader} to use.
0383: *
0384: * @throws InitializationException in case of an initialization problem
0385: * @since 1.3
0386: */
0387: public XStream(ReflectionProvider reflectionProvider,
0388: HierarchicalStreamDriver driver, ClassLoader classLoader) {
0389: this (reflectionProvider, driver, classLoader, null);
0390: }
0391:
0392: /**
0393: * Constructs an XStream with a special {@link HierarchicalStreamDriver} and {@link ReflectionProvider} and additionally with a prepared {@link Mapper}
0394: * and the {@link ClassLoader} in use.
0395: *
0396: * <p>Note, if the class loader should be changed later again, you should provide a {@link ClassLoaderReference} as {@link ClassLoader} that is also
0397: * use in the {@link Mapper} chain.</p>
0398: *
0399: * @throws InitializationException in case of an initialization problem
0400: * @since 1.3
0401: */
0402: public XStream(ReflectionProvider reflectionProvider,
0403: HierarchicalStreamDriver driver, ClassLoader classLoader,
0404: Mapper mapper) {
0405: this (reflectionProvider, driver, classLoader, mapper,
0406: new DefaultConverterLookup(), null);
0407: }
0408:
0409: /**
0410: * Constructs an XStream with a special {@link HierarchicalStreamDriver}, {@link ReflectionProvider}, a prepared {@link Mapper}
0411: * and the {@link ClassLoader} in use and an own {@link ConverterRegistry}.
0412: *
0413: * <p>Note, if the class loader should be changed later again, you should provide a {@link ClassLoaderReference} as {@link ClassLoader} that is also
0414: * use in the {@link Mapper} chain.</p>
0415: *
0416: * @throws InitializationException in case of an initialization problem
0417: * @since 1.3
0418: */
0419: public XStream(ReflectionProvider reflectionProvider,
0420: HierarchicalStreamDriver driver, ClassLoader classLoader,
0421: Mapper mapper, ConverterLookup converterLookup,
0422: ConverterRegistry converterRegistry) {
0423: jvm = new JVM();
0424: if (reflectionProvider == null) {
0425: reflectionProvider = jvm.bestReflectionProvider();
0426: }
0427: this .reflectionProvider = reflectionProvider;
0428: this .hierarchicalStreamDriver = driver;
0429: this .classLoaderReference = classLoader instanceof ClassLoaderReference ? (ClassLoaderReference) classLoader
0430: : new ClassLoaderReference(classLoader);
0431: this .converterLookup = converterLookup;
0432: this .converterRegistry = converterRegistry != null ? converterRegistry
0433: : (converterLookup instanceof ConverterRegistry ? (ConverterRegistry) converterLookup
0434: : null);
0435: this .mapper = mapper == null ? buildMapper() : mapper;
0436:
0437: setupMappers();
0438: setupAliases();
0439: setupDefaultImplementations();
0440: setupConverters();
0441: setupImmutableTypes();
0442: setMode(XPATH_RELATIVE_REFERENCES);
0443: }
0444:
0445: private Mapper buildMapper() {
0446: Mapper mapper = new DefaultMapper(classLoaderReference);
0447: if (useXStream11XmlFriendlyMapper()) {
0448: mapper = new XStream11XmlFriendlyMapper(mapper);
0449: }
0450: if (jvm.loadClass("net.sf.cglib.proxy.Enhancer") != null) {
0451: mapper = buildMapperDynamically(
0452: "com.thoughtworks.xstream.mapper.CGLIBMapper",
0453: new Class[] { Mapper.class },
0454: new Object[] { mapper });
0455: }
0456: mapper = new DynamicProxyMapper(mapper);
0457: mapper = new ClassAliasingMapper(mapper);
0458: mapper = new FieldAliasingMapper(mapper);
0459: mapper = new AttributeAliasingMapper(mapper);
0460: mapper = new ImplicitCollectionMapper(mapper);
0461: mapper = new OuterClassMapper(mapper);
0462: mapper = new ArrayMapper(mapper);
0463: mapper = new LocalConversionMapper(mapper);
0464: mapper = new DefaultImplementationsMapper(mapper);
0465: if (JVM.is15()) {
0466: mapper = buildMapperDynamically(
0467: "com.thoughtworks.xstream.mapper.EnumMapper",
0468: new Class[] { Mapper.class, ConverterLookup.class },
0469: new Object[] { mapper, converterLookup });
0470: } else {
0471: mapper = new AttributeMapper(mapper, converterLookup);
0472: }
0473: mapper = new ImmutableTypesMapper(mapper);
0474: if (JVM.is15()) {
0475: mapper = buildMapperDynamically(ANNOTATION_MAPPER_TYPE,
0476: new Class[] { Mapper.class,
0477: ConverterRegistry.class, ClassLoader.class,
0478: ReflectionProvider.class, JVM.class },
0479: new Object[] { mapper, converterLookup,
0480: classLoaderReference, reflectionProvider,
0481: jvm });
0482: }
0483: mapper = wrapMapper((MapperWrapper) mapper);
0484: mapper = new CachingMapper(mapper);
0485: return mapper;
0486: }
0487:
0488: private Mapper buildMapperDynamically(String className,
0489: Class[] constructorParamTypes,
0490: Object[] constructorParamValues) {
0491: try {
0492: Class type = Class.forName(className, false,
0493: classLoaderReference.getReference());
0494: Constructor constructor = type
0495: .getConstructor(constructorParamTypes);
0496: return (Mapper) constructor
0497: .newInstance(constructorParamValues);
0498: } catch (Exception e) {
0499: throw new InitializationException(
0500: "Could not instantiate mapper : " + className, e);
0501: }
0502: }
0503:
0504: protected MapperWrapper wrapMapper(MapperWrapper next) {
0505: return next;
0506: }
0507:
0508: protected boolean useXStream11XmlFriendlyMapper() {
0509: return false;
0510: }
0511:
0512: private void setupMappers() {
0513: classAliasingMapper = (ClassAliasingMapper) this .mapper
0514: .lookupMapperOfType(ClassAliasingMapper.class);
0515: fieldAliasingMapper = (FieldAliasingMapper) this .mapper
0516: .lookupMapperOfType(FieldAliasingMapper.class);
0517: attributeMapper = (AttributeMapper) this .mapper
0518: .lookupMapperOfType(AttributeMapper.class);
0519: attributeAliasingMapper = (AttributeAliasingMapper) this .mapper
0520: .lookupMapperOfType(AttributeAliasingMapper.class);
0521: implicitCollectionMapper = (ImplicitCollectionMapper) this .mapper
0522: .lookupMapperOfType(ImplicitCollectionMapper.class);
0523: defaultImplementationsMapper = (DefaultImplementationsMapper) this .mapper
0524: .lookupMapperOfType(DefaultImplementationsMapper.class);
0525: immutableTypesMapper = (ImmutableTypesMapper) this .mapper
0526: .lookupMapperOfType(ImmutableTypesMapper.class);
0527: localConversionMapper = (LocalConversionMapper) this .mapper
0528: .lookupMapperOfType(LocalConversionMapper.class);
0529: annotationConfiguration = (AnnotationConfiguration) this .mapper
0530: .lookupMapperOfType(AnnotationConfiguration.class);
0531: }
0532:
0533: protected void setupAliases() {
0534: if (classAliasingMapper == null) {
0535: return;
0536: }
0537:
0538: alias("null", Mapper.Null.class);
0539: alias("int", Integer.class);
0540: alias("float", Float.class);
0541: alias("double", Double.class);
0542: alias("long", Long.class);
0543: alias("short", Short.class);
0544: alias("char", Character.class);
0545: alias("byte", Byte.class);
0546: alias("boolean", Boolean.class);
0547: alias("number", Number.class);
0548: alias("object", Object.class);
0549: alias("big-int", BigInteger.class);
0550: alias("big-decimal", BigDecimal.class);
0551:
0552: alias("string-buffer", StringBuffer.class);
0553: alias("string", String.class);
0554: alias("java-class", Class.class);
0555: alias("method", Method.class);
0556: alias("constructor", Constructor.class);
0557: alias("date", Date.class);
0558: alias("url", URL.class);
0559: alias("bit-set", BitSet.class);
0560:
0561: alias("map", Map.class);
0562: alias("entry", Map.Entry.class);
0563: alias("properties", Properties.class);
0564: alias("list", List.class);
0565: alias("set", Set.class);
0566:
0567: alias("linked-list", LinkedList.class);
0568: alias("vector", Vector.class);
0569: alias("tree-map", TreeMap.class);
0570: alias("tree-set", TreeSet.class);
0571: alias("hashtable", Hashtable.class);
0572:
0573: if (jvm.supportsAWT()) {
0574: // Instantiating these two classes starts the AWT system, which is undesirable. Calling
0575: // loadClass ensures a reference to the class is found but they are not instantiated.
0576: alias("awt-color", jvm.loadClass("java.awt.Color"));
0577: alias("awt-font", jvm.loadClass("java.awt.Font"));
0578: alias("awt-text-attribute", jvm
0579: .loadClass("java.awt.font.TextAttribute"));
0580: }
0581:
0582: if (jvm.supportsSQL()) {
0583: alias("sql-timestamp", jvm.loadClass("java.sql.Timestamp"));
0584: alias("sql-time", jvm.loadClass("java.sql.Time"));
0585: alias("sql-date", jvm.loadClass("java.sql.Date"));
0586: }
0587:
0588: alias("file", File.class);
0589: alias("locale", Locale.class);
0590: alias("gregorian-calendar", Calendar.class);
0591:
0592: // since jdk 1.4 included, but previously available as separate package ...
0593: Class type = jvm.loadClass("javax.security.auth.Subject");
0594: if (type != null) {
0595: alias("auth-subject", type);
0596: }
0597:
0598: // since jdk 1.5 included, but available separately in JAXB ...
0599: type = jvm.loadClass("javax.xml.datatype.Duration");
0600: if (type != null) {
0601: alias("duration", type);
0602: }
0603:
0604: if (JVM.is14()) {
0605: alias("linked-hash-map", jvm
0606: .loadClass("java.util.LinkedHashMap"));
0607: alias("linked-hash-set", jvm
0608: .loadClass("java.util.LinkedHashSet"));
0609: alias("trace", jvm.loadClass("java.lang.StackTraceElement"));
0610: alias("currency", jvm.loadClass("java.util.Currency"));
0611: aliasType("charset", jvm
0612: .loadClass("java.nio.charset.Charset"));
0613: }
0614:
0615: if (JVM.is15()) {
0616: alias("enum-set", jvm.loadClass("java.util.EnumSet"));
0617: alias("enum-map", jvm.loadClass("java.util.EnumMap"));
0618: alias("string-builder", jvm
0619: .loadClass("java.lang.StringBuilder"));
0620: alias("uuid", jvm.loadClass("java.util.UUID"));
0621: }
0622: }
0623:
0624: protected void setupDefaultImplementations() {
0625: if (defaultImplementationsMapper == null) {
0626: return;
0627: }
0628: addDefaultImplementation(HashMap.class, Map.class);
0629: addDefaultImplementation(ArrayList.class, List.class);
0630: addDefaultImplementation(HashSet.class, Set.class);
0631: addDefaultImplementation(GregorianCalendar.class,
0632: Calendar.class);
0633: }
0634:
0635: protected void setupConverters() {
0636: final ReflectionConverter reflectionConverter = new ReflectionConverter(
0637: mapper, reflectionProvider);
0638: registerConverter(reflectionConverter, PRIORITY_VERY_LOW);
0639:
0640: registerConverter(new SerializableConverter(mapper,
0641: reflectionProvider), PRIORITY_LOW);
0642: registerConverter(new ExternalizableConverter(mapper),
0643: PRIORITY_LOW);
0644:
0645: registerConverter(new NullConverter(), PRIORITY_VERY_HIGH);
0646: registerConverter(new IntConverter(), PRIORITY_NORMAL);
0647: registerConverter(new FloatConverter(), PRIORITY_NORMAL);
0648: registerConverter(new DoubleConverter(), PRIORITY_NORMAL);
0649: registerConverter(new LongConverter(), PRIORITY_NORMAL);
0650: registerConverter(new ShortConverter(), PRIORITY_NORMAL);
0651: registerConverter((Converter) new CharConverter(),
0652: PRIORITY_NORMAL);
0653: registerConverter(new BooleanConverter(), PRIORITY_NORMAL);
0654: registerConverter(new ByteConverter(), PRIORITY_NORMAL);
0655:
0656: registerConverter(new StringConverter(), PRIORITY_NORMAL);
0657: registerConverter(new StringBufferConverter(), PRIORITY_NORMAL);
0658: registerConverter(new DateConverter(), PRIORITY_NORMAL);
0659: registerConverter(new BitSetConverter(), PRIORITY_NORMAL);
0660: registerConverter(new URLConverter(), PRIORITY_NORMAL);
0661: registerConverter(new BigIntegerConverter(), PRIORITY_NORMAL);
0662: registerConverter(new BigDecimalConverter(), PRIORITY_NORMAL);
0663:
0664: registerConverter(new ArrayConverter(mapper), PRIORITY_NORMAL);
0665: registerConverter(new CharArrayConverter(), PRIORITY_NORMAL);
0666: registerConverter(new CollectionConverter(mapper),
0667: PRIORITY_NORMAL);
0668: registerConverter(new MapConverter(mapper), PRIORITY_NORMAL);
0669: registerConverter(new TreeMapConverter(mapper), PRIORITY_NORMAL);
0670: registerConverter(new TreeSetConverter(mapper), PRIORITY_NORMAL);
0671: registerConverter(new PropertiesConverter(), PRIORITY_NORMAL);
0672: registerConverter(new EncodedByteArrayConverter(),
0673: PRIORITY_NORMAL);
0674:
0675: registerConverter(new FileConverter(), PRIORITY_NORMAL);
0676: if (jvm.supportsSQL()) {
0677: registerConverter(new SqlTimestampConverter(),
0678: PRIORITY_NORMAL);
0679: registerConverter(new SqlTimeConverter(), PRIORITY_NORMAL);
0680: registerConverter(new SqlDateConverter(), PRIORITY_NORMAL);
0681: }
0682: registerConverter(new DynamicProxyConverter(mapper,
0683: classLoaderReference), PRIORITY_NORMAL);
0684: registerConverter(new JavaClassConverter(classLoaderReference),
0685: PRIORITY_NORMAL);
0686: registerConverter(
0687: new JavaMethodConverter(classLoaderReference),
0688: PRIORITY_NORMAL);
0689: if (jvm.supportsAWT()) {
0690: registerConverter(new FontConverter(), PRIORITY_NORMAL);
0691: registerConverter(new ColorConverter(), PRIORITY_NORMAL);
0692: registerConverter(new TextAttributeConverter(),
0693: PRIORITY_NORMAL);
0694: }
0695: if (jvm.supportsSwing()) {
0696: registerConverter(new LookAndFeelConverter(mapper,
0697: reflectionProvider), PRIORITY_NORMAL);
0698: }
0699: registerConverter(new LocaleConverter(), PRIORITY_NORMAL);
0700: registerConverter(new GregorianCalendarConverter(),
0701: PRIORITY_NORMAL);
0702:
0703: // since JDK 1.4 included, but previously available as separate package ...
0704: if (jvm.loadClass("javax.security.auth.Subject") != null) {
0705: dynamicallyRegisterConverter(
0706: "com.thoughtworks.xstream.converters.extended.SubjectConverter",
0707: PRIORITY_NORMAL, new Class[] { Mapper.class },
0708: new Object[] { mapper });
0709: }
0710:
0711: // since JDK 1.5 included, bas as part of JAXB previously available ...
0712: if (jvm.loadClass("javax.xml.datatype.Duration") != null) {
0713: dynamicallyRegisterConverter(
0714: "com.thoughtworks.xstream.converters.extended.DurationConverter",
0715: PRIORITY_NORMAL, null, null);
0716: }
0717:
0718: if (JVM.is14()) {
0719: // late bound converters - allows XStream to be compiled on earlier JDKs
0720: dynamicallyRegisterConverter(
0721: "com.thoughtworks.xstream.converters.extended.ThrowableConverter",
0722: PRIORITY_NORMAL, new Class[] { Converter.class },
0723: new Object[] { reflectionConverter });
0724: dynamicallyRegisterConverter(
0725: "com.thoughtworks.xstream.converters.extended.StackTraceElementConverter",
0726: PRIORITY_NORMAL, null, null);
0727: dynamicallyRegisterConverter(
0728: "com.thoughtworks.xstream.converters.extended.CurrencyConverter",
0729: PRIORITY_NORMAL, null, null);
0730: dynamicallyRegisterConverter(
0731: "com.thoughtworks.xstream.converters.extended.RegexPatternConverter",
0732: PRIORITY_NORMAL, new Class[] { Converter.class },
0733: new Object[] { reflectionConverter });
0734: dynamicallyRegisterConverter(
0735: "com.thoughtworks.xstream.converters.extended.CharsetConverter",
0736: PRIORITY_NORMAL, null, null);
0737: }
0738:
0739: if (JVM.is15()) {
0740: // late bound converters - allows XStream to be compiled on earlier JDKs
0741: dynamicallyRegisterConverter(
0742: "com.thoughtworks.xstream.converters.enums.EnumConverter",
0743: PRIORITY_NORMAL, null, null);
0744: dynamicallyRegisterConverter(
0745: "com.thoughtworks.xstream.converters.enums.EnumSetConverter",
0746: PRIORITY_NORMAL, new Class[] { Mapper.class },
0747: new Object[] { mapper });
0748: dynamicallyRegisterConverter(
0749: "com.thoughtworks.xstream.converters.enums.EnumMapConverter",
0750: PRIORITY_NORMAL, new Class[] { Mapper.class },
0751: new Object[] { mapper });
0752: dynamicallyRegisterConverter(
0753: "com.thoughtworks.xstream.converters.basic.StringBuilderConverter",
0754: PRIORITY_NORMAL, null, null);
0755: dynamicallyRegisterConverter(
0756: "com.thoughtworks.xstream.converters.basic.UUIDConverter",
0757: PRIORITY_NORMAL, null, null);
0758: }
0759:
0760: if (jvm.loadClass("net.sf.cglib.proxy.Enhancer") != null) {
0761: dynamicallyRegisterConverter(
0762: "com.thoughtworks.xstream.converters.reflection.CGLIBEnhancedConverter",
0763: PRIORITY_NORMAL, new Class[] { Mapper.class,
0764: ReflectionProvider.class }, new Object[] {
0765: mapper, reflectionProvider });
0766: }
0767:
0768: registerConverter(new SelfStreamingInstanceChecker(
0769: reflectionConverter, this ), PRIORITY_NORMAL);
0770: }
0771:
0772: private void dynamicallyRegisterConverter(String className,
0773: int priority, Class[] constructorParamTypes,
0774: Object[] constructorParamValues) {
0775: try {
0776: Class type = Class.forName(className, false,
0777: classLoaderReference.getReference());
0778: Constructor constructor = type
0779: .getConstructor(constructorParamTypes);
0780: Object instance = constructor
0781: .newInstance(constructorParamValues);
0782: if (instance instanceof Converter) {
0783: registerConverter((Converter) instance, priority);
0784: } else if (instance instanceof SingleValueConverter) {
0785: registerConverter((SingleValueConverter) instance,
0786: priority);
0787: }
0788: } catch (Exception e) {
0789: throw new InitializationException(
0790: "Could not instantiate converter : " + className, e);
0791: }
0792: }
0793:
0794: protected void setupImmutableTypes() {
0795: if (immutableTypesMapper == null) {
0796: return;
0797: }
0798:
0799: // primitives are always immutable
0800: addImmutableType(boolean.class);
0801: addImmutableType(Boolean.class);
0802: addImmutableType(byte.class);
0803: addImmutableType(Byte.class);
0804: addImmutableType(char.class);
0805: addImmutableType(Character.class);
0806: addImmutableType(double.class);
0807: addImmutableType(Double.class);
0808: addImmutableType(float.class);
0809: addImmutableType(Float.class);
0810: addImmutableType(int.class);
0811: addImmutableType(Integer.class);
0812: addImmutableType(long.class);
0813: addImmutableType(Long.class);
0814: addImmutableType(short.class);
0815: addImmutableType(Short.class);
0816:
0817: // additional types
0818: addImmutableType(Mapper.Null.class);
0819: addImmutableType(BigDecimal.class);
0820: addImmutableType(BigInteger.class);
0821: addImmutableType(String.class);
0822: addImmutableType(URL.class);
0823: addImmutableType(File.class);
0824: addImmutableType(Class.class);
0825:
0826: if (jvm.supportsAWT()) {
0827: addImmutableType(jvm
0828: .loadClass("java.awt.font.TextAttribute"));
0829: }
0830:
0831: if (JVM.is14()) {
0832: // late bound types - allows XStream to be compiled on earlier JDKs
0833: Class type = jvm
0834: .loadClass("com.thoughtworks.xstream.converters.extended.CharsetConverter");
0835: addImmutableType(type);
0836: }
0837: }
0838:
0839: public void setMarshallingStrategy(
0840: MarshallingStrategy marshallingStrategy) {
0841: this .marshallingStrategy = marshallingStrategy;
0842: }
0843:
0844: /**
0845: * Serialize an object to a pretty-printed XML String.
0846: * @throws XStreamException if the object cannot be serialized
0847: */
0848: public String toXML(Object obj) {
0849: Writer writer = new StringWriter();
0850: toXML(obj, writer);
0851: return writer.toString();
0852: }
0853:
0854: /**
0855: * Serialize an object to the given Writer as pretty-printed XML.
0856: * @throws XStreamException if the object cannot be serialized
0857: */
0858: public void toXML(Object obj, Writer out) {
0859: HierarchicalStreamWriter writer = hierarchicalStreamDriver
0860: .createWriter(out);
0861: marshal(obj, writer);
0862: writer.flush();
0863: }
0864:
0865: /**
0866: * Serialize an object to the given OutputStream as pretty-printed XML.
0867: * @throws XStreamException if the object cannot be serialized
0868: */
0869: public void toXML(Object obj, OutputStream out) {
0870: HierarchicalStreamWriter writer = hierarchicalStreamDriver
0871: .createWriter(out);
0872: marshal(obj, writer);
0873: writer.flush();
0874: }
0875:
0876: /**
0877: * Serialize and object to a hierarchical data structure (such as XML).
0878: * @throws XStreamException if the object cannot be serialized
0879: */
0880: public void marshal(Object obj, HierarchicalStreamWriter writer) {
0881: marshal(obj, writer, null);
0882: }
0883:
0884: /**
0885: * Serialize and object to a hierarchical data structure (such as XML).
0886: *
0887: * @param dataHolder Extra data you can use to pass to your converters. Use this as you want. If
0888: * not present, XStream shall create one lazily as needed.
0889: * @throws XStreamException if the object cannot be serialized
0890: */
0891: public void marshal(Object obj, HierarchicalStreamWriter writer,
0892: DataHolder dataHolder) {
0893: marshallingStrategy.marshal(writer, obj, converterLookup,
0894: mapper, dataHolder);
0895: }
0896:
0897: /**
0898: * Deserialize an object from an XML String.
0899: * @throws XStreamException if the object cannot be deserialized
0900: */
0901: public Object fromXML(String xml) {
0902: return fromXML(new StringReader(xml));
0903: }
0904:
0905: /**
0906: * Deserialize an object from an XML Reader.
0907: * @throws XStreamException if the object cannot be deserialized
0908: */
0909: public Object fromXML(Reader xml) {
0910: return unmarshal(hierarchicalStreamDriver.createReader(xml),
0911: null);
0912: }
0913:
0914: /**
0915: * Deserialize an object from an XML InputStream.
0916: * @throws XStreamException if the object cannot be deserialized
0917: */
0918: public Object fromXML(InputStream input) {
0919: return unmarshal(hierarchicalStreamDriver.createReader(input),
0920: null);
0921: }
0922:
0923: /**
0924: * Deserialize an object from an XML String, populating the fields of the given root object
0925: * instead of instantiating a new one. Note, that this is a special use case! With the ReflectionConverter
0926: * XStream will write directly into the raw memory area of the existing object. Use with care!
0927: * @throws XStreamException if the object cannot be deserialized
0928: */
0929: public Object fromXML(String xml, Object root) {
0930: return fromXML(new StringReader(xml), root);
0931: }
0932:
0933: /**
0934: * Deserialize an object from an XML Reader, populating the fields of the given root object
0935: * instead of instantiating a new one. Note, that this is a special use case! With the ReflectionConverter
0936: * XStream will write directly into the raw memory area of the existing object. Use with care!
0937: * @throws XStreamException if the object cannot be deserialized
0938: */
0939: public Object fromXML(Reader xml, Object root) {
0940: return unmarshal(hierarchicalStreamDriver.createReader(xml),
0941: root);
0942: }
0943:
0944: /**
0945: * Deserialize an object from an XML InputStream, populating the fields of the given root object
0946: * instead of instantiating a new one. Note, that this is a special use case! With the ReflectionConverter
0947: * XStream will write directly into the raw memory area of the existing object. Use with care!
0948: * @throws XStreamException if the object cannot be deserialized
0949: */
0950: public Object fromXML(InputStream xml, Object root) {
0951: return unmarshal(hierarchicalStreamDriver.createReader(xml),
0952: root);
0953: }
0954:
0955: /**
0956: * Deserialize an object from a hierarchical data structure (such as XML).
0957: * @throws XStreamException if the object cannot be deserialized
0958: */
0959: public Object unmarshal(HierarchicalStreamReader reader) {
0960: return unmarshal(reader, null, null);
0961: }
0962:
0963: /**
0964: * Deserialize an object from a hierarchical data structure (such as XML), populating the fields
0965: * of the given root object instead of instantiating a new one. Note, that this is a special use case! With the ReflectionConverter
0966: * XStream will write directly into the raw memory area of the existing object. Use with care!
0967: * @throws XStreamException if the object cannot be deserialized
0968: */
0969: public Object unmarshal(HierarchicalStreamReader reader, Object root) {
0970: return unmarshal(reader, root, null);
0971: }
0972:
0973: /**
0974: * Deserialize an object from a hierarchical data structure (such as XML).
0975: *
0976: * @param root If present, the passed in object will have its fields populated, as opposed to
0977: * XStream creating a new instance. Note, that this is a special use case! With the ReflectionConverter
0978: * XStream will write directly into the raw memory area of the existing object. Use with care!
0979: * @param dataHolder Extra data you can use to pass to your converters. Use this as you want. If
0980: * not present, XStream shall create one lazily as needed.
0981: * @throws XStreamException if the object cannot be deserialized
0982: */
0983: public Object unmarshal(HierarchicalStreamReader reader,
0984: Object root, DataHolder dataHolder) {
0985: return marshallingStrategy.unmarshal(root, reader, dataHolder,
0986: converterLookup, mapper);
0987: }
0988:
0989: /**
0990: * Alias a Class to a shorter name to be used in XML elements.
0991: *
0992: * @param name Short name
0993: * @param type Type to be aliased
0994: * @throws InitializationException if no {@link ClassAliasingMapper} is available
0995: */
0996: public void alias(String name, Class type) {
0997: if (classAliasingMapper == null) {
0998: throw new InitializationException("No "
0999: + ClassAliasingMapper.class.getName()
1000: + " available");
1001: }
1002: classAliasingMapper.addClassAlias(name, type);
1003: }
1004:
1005: /**
1006: * Alias a type to a shorter name to be used in XML elements.
1007: * Any class that is assignable to this type will be aliased to the same name.
1008: *
1009: * @param name Short name
1010: * @param type Type to be aliased
1011: * @since 1.2
1012: * @throws InitializationException if no {@link ClassAliasingMapper} is available
1013: */
1014: public void aliasType(String name, Class type) {
1015: if (classAliasingMapper == null) {
1016: throw new InitializationException("No "
1017: + ClassAliasingMapper.class.getName()
1018: + " available");
1019: }
1020: classAliasingMapper.addTypeAlias(name, type);
1021: }
1022:
1023: /**
1024: * Alias a Class to a shorter name to be used in XML elements.
1025: *
1026: * @param name Short name
1027: * @param type Type to be aliased
1028: * @param defaultImplementation Default implementation of type to use if no other specified.
1029: * @throws InitializationException if no {@link DefaultImplementationsMapper} or no {@link ClassAliasingMapper} is available
1030: */
1031: public void alias(String name, Class type,
1032: Class defaultImplementation) {
1033: alias(name, type);
1034: addDefaultImplementation(defaultImplementation, type);
1035: }
1036:
1037: /**
1038: * Create an alias for a field name.
1039: *
1040: * @param alias the alias itself
1041: * @param definedIn the type that declares the field
1042: * @param fieldName the name of the field
1043: * @throws InitializationException if no {@link FieldAliasingMapper} is available
1044: */
1045: public void aliasField(String alias, Class definedIn,
1046: String fieldName) {
1047: if (fieldAliasingMapper == null) {
1048: throw new InitializationException("No "
1049: + FieldAliasingMapper.class.getName()
1050: + " available");
1051: }
1052: fieldAliasingMapper.addFieldAlias(alias, definedIn, fieldName);
1053: }
1054:
1055: /**
1056: * Create an alias for an attribute
1057: *
1058: * @param alias the alias itself
1059: * @param attributeName the name of the attribute
1060: * @throws InitializationException if no {@link AttributeAliasingMapper} is available
1061: */
1062: public void aliasAttribute(String alias, String attributeName) {
1063: if (attributeAliasingMapper == null) {
1064: throw new InitializationException("No "
1065: + AttributeAliasingMapper.class.getName()
1066: + " available");
1067: }
1068: attributeAliasingMapper.addAliasFor(attributeName, alias);
1069: }
1070:
1071: /**
1072: * Create an alias for an attribute.
1073: *
1074: * @param definedIn the type where the attribute is defined
1075: * @param attributeName the name of the attribute
1076: * @param alias the alias itself
1077: * @throws InitializationException if no {@link AttributeAliasingMapper} is available
1078: * @since 1.2.2
1079: */
1080: public void aliasAttribute(Class definedIn, String attributeName,
1081: String alias) {
1082: aliasField(alias, definedIn, attributeName);
1083: useAttributeFor(definedIn, attributeName);
1084: }
1085:
1086: /**
1087: * Use an attribute for a field or a specific type.
1088: *
1089: * @param fieldName the name of the field
1090: * @param type the Class of the type to be rendered as XML attribute
1091: * @throws InitializationException if no {@link AttributeMapper} is available
1092: * @since 1.2
1093: */
1094: public void useAttributeFor(String fieldName, Class type) {
1095: if (attributeMapper == null) {
1096: throw new InitializationException("No "
1097: + AttributeMapper.class.getName() + " available");
1098: }
1099: attributeMapper.addAttributeFor(fieldName, type);
1100: }
1101:
1102: /**
1103: * Use an attribute for a field declared in a specific type.
1104: *
1105: * @param fieldName the name of the field
1106: * @param definedIn the Class containing such field
1107: * @throws InitializationException if no {@link AttributeMapper} is available
1108: * @since 1.2.2
1109: */
1110: public void useAttributeFor(Class definedIn, String fieldName) {
1111: if (attributeMapper == null) {
1112: throw new InitializationException("No "
1113: + AttributeMapper.class.getName() + " available");
1114: }
1115: attributeMapper.addAttributeFor(definedIn, fieldName);
1116: }
1117:
1118: /**
1119: * Use an attribute for an arbitrary type.
1120: *
1121: * @param type the Class of the type to be rendered as XML attribute
1122: * @throws InitializationException if no {@link AttributeMapper} is available
1123: * @since 1.2
1124: */
1125: public void useAttributeFor(Class type) {
1126: if (attributeMapper == null) {
1127: throw new InitializationException("No "
1128: + AttributeMapper.class.getName() + " available");
1129: }
1130: attributeMapper.addAttributeFor(type);
1131: }
1132:
1133: /**
1134: * Associate a default implementation of a class with an object. Whenever XStream encounters an
1135: * instance of this type, it will use the default implementation instead. For example,
1136: * java.util.ArrayList is the default implementation of java.util.List.
1137: *
1138: * @param defaultImplementation
1139: * @param ofType
1140: * @throws InitializationException if no {@link DefaultImplementationsMapper} is available
1141: */
1142: public void addDefaultImplementation(Class defaultImplementation,
1143: Class ofType) {
1144: if (defaultImplementationsMapper == null) {
1145: throw new InitializationException("No "
1146: + DefaultImplementationsMapper.class.getName()
1147: + " available");
1148: }
1149: defaultImplementationsMapper.addDefaultImplementation(
1150: defaultImplementation, ofType);
1151: }
1152:
1153: /**
1154: * Add immutable types. The value of the instances of these types will always be written into
1155: * the stream even if they appear multiple times.
1156: * @throws InitializationException if no {@link ImmutableTypesMapper} is available
1157: */
1158: public void addImmutableType(Class type) {
1159: if (immutableTypesMapper == null) {
1160: throw new InitializationException("No "
1161: + ImmutableTypesMapper.class.getName()
1162: + " available");
1163: }
1164: immutableTypesMapper.addImmutableType(type);
1165: }
1166:
1167: public void registerConverter(Converter converter) {
1168: registerConverter(converter, PRIORITY_NORMAL);
1169: }
1170:
1171: public void registerConverter(Converter converter, int priority) {
1172: if (converterRegistry != null) {
1173: converterRegistry.registerConverter(converter, priority);
1174: }
1175: }
1176:
1177: public void registerConverter(SingleValueConverter converter) {
1178: registerConverter(converter, PRIORITY_NORMAL);
1179: }
1180:
1181: public void registerConverter(SingleValueConverter converter,
1182: int priority) {
1183: if (converterRegistry != null) {
1184: converterRegistry.registerConverter(
1185: new SingleValueConverterWrapper(converter),
1186: priority);
1187: }
1188: }
1189:
1190: /**
1191: * Register a local {@link Converter} for a field.
1192: *
1193: * @param definedIn the class type the field is defined in
1194: * @param fieldName the field name
1195: * @param converter the converter to use
1196: * @since 1.3
1197: */
1198: public void registerLocalConverter(Class definedIn,
1199: String fieldName, Converter converter) {
1200: if (localConversionMapper == null) {
1201: throw new InitializationException("No "
1202: + LocalConversionMapper.class.getName()
1203: + " available");
1204: }
1205: localConversionMapper.registerLocalConverter(definedIn,
1206: fieldName, converter);
1207: }
1208:
1209: /**
1210: * Register a local {@link SingleValueConverter} for a field.
1211: *
1212: * @param definedIn the class type the field is defined in
1213: * @param fieldName the field name
1214: * @param converter the converter to use
1215: * @since 1.3
1216: */
1217: public void registerLocalConverter(Class definedIn,
1218: String fieldName, SingleValueConverter converter) {
1219: registerLocalConverter(definedIn, fieldName,
1220: (Converter) new SingleValueConverterWrapper(converter));
1221: }
1222:
1223: /**
1224: * @throws ClassCastException if mapper is not really a deprecated {@link ClassMapper} instance
1225: * @deprecated As of 1.2, use {@link #getMapper}
1226: */
1227: public ClassMapper getClassMapper() {
1228: if (mapper instanceof ClassMapper) {
1229: return (ClassMapper) mapper;
1230: } else {
1231: return (ClassMapper) Proxy.newProxyInstance(
1232: getClassLoader(),
1233: new Class[] { ClassMapper.class },
1234: new InvocationHandler() {
1235: public Object invoke(Object proxy,
1236: Method method, Object[] args)
1237: throws Throwable {
1238: return method.invoke(mapper, args);
1239: }
1240: });
1241: }
1242: }
1243:
1244: /**
1245: * Retrieve the {@link Mapper}. This is by default a chain of {@link MapperWrapper MapperWrappers}.
1246: *
1247: * @return the mapper
1248: * @since 1.2
1249: */
1250: public Mapper getMapper() {
1251: return mapper;
1252: }
1253:
1254: /**
1255: * Retrieve the {@link ReflectionProvider} in use.
1256: *
1257: * @return the mapper
1258: * @since 1.2.1
1259: */
1260: public ReflectionProvider getReflectionProvider() {
1261: return reflectionProvider;
1262: }
1263:
1264: public ConverterLookup getConverterLookup() {
1265: return converterLookup;
1266: }
1267:
1268: /**
1269: * Change mode for dealing with duplicate references. Valid values are
1270: * <code>XPATH_ABSOLUTE_REFERENCES</code>, <code>XPATH_RELATIVE_REFERENCES</code>,
1271: * <code>XStream.ID_REFERENCES</code> and <code>XStream.NO_REFERENCES</code>.
1272: *
1273: * @throws IllegalArgumentException if the mode is not one of the declared types
1274: * @see #XPATH_ABSOLUTE_REFERENCES
1275: * @see #XPATH_RELATIVE_REFERENCES
1276: * @see #ID_REFERENCES
1277: * @see #NO_REFERENCES
1278: */
1279: public void setMode(int mode) {
1280: switch (mode) {
1281: case NO_REFERENCES:
1282: setMarshallingStrategy(new TreeMarshallingStrategy());
1283: break;
1284: case ID_REFERENCES:
1285: setMarshallingStrategy(new ReferenceByIdMarshallingStrategy());
1286: break;
1287: case XPATH_RELATIVE_REFERENCES:
1288: setMarshallingStrategy(new ReferenceByXPathMarshallingStrategy(
1289: ReferenceByXPathMarshallingStrategy.RELATIVE));
1290: break;
1291: case XPATH_ABSOLUTE_REFERENCES:
1292: setMarshallingStrategy(new ReferenceByXPathMarshallingStrategy(
1293: ReferenceByXPathMarshallingStrategy.ABSOLUTE));
1294: break;
1295: default:
1296: throw new IllegalArgumentException("Unknown mode : " + mode);
1297: }
1298: }
1299:
1300: /**
1301: * Adds a default implicit collection which is used for any unmapped xml tag.
1302: *
1303: * @param ownerType class owning the implicit collection
1304: * @param fieldName name of the field in the ownerType. This field must be an
1305: * <code>java.util.ArrayList</code>.
1306: */
1307: public void addImplicitCollection(Class ownerType, String fieldName) {
1308: if (implicitCollectionMapper == null) {
1309: throw new InitializationException("No "
1310: + ImplicitCollectionMapper.class.getName()
1311: + " available");
1312: }
1313: implicitCollectionMapper.add(ownerType, fieldName, null, null);
1314: }
1315:
1316: /**
1317: * Adds implicit collection which is used for all items of the given itemType.
1318: *
1319: * @param ownerType class owning the implicit collection
1320: * @param fieldName name of the field in the ownerType. This field must be an
1321: * <code>java.util.ArrayList</code>.
1322: * @param itemType type of the items to be part of this collection.
1323: * @throws InitializationException if no {@link ImplicitCollectionMapper} is available
1324: */
1325: public void addImplicitCollection(Class ownerType,
1326: String fieldName, Class itemType) {
1327: if (implicitCollectionMapper == null) {
1328: throw new InitializationException("No "
1329: + ImplicitCollectionMapper.class.getName()
1330: + " available");
1331: }
1332: implicitCollectionMapper.add(ownerType, fieldName, null,
1333: itemType);
1334: }
1335:
1336: /**
1337: * Adds implicit collection which is used for all items of the given element name defined by
1338: * itemFieldName.
1339: *
1340: * @param ownerType class owning the implicit collection
1341: * @param fieldName name of the field in the ownerType. This field must be an
1342: * <code>java.util.ArrayList</code>.
1343: * @param itemFieldName element name of the implicit collection
1344: * @param itemType item type to be aliases be the itemFieldName
1345: * @throws InitializationException if no {@link ImplicitCollectionMapper} is available
1346: */
1347: public void addImplicitCollection(Class ownerType,
1348: String fieldName, String itemFieldName, Class itemType) {
1349: if (implicitCollectionMapper == null) {
1350: throw new InitializationException("No "
1351: + ImplicitCollectionMapper.class.getName()
1352: + " available");
1353: }
1354: implicitCollectionMapper.add(ownerType, fieldName,
1355: itemFieldName, itemType);
1356: }
1357:
1358: /**
1359: * Create a DataHolder that can be used to pass data to the converters. The DataHolder is provided with a
1360: * call to {@link #marshal(Object, HierarchicalStreamWriter, DataHolder)} or
1361: * {@link #unmarshal(HierarchicalStreamReader, Object, DataHolder)}.
1362: *
1363: * @return a new {@link DataHolder}
1364: */
1365: public DataHolder newDataHolder() {
1366: return new MapBackedDataHolder();
1367: }
1368:
1369: /**
1370: * Creates an ObjectOutputStream that serializes a stream of objects to the writer using
1371: * XStream.
1372: * <p>
1373: * To change the name of the root element (from <object-stream>), use
1374: * {@link #createObjectOutputStream(java.io.Writer, String)}.
1375: * </p>
1376: *
1377: * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String)
1378: * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader)
1379: * @since 1.0.3
1380: */
1381: public ObjectOutputStream createObjectOutputStream(Writer writer)
1382: throws IOException {
1383: return createObjectOutputStream(hierarchicalStreamDriver
1384: .createWriter(writer), "object-stream");
1385: }
1386:
1387: /**
1388: * Creates an ObjectOutputStream that serializes a stream of objects to the writer using
1389: * XStream.
1390: * <p>
1391: * To change the name of the root element (from <object-stream>), use
1392: * {@link #createObjectOutputStream(java.io.Writer, String)}.
1393: * </p>
1394: *
1395: * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String)
1396: * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader)
1397: * @since 1.0.3
1398: */
1399: public ObjectOutputStream createObjectOutputStream(
1400: HierarchicalStreamWriter writer) throws IOException {
1401: return createObjectOutputStream(writer, "object-stream");
1402: }
1403:
1404: /**
1405: * Creates an ObjectOutputStream that serializes a stream of objects to the writer using
1406: * XStream.
1407: *
1408: * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String)
1409: * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader)
1410: * @since 1.0.3
1411: */
1412: public ObjectOutputStream createObjectOutputStream(Writer writer,
1413: String rootNodeName) throws IOException {
1414: return createObjectOutputStream(hierarchicalStreamDriver
1415: .createWriter(writer), rootNodeName);
1416: }
1417:
1418: /**
1419: * Creates an ObjectOutputStream that serializes a stream of objects to the OutputStream using
1420: * XStream.
1421: * <p>
1422: * To change the name of the root element (from <object-stream>), use
1423: * {@link #createObjectOutputStream(java.io.Writer, String)}.
1424: * </p>
1425: *
1426: * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String)
1427: * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader)
1428: * @since 1.3
1429: */
1430: public ObjectOutputStream createObjectOutputStream(OutputStream out)
1431: throws IOException {
1432: return createObjectOutputStream(hierarchicalStreamDriver
1433: .createWriter(out), "object-stream");
1434: }
1435:
1436: /**
1437: * Creates an ObjectOutputStream that serializes a stream of objects to the OutputStream using
1438: * XStream.
1439: *
1440: * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String)
1441: * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader)
1442: * @since 1.3
1443: */
1444: public ObjectOutputStream createObjectOutputStream(
1445: OutputStream out, String rootNodeName) throws IOException {
1446: return createObjectOutputStream(hierarchicalStreamDriver
1447: .createWriter(out), rootNodeName);
1448: }
1449:
1450: /**
1451: * Creates an ObjectOutputStream that serializes a stream of objects to the writer using
1452: * XStream.
1453: * <p>
1454: * Because an ObjectOutputStream can contain multiple items and XML only allows a single root
1455: * node, the stream must be written inside an enclosing node.
1456: * </p>
1457: * <p>
1458: * It is necessary to call ObjectOutputStream.close() when done, otherwise the stream will be
1459: * incomplete.
1460: * </p>
1461: * <h3>Example</h3>
1462: *
1463: * <pre>
1464: * ObjectOutputStream out = xstream.createObjectOutputStream(aWriter, "things");
1465: * out.writeInt(123);
1466: * out.writeObject("Hello");
1467: * out.writeObject(someObject)
1468: * out.close();
1469: * </pre>
1470: *
1471: * @param writer The writer to serialize the objects to.
1472: * @param rootNodeName The name of the root node enclosing the stream of objects.
1473: * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader)
1474: * @since 1.0.3
1475: */
1476: public ObjectOutputStream createObjectOutputStream(
1477: final HierarchicalStreamWriter writer, String rootNodeName)
1478: throws IOException {
1479: final StatefulWriter statefulWriter = new StatefulWriter(writer);
1480: statefulWriter.startNode(rootNodeName, null);
1481: return new CustomObjectOutputStream(
1482: new CustomObjectOutputStream.StreamCallback() {
1483: public void writeToStream(Object object) {
1484: marshal(object, statefulWriter);
1485: }
1486:
1487: public void writeFieldsToStream(Map fields)
1488: throws NotActiveException {
1489: throw new NotActiveException(
1490: "not in call to writeObject");
1491: }
1492:
1493: public void defaultWriteObject()
1494: throws NotActiveException {
1495: throw new NotActiveException(
1496: "not in call to writeObject");
1497: }
1498:
1499: public void flush() {
1500: statefulWriter.flush();
1501: }
1502:
1503: public void close() {
1504: if (statefulWriter.state() != StatefulWriter.STATE_CLOSED) {
1505: statefulWriter.endNode();
1506: statefulWriter.close();
1507: }
1508: }
1509: });
1510: }
1511:
1512: /**
1513: * Creates an ObjectInputStream that deserializes a stream of objects from a reader using
1514: * XStream.
1515: *
1516: * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader)
1517: * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String)
1518: * @since 1.0.3
1519: */
1520: public ObjectInputStream createObjectInputStream(Reader xmlReader)
1521: throws IOException {
1522: return createObjectInputStream(hierarchicalStreamDriver
1523: .createReader(xmlReader));
1524: }
1525:
1526: /**
1527: * Creates an ObjectInputStream that deserializes a stream of objects from an InputStream using
1528: * XStream.
1529: *
1530: * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader)
1531: * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String)
1532: * @since 1.3
1533: */
1534: public ObjectInputStream createObjectInputStream(InputStream in)
1535: throws IOException {
1536: return createObjectInputStream(hierarchicalStreamDriver
1537: .createReader(in));
1538: }
1539:
1540: /**
1541: * Creates an ObjectInputStream that deserializes a stream of objects from a reader using
1542: * XStream.
1543: * <h3>Example</h3>
1544: *
1545: * <pre>
1546: * ObjectInputStream in = xstream.createObjectOutputStream(aReader);
1547: * int a = out.readInt();
1548: * Object b = out.readObject();
1549: * Object c = out.readObject();
1550: * </pre>
1551: *
1552: * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String)
1553: * @since 1.0.3
1554: */
1555: public ObjectInputStream createObjectInputStream(
1556: final HierarchicalStreamReader reader) throws IOException {
1557: return new CustomObjectInputStream(
1558: new CustomObjectInputStream.StreamCallback() {
1559: public Object readFromStream() throws EOFException {
1560: if (!reader.hasMoreChildren()) {
1561: throw new EOFException();
1562: }
1563: reader.moveDown();
1564: Object result = unmarshal(reader);
1565: reader.moveUp();
1566: return result;
1567: }
1568:
1569: public Map readFieldsFromStream()
1570: throws IOException {
1571: throw new NotActiveException(
1572: "not in call to readObject");
1573: }
1574:
1575: public void defaultReadObject()
1576: throws NotActiveException {
1577: throw new NotActiveException(
1578: "not in call to readObject");
1579: }
1580:
1581: public void registerValidation(
1582: ObjectInputValidation validation,
1583: int priority) throws NotActiveException {
1584: throw new NotActiveException("stream inactive");
1585: }
1586:
1587: public void close() {
1588: reader.close();
1589: }
1590: });
1591: }
1592:
1593: /**
1594: * Change the ClassLoader XStream uses to load classes.
1595: *
1596: * @since 1.1.1
1597: */
1598: public void setClassLoader(ClassLoader classLoader) {
1599: classLoaderReference.setReference(classLoader);
1600: }
1601:
1602: /**
1603: * Change the ClassLoader XStream uses to load classes.
1604: *
1605: * @since 1.1.1
1606: */
1607: public ClassLoader getClassLoader() {
1608: return classLoaderReference.getReference();
1609: }
1610:
1611: /**
1612: * Prevents a field from being serialized. To omit a field you must always provide the declaring
1613: * type and not necessarily the type that is converted.
1614: *
1615: * @since 1.1.3
1616: * @throws InitializationException if no {@link FieldAliasingMapper} is available
1617: */
1618: public void omitField(Class definedIn, String fieldName) {
1619: if (fieldAliasingMapper == null) {
1620: throw new InitializationException("No "
1621: + FieldAliasingMapper.class.getName()
1622: + " available");
1623: }
1624: fieldAliasingMapper.omitField(definedIn, fieldName);
1625: }
1626:
1627: /**
1628: * Process the annotations of the given types and configure the XStream.
1629: *
1630: * @param types the types with XStream annotations
1631: * @since 1.3
1632: */
1633: public void processAnnotations(final Class[] types) {
1634: if (annotationConfiguration == null) {
1635: throw new InitializationException("No "
1636: + ANNOTATION_MAPPER_TYPE + " available");
1637: }
1638: annotationConfiguration.processAnnotations(types);
1639: }
1640:
1641: /**
1642: * Process the annotations of the given type and configure the XStream. A call of this method
1643: * will automatically turn the auto-detection mode for annotations off.
1644: *
1645: * @param type the type with XStream annotations
1646: * @since 1.3
1647: */
1648: public void processAnnotations(final Class type) {
1649: processAnnotations(new Class[] { type });
1650: }
1651:
1652: /**
1653: * Set the auto-detection mode of the AnnotationMapper. Note that auto-detection implies that
1654: * the XStream is configured while it is processing the XML steams. This is a potential concurrency
1655: * problem. Also is it technically not possible to detect all class aliases at deserialization. You have
1656: * been warned!
1657: *
1658: * @param mode <code>true</code> if annotations are auto-detected
1659: * @since 1.3
1660: */
1661: public void autodetectAnnotations(boolean mode) {
1662: if (annotationConfiguration != null) {
1663: annotationConfiguration.autodetectAnnotations(mode);
1664: }
1665: }
1666:
1667: /**
1668: * @deprecated since 1.3, use {@link InitializationException} instead
1669: */
1670: public static class InitializationException extends
1671: XStreamException {
1672: public InitializationException(String message, Throwable cause) {
1673: super (message, cause);
1674: }
1675:
1676: public InitializationException(String message) {
1677: super (message);
1678: }
1679: }
1680:
1681: private Object readResolve() {
1682: jvm = new JVM();
1683: return this;
1684: }
1685:
1686: }
|