Index: 3rdParty_sources/versions.txt =================================================================== diff -u -rf08f6c4324d6ce0ca8dc43b875a498d89dd91116 -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/versions.txt (.../versions.txt) (revision f08f6c4324d6ce0ca8dc43b875a498d89dd91116) +++ 3rdParty_sources/versions.txt (.../versions.txt) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -48,4 +48,4 @@ xmltooling 1.4.0 -XStream 1.1.3 \ No newline at end of file +XStream 1.5.0 \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/InitializationException.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/InitializationException.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/InitializationException.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2007, 2008, 2013 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 22. October 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream; + +/** + * Exception thrown configuring an XStream instance. + * + * @author Joe Walnes + * @author Jörg Schaible + * @since 1.3 + */ +public class InitializationException extends XStreamException { + public InitializationException(String message, Throwable cause) { + super(message, cause); + } + + public InitializationException(String message) { + super(message); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/MarshallingStrategy.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/MarshallingStrategy.java (.../MarshallingStrategy.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/MarshallingStrategy.java (.../MarshallingStrategy.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,15 +1,54 @@ +/* + * Copyright (C) 2004, 2006 Joe Walnes. + * Copyright (C) 2007, 2009, 2014 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 16. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.DataHolder; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.core.DefaultConverterLookup; -import com.thoughtworks.xstream.alias.ClassMapper; -import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.mapper.Mapper; + +/** + * Core interface for a marshalling strategy. + *

+ * An implementation dictates how an object graph is marshalled and unmarshalled. It is the implementation's + * responsibility to deal with references between the objects. + *

+ */ public interface MarshallingStrategy { - Object unmarshal(Object root, HierarchicalStreamReader reader, DataHolder dataHolder, DefaultConverterLookup converterLookup, ClassMapper classMapper); + /** + * Marshal an object graph. + * + * @param writer the target for the marshalled data + * @param obj the object to marshal + * @param converterLookup the converter store + * @param mapper the mapper chain + * @param dataHolder the holder for additional data and state while marshalling + */ + void marshal(HierarchicalStreamWriter writer, Object obj, ConverterLookup converterLookup, Mapper mapper, + DataHolder dataHolder); - void marshal(HierarchicalStreamWriter writer, Object obj, DefaultConverterLookup converterLookup, ClassMapper classMapper, DataHolder dataHolder); - + /** + * Unmarshal an object graph. + * + * @param root a possible root object (should be {@code null} in normal cases) + * @param reader the source for the unmarshalled object data + * @param dataHolder the holder for additional data and state while marshalling + * @param converterLookup the converter store + * @param mapper the mapper chain + * @return the unmarshalled object + */ + Object unmarshal(Object root, HierarchicalStreamReader reader, DataHolder dataHolder, ConverterLookup converterLookup, + Mapper mapper); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/XStream.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/XStream.java (.../XStream.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/XStream.java (.../XStream.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,242 +1,663 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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 com.thoughtworks.xstream.alias.ClassMapper; +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.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URI; +import java.net.URL; +import java.nio.charset.Charset; +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; +import java.util.Currency; +import java.util.Date; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +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.SortedSet; +import java.util.TimeZone; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.UUID; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; + +import com.thoughtworks.xstream.converters.ConversionException; 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.basic.*; -import com.thoughtworks.xstream.converters.collections.*; -import com.thoughtworks.xstream.converters.extended.*; +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.StringBuilderConverter; +import com.thoughtworks.xstream.converters.basic.StringConverter; +import com.thoughtworks.xstream.converters.basic.URIConverter; +import com.thoughtworks.xstream.converters.basic.URLConverter; +import com.thoughtworks.xstream.converters.basic.UUIDConverter; +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.SingletonCollectionConverter; +import com.thoughtworks.xstream.converters.collections.SingletonMapConverter; +import com.thoughtworks.xstream.converters.collections.TreeMapConverter; +import com.thoughtworks.xstream.converters.collections.TreeSetConverter; +import com.thoughtworks.xstream.converters.enums.EnumConverter; +import com.thoughtworks.xstream.converters.enums.EnumMapConverter; +import com.thoughtworks.xstream.converters.enums.EnumSetConverter; +import com.thoughtworks.xstream.converters.extended.CharsetConverter; +import com.thoughtworks.xstream.converters.extended.ColorConverter; +import com.thoughtworks.xstream.converters.extended.CurrencyConverter; +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.JavaFieldConverter; +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.RegexPatternConverter; +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.StackTraceElementConverter; +import com.thoughtworks.xstream.converters.extended.TextAttributeConverter; +import com.thoughtworks.xstream.converters.extended.ThrowableConverter; 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.SerializableConverter; -import com.thoughtworks.xstream.core.*; -import com.thoughtworks.xstream.core.util.ClassLoaderReference; +import com.thoughtworks.xstream.core.ClassLoaderReference; +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.CompositeClassLoader; import com.thoughtworks.xstream.core.util.CustomObjectInputStream; import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; +import com.thoughtworks.xstream.core.util.SelfStreamingInstanceChecker; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; +import com.thoughtworks.xstream.io.StatefulWriter; import com.thoughtworks.xstream.io.xml.XppDriver; -import com.thoughtworks.xstream.mapper.*; +import com.thoughtworks.xstream.mapper.AnnotationMapper; +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.EnumMapper; +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.SecurityMapper; +import com.thoughtworks.xstream.mapper.SystemAttributeAliasingMapper; +import com.thoughtworks.xstream.mapper.XStream11XmlFriendlyMapper; +import com.thoughtworks.xstream.security.AnyTypePermission; +import com.thoughtworks.xstream.security.ArrayTypePermission; +import com.thoughtworks.xstream.security.ExplicitTypePermission; +import com.thoughtworks.xstream.security.InterfaceTypePermission; +import com.thoughtworks.xstream.security.NoPermission; +import com.thoughtworks.xstream.security.NoTypePermission; +import com.thoughtworks.xstream.security.NullPermission; +import com.thoughtworks.xstream.security.PrimitiveTypePermission; +import com.thoughtworks.xstream.security.RegExpTypePermission; +import com.thoughtworks.xstream.security.TypeHierarchyPermission; +import com.thoughtworks.xstream.security.TypePermission; +import com.thoughtworks.xstream.security.WildcardTypePermission; -import java.io.*; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.net.URL; -import java.sql.Time; -import java.sql.Timestamp; -import java.util.*; /** * Simple facade to XStream library, a Java-XML serialization tool. - *

- *


Example
+ * 

+ *


+ * Example
+ * + *
  * XStream xstream = new XStream();
  * String xml = xstream.toXML(myObject); // serialize to XML
  * Object myObject2 = xstream.fromXML(xml); // deserialize from XML
- * 

- *

+ *

+ * + *
+ *
*

Aliasing classes

- *

- *

To create shorter XML, you can specify aliases for classes using - * the alias() method. - * For example, you can shorten all occurences of element - * <com.blah.MyThing> to - * <my-thing> by registering an alias for the class. - *


- * xstream.alias("my-thing", MyThing.class);
- * 

- *

+ *

+ * To create shorter XML, you can specify aliases for classes using the alias() method. For example, you + * can shorten all occurrences of element <com.blah.MyThing> to <my-thing> by + * registering an alias for the class. + *

+ *


+ *
+ * + *
+ * xstream.alias("my-thing", MyThing.class);
+ * 
+ * + *
+ *
*

Converters

- *

- *

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.

- *

- *

Extra converters can be registered using the registerConverter() - * 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.

- *

- *


Example
+ * 

+ * 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. + *

+ *

+ * Extra converters can be registered using the registerConverter() 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. + *

+ *

+ *


+ * Example
+ * + *
  * xstream.registerConverter(new SqlTimestampConverter());
  * xstream.registerConverter(new DynamicProxyConverter());
- * 

- *

The default converter, ie the converter which will be used if no other registered - * converter is suitable, can be configured by either one of the constructors - * or can be changed using the changeDefaultConverter() method. - * If not set, XStream uses {@link com.thoughtworks.xstream.converters.reflection.ReflectionConverter} - * as the initial default converter. + *

+ * + *
+ *
+ *

+ * 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. *

- *

- *


Example
- * xstream.changeDefaultConverter(new ACustomDefaultConverter());
- * 

- *

+ *

+ *


+ * Example
+ * + *
+ * xstream.registerConverter(new CustomDefaultConverter(), XStream.PRIORITY_VERY_LOW);
+ * 
+ * + *
+ *
*

Object graphs

- *

- *

XStream has support for object graphs; a deserialized object graph - * will keep references intact, including circular references.

- *

- *

XStream can signify references in XML using either XPath or IDs. The - * mode can be changed using setMode():

- *

- * + *

+ * XStream has support for object graphs; a deserialized object graph will keep references intact, including circular + * references. + *

+ *

+ * XStream can signify references in XML using either relative/absolute XPath or IDs. The mode can be changed using + * setMode(): + *

+ *
+ * * - * - * + * + * * * + * + * + * + * + * + * + * + * + * + * + * + * * - * + * * * * - * + * * *
xstream.setMode(XStream.XPATH_REFERENCES);(Default) Uses XPath references to signify duplicate - * references. This produces XML with the least clutter.xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES);(Default) Uses XPath relative references to signify duplicate references. This produces XML with the least + * clutter.
xstream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES);Uses XPath absolute references to signify duplicate references. This produces XML with the least clutter.
xstream.setMode(XStream.SINGLE_NODE_XPATH_RELATIVE_REFERENCES);Uses XPath relative references to signify duplicate references. The XPath expression ensures that a single node + * only is selected always.
xstream.setMode(XStream.SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES);Uses XPath absolute references to signify duplicate references. The XPath expression ensures that a single node + * only is selected always.
xstream.setMode(XStream.ID_REFERENCES);Uses ID references to signify duplicate references. In some - * scenarios, such as when using hand-written XML, this is - * easier to work with.Uses ID references to signify duplicate references. In some scenarios, such as when using hand-written XML, this + * is easier to work with.
xstream.setMode(XStream.NO_REFERENCES);This disables object graph support and treats the object - * structure like a tree. Duplicate references are treated - * as two seperate objects and circular references cause an - * exception. This is slightly faster and uses less memory - * than the other two modes.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.
- * *

Thread safety

- * - *

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. - * + *

+ * 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. + * Note, that this only applies if annotations are not + * auto-detected on-the-fly. + *

*

Implicit collections

- *

- *

To avoid the need for special tags for collections, you can define implicit collections using one of the - * addImplicitCollection methods.

- * + *

+ * To avoid the need for special tags for collections, you can define implicit collections using one of the + * addImplicitCollection methods. + *

+ * * @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 final ReflectionProvider reflectionProvider; + private final HierarchicalStreamDriver hierarchicalStreamDriver; + private final ClassLoaderReference classLoaderReference; + private MarshallingStrategy marshallingStrategy; + private final ConverterLookup converterLookup; + private final ConverterRegistry converterRegistry; + private final 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 SecurityMapper securityMapper; + private AnnotationMapper annotationMapper; - private ReflectionProvider reflectionProvider; - private HierarchicalStreamDriver hierarchicalStreamDriver; - private MarshallingStrategy marshallingStrategy; - private ClassLoaderReference classLoaderReference; // TODO: Should be changeable - - private ClassMapper classMapper; - private DefaultConverterLookup converterLookup; - private JVM jvm = new JVM(); - public static final int NO_REFERENCES = 1001; public static final int ID_REFERENCES = 1002; - public static final int XPATH_REFERENCES = 1003; + public static final int XPATH_RELATIVE_REFERENCES = 1003; + public static final int XPATH_ABSOLUTE_REFERENCES = 1004; + public static final int SINGLE_NODE_XPATH_RELATIVE_REFERENCES = 1005; + public static final int SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES = 1006; - private static final int PRIORITY_NORMAL = 0; - private static final int PRIORITY_LOW = -10; - private static final int PRIORITY_VERY_LOW = -20; + 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 Pattern IGNORE_ALL = Pattern.compile(".*"); + + /** + * 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, null, new XppDriver()); + this(new XppDriver()); } /** - * @deprecated As of XStream 1.1.1, a default Converter is unnecessary as you can register a Converter with an - * associated priority. Use an alternate constructor. + * Constructs an XStream with a special {@link ReflectionProvider}. + *

+ * The instance will use the {@link XppDriver} as default. + *

+ * + * @param reflectionProvider the reflection provider to use or null for best matching reflection provider + * @throws InitializationException in case of an initialization problem */ - public XStream(Converter defaultConverter) { - this(null, null, new XppDriver(), null); - registerConverter(defaultConverter, PRIORITY_VERY_LOW); + public XStream(final ReflectionProvider reflectionProvider) { + this(reflectionProvider, new XppDriver()); } - public XStream(HierarchicalStreamDriver hierarchicalStreamDriver) { - this(null, null, hierarchicalStreamDriver); + /** + * Constructs an XStream with a special {@link HierarchicalStreamDriver}. + *

+ * The instance will tries to determine the best match for the {@link ReflectionProvider} on its own. + *

+ * + * @param hierarchicalStreamDriver the driver instance + * @throws InitializationException in case of an initialization problem + */ + public XStream(final HierarchicalStreamDriver hierarchicalStreamDriver) { + this(null, hierarchicalStreamDriver); } - public XStream(ReflectionProvider reflectionProvider) { - this(reflectionProvider, null, new XppDriver()); + /** + * Constructs an XStream with a special {@link HierarchicalStreamDriver} and {@link ReflectionProvider}. + * + * @param reflectionProvider the reflection provider to use or null for best matching Provider + * @param hierarchicalStreamDriver the driver instance + * @throws InitializationException in case of an initialization problem + */ + public XStream(final ReflectionProvider reflectionProvider, final HierarchicalStreamDriver hierarchicalStreamDriver) { + this(reflectionProvider, hierarchicalStreamDriver, new ClassLoaderReference(new CompositeClassLoader())); } - public XStream(ReflectionProvider reflectionProvider, HierarchicalStreamDriver hierarchicalStreamDriver) { - this(reflectionProvider, null, hierarchicalStreamDriver); + /** + * Constructs an XStream with a special {@link HierarchicalStreamDriver}, {@link ReflectionProvider} and a + * {@link ClassLoaderReference}. + * + * @param reflectionProvider the reflection provider to use or null for best matching Provider + * @param driver the driver instance + * @param classLoaderReference the reference to the {@link ClassLoader} to use + * @throws InitializationException in case of an initialization problem + * @since 1.4.5 + */ + public XStream( + final ReflectionProvider reflectionProvider, final HierarchicalStreamDriver driver, + final ClassLoaderReference classLoaderReference) { + this(reflectionProvider, driver, classLoaderReference, null); } - public XStream(ReflectionProvider reflectionProvider, ClassMapper classMapper, HierarchicalStreamDriver driver) { - this(reflectionProvider, classMapper, driver, null); + /** + * Constructs an XStream with a special {@link HierarchicalStreamDriver}, {@link ReflectionProvider} and the + * {@link ClassLoader} to use. + * + * @throws InitializationException in case of an initialization problem + * @since 1.3 + * @deprecated As of 1.4.5 use {@link #XStream(ReflectionProvider, HierarchicalStreamDriver, ClassLoaderReference)} + */ + @Deprecated + public XStream( + final ReflectionProvider reflectionProvider, final HierarchicalStreamDriver driver, + final ClassLoader classLoader) { + this(reflectionProvider, driver, classLoader, null); } - public XStream(ReflectionProvider reflectionProvider, ClassMapper classMapper, HierarchicalStreamDriver driver, String classAttributeIdentifier) { - jvm = new JVM(); + /** + * Constructs an XStream with a special {@link HierarchicalStreamDriver}, {@link ReflectionProvider}, a prepared + * {@link Mapper} chain and the {@link ClassLoader} to use. + * + * @param reflectionProvider the reflection provider to use or null for best matching Provider + * @param driver the driver instance + * @param classLoader the {@link ClassLoader} to use + * @param mapper the instance with the {@link Mapper} chain or null for the default chain + * @throws InitializationException in case of an initialization problem + * @since 1.3 + * @deprecated As of 1.4.5 use + * {@link #XStream(ReflectionProvider, HierarchicalStreamDriver, ClassLoaderReference, Mapper)} + */ + @Deprecated + public XStream( + final ReflectionProvider reflectionProvider, final HierarchicalStreamDriver driver, + final ClassLoader classLoader, final Mapper mapper) { + this(reflectionProvider, driver, new ClassLoaderReference(classLoader), mapper, new DefaultConverterLookup()); + } + + /** + * Constructs an XStream with a special {@link HierarchicalStreamDriver}, {@link ReflectionProvider}, a prepared + * {@link Mapper} chain and the {@link ClassLoaderReference}. + *

+ * The {@link ClassLoaderReference} should also be used for the {@link Mapper} chain. + *

+ * + * @param reflectionProvider the reflection provider to use or null for best matching Provider + * @param driver the driver instance + * @param classLoaderReference the reference to the {@link ClassLoader} to use + * @param mapper the instance with the {@link Mapper} chain or null for the default chain + * @throws InitializationException in case of an initialization problem + * @since 1.4.5 + */ + public XStream( + final ReflectionProvider reflectionProvider, final HierarchicalStreamDriver driver, + final ClassLoaderReference classLoaderReference, final Mapper mapper) { + this(reflectionProvider, driver, classLoaderReference, mapper, new DefaultConverterLookup()); + } + + private XStream( + final ReflectionProvider reflectionProvider, final HierarchicalStreamDriver driver, + final ClassLoaderReference classLoader, final Mapper mapper, + final DefaultConverterLookup defaultConverterLookup) { + this(reflectionProvider, driver, classLoader, mapper, new ConverterLookup() { + @Override + public Converter lookupConverterForType(final Class type) { + return defaultConverterLookup.lookupConverterForType(type); + } + }, new ConverterRegistry() { + @Override + public void registerConverter(final Converter converter, final int priority) { + defaultConverterLookup.registerConverter(converter, priority); + } + }); + } + + /** + * Constructs an XStream with a special {@link HierarchicalStreamDriver}, {@link ReflectionProvider}, a prepared + * {@link Mapper} chain, the {@link ClassLoaderReference} and an own {@link ConverterLookup} and + * {@link ConverterRegistry}. + * + * @param reflectionProvider the reflection provider to use or null for best matching Provider + * @param driver the driver instance + * @param classLoader the {@link ClassLoader} to use + * @param mapper the instance with the {@link Mapper} chain or null for the default chain + * @param converterLookup the instance that is used to lookup the converters + * @param converterRegistry an instance to manage the converter instances + * @throws InitializationException in case of an initialization problem + * @since 1.3 + * @deprecated As of 1.4.5 use + * {@link #XStream(ReflectionProvider, HierarchicalStreamDriver, ClassLoaderReference, Mapper, ConverterLookup, ConverterRegistry)} + */ + @Deprecated + public XStream( + final ReflectionProvider reflectionProvider, final HierarchicalStreamDriver driver, + final ClassLoader classLoader, final Mapper mapper, final ConverterLookup converterLookup, + final ConverterRegistry converterRegistry) { + this(reflectionProvider, driver, new ClassLoaderReference(classLoader), mapper, converterLookup, + converterRegistry); + } + + /** + * Constructs an XStream with a special {@link HierarchicalStreamDriver}, {@link ReflectionProvider}, a prepared + * {@link Mapper} chain, the {@link ClassLoaderReference} and an own {@link ConverterLookup} and + * {@link ConverterRegistry}. + *

+ * The ClassLoaderReference should also be used for the Mapper chain. The ConverterLookup should access the + * ConverterRegistry if you intent to register {@link Converter} instances with XStream facade or you are using + * annotations. + *

+ * + * @param reflectionProvider the reflection provider to use or null for best matching Provider + * @param driver the driver instance + * @param classLoaderReference the reference to the {@link ClassLoader} to use + * @param mapper the instance with the {@link Mapper} chain or null for the default chain + * @param converterLookup the instance that is used to lookup the converters + * @param converterRegistry an instance to manage the converter instances or null to prevent any further + * registry (including annotations) + * @throws InitializationException in case of an initialization problem + * @since 1.4.5 + */ + public XStream( + ReflectionProvider reflectionProvider, final HierarchicalStreamDriver driver, + final ClassLoaderReference classLoaderReference, final Mapper mapper, + final ConverterLookup converterLookup, final ConverterRegistry converterRegistry) { if (reflectionProvider == null) { - reflectionProvider = jvm.bestReflectionProvider(); + reflectionProvider = JVM.newReflectionProvider(); } this.reflectionProvider = reflectionProvider; - this.hierarchicalStreamDriver = driver; - this.classLoaderReference = new ClassLoaderReference(new CompositeClassLoader()); - this.classMapper = classMapper == null ? buildMapper(classAttributeIdentifier) : classMapper; - converterLookup = new DefaultConverterLookup(this.classMapper); + hierarchicalStreamDriver = driver; + this.classLoaderReference = classLoaderReference; + this.converterLookup = converterLookup; + this.converterRegistry = converterRegistry; + this.mapper = mapper == null ? buildMapper() : mapper; + + setupMappers(); + setupSecurity(); setupAliases(); setupDefaultImplementations(); setupConverters(); setupImmutableTypes(); - setMode(XPATH_REFERENCES); + setMode(XPATH_RELATIVE_REFERENCES); } - /** - * @deprecated As of XStream 1.1.1, a default Converter is unnecessary as you can register a Converter with an - * associated priority. Use an alternate constructor. - */ - public XStream(ReflectionProvider reflectionProvider, ClassMapper classMapper, HierarchicalStreamDriver driver, String classAttributeIdentifier, Converter defaultConverter) { - this(reflectionProvider, classMapper, driver, classAttributeIdentifier); - registerConverter(defaultConverter, PRIORITY_VERY_LOW); - } - - private ClassMapper buildMapper(String classAttributeIdentifier) { - MapperWrapper mapper = new DefaultMapper(classLoaderReference, classAttributeIdentifier); - mapper = new XmlFriendlyMapper(mapper); + 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); - classAliasingMapper = (ClassAliasingMapper) mapper; // need a reference to that one mapper = new FieldAliasingMapper(mapper); - fieldAliasingMapper = (FieldAliasingMapper) mapper; // need a reference to that one + mapper = new AttributeAliasingMapper(mapper); + mapper = new SystemAttributeAliasingMapper(mapper); mapper = new ImplicitCollectionMapper(mapper); - implicitCollectionMapper = (ImplicitCollectionMapper)mapper; // need a reference to this one - mapper = new DynamicProxyMapper(mapper); - if (JVM.is15()) { - mapper = new EnumMapper(mapper); - } mapper = new OuterClassMapper(mapper); mapper = new ArrayMapper(mapper); mapper = new DefaultImplementationsMapper(mapper); - defaultImplementationsMapper = (DefaultImplementationsMapper) mapper; // and that one + mapper = new AttributeMapper(mapper, converterLookup, reflectionProvider); + mapper = new EnumMapper(mapper); + mapper = new LocalConversionMapper(mapper); mapper = new ImmutableTypesMapper(mapper); - immutableTypesMapper = (ImmutableTypesMapper)mapper; // that one too - mapper = wrapMapper(mapper); + mapper = new SecurityMapper(mapper); + mapper = new AnnotationMapper(mapper, converterRegistry, converterLookup, classLoaderReference, + reflectionProvider); + mapper = wrapMapper((MapperWrapper)mapper); mapper = new CachingMapper(mapper); return mapper; } - protected MapperWrapper wrapMapper(MapperWrapper next) { + @SuppressWarnings("unused") + private Mapper buildMapperDynamically(final String className, final Class[] constructorParamTypes, + final Object[] constructorParamValues) { + try { + final Class type = Class.forName(className, false, classLoaderReference.getReference()); + final Constructor constructor = type.getConstructor(constructorParamTypes); + return (Mapper)constructor.newInstance(constructorParamValues); + } catch (final Exception e) { + throw new InitializationException("Could not instantiate mapper : " + className, e); + } catch (final LinkageError e) { + throw new InitializationException("Could not instantiate mapper : " + className, e); + } + } + + protected MapperWrapper wrapMapper(final MapperWrapper next) { return next; } + /** + * @deprecated As of upcoming + */ + @Deprecated + protected boolean useXStream11XmlFriendlyMapper() { + return false; + } + + private void setupMappers() { + packageAliasingMapper = mapper.lookupMapperOfType(PackageAliasingMapper.class); + classAliasingMapper = mapper.lookupMapperOfType(ClassAliasingMapper.class); + fieldAliasingMapper = mapper.lookupMapperOfType(FieldAliasingMapper.class); + attributeMapper = mapper.lookupMapperOfType(AttributeMapper.class); + attributeAliasingMapper = mapper.lookupMapperOfType(AttributeAliasingMapper.class); + systemAttributeAliasingMapper = mapper.lookupMapperOfType(SystemAttributeAliasingMapper.class); + implicitCollectionMapper = mapper.lookupMapperOfType(ImplicitCollectionMapper.class); + defaultImplementationsMapper = mapper.lookupMapperOfType(DefaultImplementationsMapper.class); + immutableTypesMapper = mapper.lookupMapperOfType(ImmutableTypesMapper.class); + localConversionMapper = mapper.lookupMapperOfType(LocalConversionMapper.class); + securityMapper = mapper.lookupMapperOfType(SecurityMapper.class); + annotationMapper = mapper.lookupMapperOfType(AnnotationMapper.class); + } + + protected void setupSecurity() { + if (securityMapper == null) { + return; + } + + addPermission(NullPermission.NULL); + addPermission(PrimitiveTypePermission.PRIMITIVES); + addPermission(ArrayTypePermission.ARRAYS); + addPermission(InterfaceTypePermission.INTERFACES); + allowTypeHierarchy(Calendar.class); + allowTypeHierarchy(Collection.class); + allowTypeHierarchy(Enum.class); + allowTypeHierarchy(Map.class); + allowTypeHierarchy(Map.Entry.class); + allowTypeHierarchy(Member.class); + allowTypeHierarchy(Number.class); + allowTypeHierarchy(Throwable.class); + allowTypeHierarchy(TimeZone.class); + + final Set> types = new HashSet>(); + types.addAll(Arrays.>asList(BitSet.class, Charset.class, Class.class, Currency.class, Date.class, + DecimalFormatSymbols.class, File.class, Locale.class, Object.class, Pattern.class, StackTraceElement.class, + String.class, StringBuffer.class, StringBuilder.class, URL.class, URI.class, UUID.class)); + if (JVM.isSQLAvailable()) { + types.add(JVM.loadClassForName("java.sql.Timestamp")); + types.add(JVM.loadClassForName("java.sql.Time")); + types.add(JVM.loadClassForName("java.sql.Date")); + } + types.remove(null); + allowTypes(types.toArray(new Class[types.size()])); + } + protected void setupAliases() { - alias("null", ClassMapper.Null.class); + if (classAliasingMapper == null) { + return; + } + + alias("null", Mapper.Null.class); alias("int", Integer.class); alias("float", Float.class); alias("double", Double.class); @@ -250,153 +671,194 @@ alias("big-int", BigInteger.class); alias("big-decimal", BigDecimal.class); - alias("string-buffer", StringBuffer.class); alias("string", String.class); + alias("string-buffer", StringBuffer.class); + alias("string-builder", StringBuilder.class); + alias("uuid", UUID.class); alias("java-class", Class.class); alias("method", Method.class); alias("constructor", Constructor.class); + alias("field", Field.class); alias("date", Date.class); + alias("gregorian-calendar", Calendar.class); + alias("uri", URI.class); alias("url", URL.class); + alias("file", File.class); + alias("locale", Locale.class); alias("bit-set", BitSet.class); + alias("trace", StackTraceElement.class); + alias("currency", Currency.class); alias("map", Map.class); alias("entry", Map.Entry.class); alias("properties", Properties.class); alias("list", List.class); alias("set", Set.class); + alias("sorted-set", SortedSet.class); alias("linked-list", LinkedList.class); alias("vector", Vector.class); alias("tree-map", TreeMap.class); alias("tree-set", TreeSet.class); alias("hashtable", Hashtable.class); + alias("linked-hash-map", LinkedHashMap.class); + alias("linked-hash-set", LinkedHashSet.class); + alias("concurrent-hash-map", ConcurrentHashMap.class); - // 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("enum-set", EnumSet.class); + alias("enum-map", EnumMap.class); + alias("empty-list", Collections.EMPTY_LIST.getClass()); + alias("empty-map", Collections.EMPTY_MAP.getClass()); + alias("empty-set", Collections.EMPTY_SET.getClass()); + alias("singleton-list", Collections.singletonList(this).getClass()); + alias("singleton-map", Collections.singletonMap(this, null).getClass()); + alias("singleton-set", Collections.singleton(this).getClass()); - alias("sql-timestamp", Timestamp.class); - alias("sql-time", Time.class); - alias("sql-date", java.sql.Date.class); - alias("file", File.class); - alias("locale", Locale.class); - alias("gregorian-calendar", Calendar.class); + if (JVM.isAWTAvailable()) { + // 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.loadClassForName("java.awt.Color", false)); + alias("awt-font", JVM.loadClassForName("java.awt.Font", false)); + alias("awt-text-attribute", JVM.loadClassForName("java.awt.font.TextAttribute")); + } - - if (JVM.is14()) { - 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")); - // since jdk 1.4 included, but previously available as separate package ... - alias("auth-subject", jvm.loadClass("javax.security.auth.Subject")); + if (JVM.isSQLAvailable()) { + alias("sql-timestamp", JVM.loadClassForName("java.sql.Timestamp")); + alias("sql-time", JVM.loadClassForName("java.sql.Time")); + alias("sql-date", JVM.loadClassForName("java.sql.Date")); } - if (JVM.is15()) { - alias("enum-set", jvm.loadClass("java.util.EnumSet")); - alias("enum-map", jvm.loadClass("java.util.EnumMap")); + aliasType("charset", Charset.class); + + if (JVM.loadClassForName("javax.security.auth.Subject") != null) { + aliasDynamically("auth-subject", "javax.security.auth.Subject"); } + if (JVM.loadClassForName("javax.xml.datatype.Duration") != null) { + aliasDynamically("duration", "javax.xml.datatype.Duration"); + } } + private void aliasDynamically(final String alias, final String className) { + final Class type = JVM.loadClassForName(className); + if (type != null) { + alias(alias, type); + } + } + protected void setupDefaultImplementations() { + if (defaultImplementationsMapper == null) { + return; + } addDefaultImplementation(HashMap.class, Map.class); addDefaultImplementation(ArrayList.class, List.class); addDefaultImplementation(HashSet.class, Set.class); + addDefaultImplementation(TreeSet.class, SortedSet.class); addDefaultImplementation(GregorianCalendar.class, Calendar.class); } protected void setupConverters() { - ReflectionConverter reflectionConverter = new ReflectionConverter(classMapper, reflectionProvider); - registerConverter(reflectionConverter, PRIORITY_VERY_LOW); + registerConverter(new ReflectionConverter(mapper, reflectionProvider), PRIORITY_VERY_LOW); - registerConverter(new SerializableConverter(classMapper, reflectionProvider), PRIORITY_LOW); - registerConverter(new ExternalizableConverter(classMapper), PRIORITY_LOW); + registerConverter(new SerializableConverter(mapper, reflectionProvider, classLoaderReference), PRIORITY_LOW); + registerConverter(new ExternalizableConverter(mapper, classLoaderReference), 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(new CharConverter(), 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 StringBuilderConverter(), PRIORITY_NORMAL); + registerConverter(new ThrowableConverter(converterLookup), PRIORITY_NORMAL); + registerConverter(new StackTraceElementConverter(), PRIORITY_NORMAL); registerConverter(new DateConverter(), PRIORITY_NORMAL); + registerConverter(new GregorianCalendarConverter(), PRIORITY_NORMAL); + registerConverter(new RegexPatternConverter(), PRIORITY_NORMAL); + registerConverter(new CurrencyConverter(), PRIORITY_NORMAL); + registerConverter(new CharsetConverter(), PRIORITY_NORMAL); + registerConverter(new LocaleConverter(), PRIORITY_NORMAL); registerConverter(new BitSetConverter(), PRIORITY_NORMAL); + registerConverter(new UUIDConverter(), PRIORITY_NORMAL); + registerConverter(new URIConverter(), PRIORITY_NORMAL); registerConverter(new URLConverter(), PRIORITY_NORMAL); registerConverter(new BigIntegerConverter(), PRIORITY_NORMAL); registerConverter(new BigDecimalConverter(), PRIORITY_NORMAL); - registerConverter(new ArrayConverter(classMapper), PRIORITY_NORMAL); + registerConverter(new ArrayConverter(mapper), PRIORITY_NORMAL); registerConverter(new CharArrayConverter(), PRIORITY_NORMAL); - registerConverter(new CollectionConverter(classMapper), PRIORITY_NORMAL); - registerConverter(new MapConverter(classMapper), PRIORITY_NORMAL); - registerConverter(new TreeMapConverter(classMapper), PRIORITY_NORMAL); - registerConverter(new TreeSetConverter(classMapper), 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 SingletonCollectionConverter(mapper), PRIORITY_NORMAL); + registerConverter(new SingletonMapConverter(mapper), PRIORITY_NORMAL); registerConverter(new PropertiesConverter(), PRIORITY_NORMAL); - registerConverter(new EncodedByteArrayConverter(), PRIORITY_NORMAL); + registerConverter((Converter)new EncodedByteArrayConverter(), PRIORITY_NORMAL); + registerConverter(new EnumConverter(), PRIORITY_NORMAL); + registerConverter(new EnumSetConverter(mapper), PRIORITY_NORMAL); + registerConverter(new EnumMapConverter(mapper), PRIORITY_NORMAL); registerConverter(new FileConverter(), PRIORITY_NORMAL); - registerConverter(new SqlTimestampConverter(), PRIORITY_NORMAL); - registerConverter(new SqlTimeConverter(), PRIORITY_NORMAL); - registerConverter(new SqlDateConverter(), PRIORITY_NORMAL); - registerConverter(new DynamicProxyConverter(classMapper, classLoaderReference), PRIORITY_NORMAL); + if (JVM.isSQLAvailable()) { + 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(), PRIORITY_NORMAL); - registerConverter(new FontConverter(), PRIORITY_NORMAL); - registerConverter(new ColorConverter(), 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.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.SubjectConverter", PRIORITY_NORMAL, - new Class[] {Mapper.class}, new Object[] {classMapper}); + registerConverter(new JavaMethodConverter(classLoaderReference), PRIORITY_NORMAL); + registerConverter(new JavaFieldConverter(classLoaderReference), PRIORITY_NORMAL); + if (JVM.isAWTAvailable()) { + registerConverter(new FontConverter(mapper), PRIORITY_NORMAL); + registerConverter(new ColorConverter(), PRIORITY_NORMAL); + registerConverter(new TextAttributeConverter(), PRIORITY_NORMAL); } + if (JVM.isSwingAvailable()) { + registerConverter(new LookAndFeelConverter(mapper, reflectionProvider), PRIORITY_NORMAL); + } - if (JVM.is15()) { - // late bound converters - allows XStream to be compiled on earlier JDKs - 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[] {classMapper}); - dynamicallyRegisterConverter( - "com.thoughtworks.xstream.converters.enums.EnumMapConverter", PRIORITY_NORMAL, - new Class[] {Mapper.class}, new Object[] {classMapper}); + if (JVM.loadClassForName("javax.security.auth.Subject") != null) { + registerConverterDynamically("com.thoughtworks.xstream.converters.extended.SubjectConverter", + PRIORITY_NORMAL, new Class[]{Mapper.class}, new Object[]{mapper}); } + if (JVM.loadClassForName("javax.xml.datatype.Duration") != null) { + registerConverterDynamically("com.thoughtworks.xstream.converters.extended.DurationConverter", + PRIORITY_NORMAL, null, null); + } + + registerConverter(new SelfStreamingInstanceChecker(converterLookup, this), PRIORITY_NORMAL); } - private void dynamicallyRegisterConverter(String className, int priority, - Class[] constructorParamTypes, Object[] constructorParamValues) { + private void registerConverterDynamically(final String className, final int priority, + final Class[] constructorParamTypes, final Object[] constructorParamValues) { try { - Class type = Class.forName(className, false, classLoaderReference.getReference()); - Constructor constructor = type.getConstructor(constructorParamTypes); - Converter converter = (Converter) constructor.newInstance(constructorParamValues); - registerConverter(converter, priority); - } catch (Exception e) { - throw new InitializationException("Could not instatiate converter : " + className, e); + final Class type = Class.forName(className, false, classLoaderReference.getReference()); + final Constructor constructor = type.getConstructor(constructorParamTypes); + final Object instance = constructor.newInstance(constructorParamValues); + if (instance instanceof Converter) { + registerConverter((Converter)instance, priority); + } else if (instance instanceof SingleValueConverter) { + registerConverter((SingleValueConverter)instance, priority); + } + } catch (final Exception e) { + throw new InitializationException("Could not instantiate converter : " + className, e); + } catch (final LinkageError 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); @@ -416,446 +878,1180 @@ addImmutableType(Short.class); // additional types - addImmutableType(ClassMapper.Null.class); + addImmutableType(Mapper.Null.class); addImmutableType(BigDecimal.class); addImmutableType(BigInteger.class); addImmutableType(String.class); + addImmutableType(Charset.class); + addImmutableType(Currency.class); + addImmutableType(URI.class); addImmutableType(URL.class); addImmutableType(File.class); addImmutableType(Class.class); + + addImmutableType(Collections.EMPTY_LIST.getClass()); + addImmutableType(Collections.EMPTY_SET.getClass()); + addImmutableType(Collections.EMPTY_MAP.getClass()); + + if (JVM.isAWTAvailable()) { + addImmutableTypeDynamically("java.awt.font.TextAttribute"); + } } - public void setMarshallingStrategy(MarshallingStrategy marshallingStrategy) { + private void addImmutableTypeDynamically(final String className) { + final Class type = JVM.loadClassForName(className); + if (type != null) { + addImmutableType(type); + } + } + + /** + * Setter for an arbitrary marshalling strategy. + * + * @param marshallingStrategy the implementation to use + * @see #setMode(int) + */ + public void setMarshallingStrategy(final 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 stringWriter = new StringWriter(); - HierarchicalStreamWriter writer = hierarchicalStreamDriver.createWriter(stringWriter); - marshal(obj, writer); - writer.flush(); - writer.close(); - return stringWriter.toString(); + public String toXML(final Object obj) { + final Writer writer = new StringWriter(); + toXML(obj, writer); + return writer.toString(); } /** - * Serialize an object to the given Writer as pretty-printed XML. + * 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); - marshal(obj, writer); - writer.flush(); + public void toXML(final Object obj, final Writer out) { + @SuppressWarnings("resource") + final HierarchicalStreamWriter writer = hierarchicalStreamDriver.createWriter(out); + try { + marshal(obj, writer); + } finally { + writer.flush(); + } } /** - * Serialize an object to the given OutputStream as pretty-printed XML. + * 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); - marshal(obj, writer); - writer.flush(); + public void toXML(final Object obj, final OutputStream out) { + @SuppressWarnings("resource") + final 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) { + public void marshal(final Object obj, final 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. + * + * @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, classMapper, dataHolder); + public void marshal(final Object obj, final HierarchicalStreamWriter writer, final 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) { + public T fromXML(final 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); + public T fromXML(final Reader reader) { + return unmarshal(hierarchicalStreamDriver.createReader(reader), null); } /** * Deserialize an object from an XML InputStream. + * + * @throws XStreamException if the object cannot be deserialized */ - public Object fromXML(InputStream input) { + public T fromXML(final 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. + * Deserialize an object from a URL. Depending on the parser implementation, some might take the file path as + * SystemId to resolve additional references. + * + * @throws XStreamException if the object cannot be deserialized + * @since 1.4 */ - public Object fromXML(String xml, Object root) { + public T fromXML(final URL url) { + return fromXML(url, null); + } + + /** + * Deserialize an object from a file. Depending on the parser implementation, some might take the file path as + * SystemId to resolve additional references. + * + * @throws XStreamException if the object cannot be deserialized + * @since 1.4 + */ + public T fromXML(final File file) { + return fromXML(file, 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 T fromXML(final String xml, final T 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. + * 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) { + public T fromXML(final Reader xml, final T 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. + * Deserialize an object from a URL, 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! Depending on the parser implementation, some might take the + * file path as SystemId to resolve additional references. + * + * @throws XStreamException if the object cannot be deserialized + * @since 1.4 */ - public Object fromXML(InputStream xml, Object root) { - return unmarshal(hierarchicalStreamDriver.createReader(xml), root); + public T fromXML(final URL url, final T root) { + return unmarshal(hierarchicalStreamDriver.createReader(url), root); } /** + * Deserialize an object from a file, 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! Depending on the parser implementation, some might take the + * file path as SystemId to resolve additional references. + * + * @throws XStreamException if the object cannot be deserialized + * @since 1.4 + */ + public T fromXML(final File file, final T root) { + final HierarchicalStreamReader reader = hierarchicalStreamDriver.createReader(file); + try { + return unmarshal(reader, root); + } finally { + reader.close(); + } + } + + /** + * 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 T fromXML(final InputStream input, final T root) { + return unmarshal(hierarchicalStreamDriver.createReader(input), 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) { + public T unmarshal(final 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. + * 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) { + public T unmarshal(final HierarchicalStreamReader reader, final T 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. - * @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. + * + * @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, classMapper); + public T unmarshal(final HierarchicalStreamReader reader, final T root, final DataHolder dataHolder) { + try { + @SuppressWarnings("unchecked") + final T t = (T)marshallingStrategy.unmarshal(root, reader, dataHolder, converterLookup, mapper); + return t; + + } catch (final ConversionException e) { + final Package pkg = getClass().getPackage(); + final String version = pkg != null ? pkg.getImplementationVersion() : null; + e.add("version", version != null ? version : "not available"); + throw e; + } } /** * Alias a Class to a shorter name to be used in XML elements. - * + * * @param name Short name - * @param type Type to be aliased + * @param type Type to be aliased + * @throws InitializationException if no {@link ClassAliasingMapper} is available */ - public void alias(String name, Class type) { + public void alias(final String name, final 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(final String name, final 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 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) { + public void alias(final String name, final Class type, final Class defaultImplementation) { alias(name, type); addDefaultImplementation(defaultImplementation, type); } - public void aliasField(String alias, Class type, String fieldName) { - fieldAliasingMapper.addFieldAlias(alias, type, fieldName); + /** + * 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(final String name, final 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(final String alias, final Class definedIn, final 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(final String alias, final 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 + * null. 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 null) + * @param systemAttributeName the name of the system attribute + * @throws InitializationException if no {@link SystemAttributeAliasingMapper} is available + * @since 1.3.1 + */ + public void aliasSystemAttribute(final String alias, final 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(final Class definedIn, final String attributeName, final 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(final String fieldName, final 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(final Class definedIn, final 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(final 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. + * 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) { + public void addDefaultImplementation(final Class defaultImplementation, final Class ofType) { + if (defaultImplementationsMapper == null) { + throw new InitializationException("No " + DefaultImplementationsMapper.class.getName() + " available"); + } defaultImplementationsMapper.addDefaultImplementation(defaultImplementation, ofType); } - public void addImmutableType(Class type) { + /** + * 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(final Class type) { + if (immutableTypesMapper == null) { + throw new InitializationException("No " + ImmutableTypesMapper.class.getName() + " available"); + } immutableTypesMapper.addImmutableType(type); } /** - * @deprecated As of 1.1.1 you should register a converter with the appropriate priority. + * Register a converter with normal priority. + * + * @param converter the converter instance */ - public void changeDefaultConverter(Converter defaultConverter) { - registerConverter(defaultConverter, PRIORITY_VERY_LOW); + public void registerConverter(final Converter converter) { + registerConverter(converter, PRIORITY_NORMAL); } - public void registerConverter(Converter converter) { + /** + * Register a converter with chosen priority. + * + * @param converter the converter instance + * @param priority the converter priority + */ + public void registerConverter(final Converter converter, final int priority) { + if (converterRegistry != null) { + converterRegistry.registerConverter(converter, priority); + } + } + + /** + * Register a single value converter with normal priority. + * + * @param converter the single value converter instance + */ + public void registerConverter(final SingleValueConverter converter) { registerConverter(converter, PRIORITY_NORMAL); } - public void registerConverter(Converter converter, int priority) { - converterLookup.registerConverter(converter, priority); + /** + * Register a single converter with chosen priority. + * + * @param converter the single converter instance + * @param priority the converter priority + */ + public void registerConverter(final SingleValueConverter converter, final int priority) { + if (converterRegistry != null) { + converterRegistry.registerConverter(new SingleValueConverterWrapper(converter), priority); + } } - public ClassMapper getClassMapper() { - return classMapper; + /** + * 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(final Class definedIn, final String fieldName, final 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(final Class definedIn, final String fieldName, + final SingleValueConverter converter) { + final Converter wrapper = new SingleValueConverterWrapper(converter); + registerLocalConverter(definedIn, fieldName, wrapper); + } + + /** + * 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 valuse are XStream.XPATH_REFERENCES, - * XStream.ID_REFERENCES and XStream.NO_REFERENCES. - * - * @see #XPATH_REFERENCES + * Change mode for dealing with duplicate references. Valid values are XPATH_ABSOLUTE_REFERENCES, + * XPATH_RELATIVE_REFERENCES, XStream.ID_REFERENCES and XStream.NO_REFERENCES + * . + * + * @throws IllegalArgumentException if the mode is not one of the declared types + * @see #setMarshallingStrategy(MarshallingStrategy) + * @see #XPATH_ABSOLUTE_REFERENCES + * @see #XPATH_RELATIVE_REFERENCES * @see #ID_REFERENCES * @see #NO_REFERENCES */ - public void setMode(int mode) { + public void setMode(final int mode) { switch (mode) { - case NO_REFERENCES: - setMarshallingStrategy(new TreeMarshallingStrategy()); - break; - case ID_REFERENCES: - setMarshallingStrategy(new ReferenceByIdMarshallingStrategy()); - break; - case XPATH_REFERENCES: - setMarshallingStrategy(new ReferenceByXPathMarshallingStrategy()); - break; - default: - throw new IllegalArgumentException("Unknown mode : " + 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; + case SINGLE_NODE_XPATH_RELATIVE_REFERENCES: + setMarshallingStrategy(new ReferenceByXPathMarshallingStrategy(ReferenceByXPathMarshallingStrategy.RELATIVE + | ReferenceByXPathMarshallingStrategy.SINGLE_NODE)); + break; + case SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES: + setMarshallingStrategy(new ReferenceByXPathMarshallingStrategy(ReferenceByXPathMarshallingStrategy.ABSOLUTE + | ReferenceByXPathMarshallingStrategy.SINGLE_NODE)); + break; + default: + throw new IllegalArgumentException("Unknown mode : " + mode); } } /** - * @deprecated Use addImplicitCollection() instead. - */ - public void addDefaultCollection(Class ownerType, String fieldName) { - addImplicitCollection(ownerType, fieldName); - } - - /** - * Adds a default implicit collection which is used for any unmapped xml tag. - * + * 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 an java.util.ArrayList. + * @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) { - implicitCollectionMapper.add(ownerType, fieldName, null, Object.class); + public void addImplicitCollection(final Class ownerType, final String fieldName) { + addImplicitCollection(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 an java.util.ArrayList. - * @param itemType type of the items to be part of this 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) { - implicitCollectionMapper.add(ownerType, fieldName, null, itemType); + public void addImplicitCollection(final Class ownerType, final String fieldName, final Class itemType) { + addImplicitCollection(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 an java.util.ArrayList. - * @param itemFieldName element name of 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) { - implicitCollectionMapper.add(ownerType, fieldName, itemFieldName, itemType); + public void addImplicitCollection(final Class ownerType, final String fieldName, final String itemFieldName, + final Class itemType) { + addImplicitMap(ownerType, fieldName, itemFieldName, itemType, null); } + /** + * Adds an implicit array. + * + * @param ownerType class owning the implicit array + * @param fieldName name of the array field + * @since 1.4 + */ + public void addImplicitArray(final Class ownerType, final String fieldName) { + addImplicitCollection(ownerType, fieldName); + } + + /** + * Adds an implicit array which is used for all items of the given itemType when the array type matches. + * + * @param ownerType class owning the implicit array + * @param fieldName name of the array field in the ownerType + * @param itemType type of the items to be part of this array + * @throws InitializationException if no {@link ImplicitCollectionMapper} is available or the array type does not + * match the itemType + * @since 1.4 + */ + public void addImplicitArray(final Class ownerType, final String fieldName, final Class itemType) { + addImplicitCollection(ownerType, fieldName, itemType); + } + + /** + * Adds an implicit array which is used for all items of the given element name defined by itemName. + * + * @param ownerType class owning the implicit array + * @param fieldName name of the array field in the ownerType + * @param itemName alias name of the items + * @throws InitializationException if no {@link ImplicitCollectionMapper} is available + * @since 1.4 + */ + public void addImplicitArray(final Class ownerType, final String fieldName, final String itemName) { + addImplicitCollection(ownerType, fieldName, itemName, null); + } + + /** + * Adds an implicit map. + * + * @param ownerType class owning the implicit map + * @param fieldName name of the field in the ownerType. This field must be a concrete map type or matching the + * default implementation type of the map type. + * @param itemType type of the items to be part of this map as value + * @param keyFieldName the name of the field of the itemType that is used for the key in the map + * @since 1.4 + */ + public void addImplicitMap(final Class ownerType, final String fieldName, final Class itemType, + final String keyFieldName) { + addImplicitMap(ownerType, fieldName, null, itemType, keyFieldName); + } + + /** + * Adds an implicit map. + * + * @param ownerType class owning the implicit map + * @param fieldName name of the field in the ownerType. This field must be a concrete map type or matching the + * default implementation type of the map type. + * @param itemName alias name of the items + * @param itemType type of the items to be part of this map as value + * @param keyFieldName the name of the field of the itemType that is used for the key in the map + * @since 1.4 + */ + public void addImplicitMap(final Class ownerType, final String fieldName, final String itemName, + final Class itemType, final String keyFieldName) { + if (implicitCollectionMapper == null) { + throw new InitializationException("No " + ImplicitCollectionMapper.class.getName() + " available"); + } + implicitCollectionMapper.add(ownerType, fieldName, itemName, itemType, keyFieldName); + } + + /** + * 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. - * - *

To change the name of the root element (from <object-stream>), use - * {@link #createObjectOutputStream(java.io.Writer, String)}.

- * + *

+ * To change the name of the root element (from <object-stream>), use + * {@link #createObjectOutputStream(java.io.Writer, String)}. + *

+ * * @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(new PrettyPrintWriter(writer), "object-stream"); + public ObjectOutputStream createObjectOutputStream(final 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. - * - *

To change the name of the root element (from <object-stream>), use - * {@link #createObjectOutputStream(java.io.Writer, String)}.

- * + *

+ * To change the name of the root element (from <object-stream>), use + * {@link #createObjectOutputStream(java.io.Writer, String)}. + *

+ * * @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 { + public ObjectOutputStream createObjectOutputStream(final 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(new PrettyPrintWriter(writer), rootNodeName); + public ObjectOutputStream createObjectOutputStream(final Writer writer, final String rootNodeName) + throws IOException { + return createObjectOutputStream(hierarchicalStreamDriver.createWriter(writer), rootNodeName); } /** + * Creates an ObjectOutputStream that serializes a stream of objects to the OutputStream using XStream. + *

+ * To change the name of the root element (from <object-stream>), use + * {@link #createObjectOutputStream(java.io.Writer, String)}. + *

+ * + * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) + * @since 1.3 + */ + public ObjectOutputStream createObjectOutputStream(final 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(final OutputStream out, final String rootNodeName) + throws IOException { + return createObjectOutputStream(hierarchicalStreamDriver.createWriter(out), rootNodeName); + } + + /** * Creates an ObjectOutputStream that serializes a stream of objects to the writer using XStream. - * - *

Because an ObjectOutputStream can contain multiple items and XML only allows a single root node, the stream - * must be written inside an enclosing node.

- * - *

It is necessary to call ObjectOutputStream.close() when done, otherwise the stream will be incomplete.

- * + *

+ * Because an ObjectOutputStream can contain multiple items and XML only allows a single root node, the stream must + * be written inside an enclosing node. + *

+ *

+ * It is necessary to call ObjectOutputStream.close() when done, otherwise the stream will be incomplete. + *

*

Example

- *
ObjectOutputStream out = xstream.createObjectOutputStream(aWriter, "things");
-     * out.writeInt(123);
-     * out.writeObject("Hello");
-     * out.writeObject(someObject)
-     * out.close();
- * + * + *
+     *  ObjectOutputStream out = xstream.createObjectOutputStream(aWriter, "things");
+     *   out.writeInt(123);
+     *   out.writeObject("Hello");
+     *   out.writeObject(someObject)
+     *   out.close();
+     * 
+ * * @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 { - writer.startNode(rootNodeName); + @SuppressWarnings("resource") + public ObjectOutputStream createObjectOutputStream(final HierarchicalStreamWriter writer, final 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, writer); + @Override + public void writeToStream(final Object object) { + marshal(object, statefulWriter); } - public void writeFieldsToStream(Map fields) throws NotActiveException { + @Override + public void writeFieldsToStream(final Map fields) throws NotActiveException { throw new NotActiveException("not in call to writeObject"); } + @Override public void defaultWriteObject() throws NotActiveException { throw new NotActiveException("not in call to writeObject"); } + @Override public void flush() { - writer.flush(); + statefulWriter.flush(); } + @Override public void close() { - writer.endNode(); - writer.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 { + public ObjectInputStream createObjectInputStream(final Reader xmlReader) throws IOException { return createObjectInputStream(hierarchicalStreamDriver.createReader(xmlReader)); } /** - * Creates an ObjectInputStream that deserializes a stream of objects from a reader using XStream. - * - *

Example

- *
ObjectInputStream in = xstream.createObjectOutputStream(aReader);
+     * 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(final InputStream in) throws IOException {
+        return createObjectInputStream(hierarchicalStreamDriver.createReader(in));
+    }
+
+    /**
+     * Creates an ObjectInputStream that deserializes a stream of objects from a reader using XStream. 

Example

+ * + *
+     * ObjectInputStream in = xstream.createObjectOutputStream(aReader);
      * int a = out.readInt();
      * Object b = out.readObject();
-     * Object c = out.readObject();
- * + * Object c = out.readObject(); + *
+ * * @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() { + @Override public Object readFromStream() throws EOFException { if (!reader.hasMoreChildren()) { throw new EOFException(); } reader.moveDown(); - Object result = unmarshal(reader); + final Object result = unmarshal(reader); reader.moveUp(); return result; } - public Map readFieldsFromStream() throws IOException { + @Override + public Map readFieldsFromStream() throws IOException { throw new NotActiveException("not in call to readObject"); } + @Override public void defaultReadObject() throws NotActiveException { throw new NotActiveException("not in call to readObject"); } - public void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException { + @Override + public void registerValidation(final ObjectInputValidation validation, final int priority) + throws NotActiveException { throw new NotActiveException("stream inactive"); } + @Override public void close() { reader.close(); } - }); + }, classLoaderReference); } /** - * Change the ClassLoader XStream uses to load classes. - * + * 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 class loader, you should call this method as early as possible - or consider to provide the + * class loader directly in the constructor. + * * @since 1.1.1 */ - public void setClassLoader(ClassLoader classLoader) { + public void setClassLoader(final ClassLoader classLoader) { classLoaderReference.setReference(classLoader); } /** - * Change the ClassLoader XStream uses to load classes. - * + * Retrieve the ClassLoader XStream uses to load classes. + * * @since 1.1.1 */ public ClassLoader getClassLoader() { return classLoaderReference.getReference(); } /** - * Prevents a field from being serialized. - * - * @since 1.2 + * Retrieve the reference to this instance' ClassLoader. Use this reference for other XStream components (like + * converters) to ensure that they will use a changed ClassLoader instance automatically. + * + * @return the reference + * @since 1.4.5 */ - public void omitField(Class type, String fieldName) { - fieldAliasingMapper.omitField(type, fieldName); + public ClassLoaderReference getClassLoaderReference() { + return classLoaderReference; } - public static class InitializationException extends BaseException { - public InitializationException(String message, Throwable cause) { - super(message, cause); + /** + * 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(final Class definedIn, final String fieldName) { + if (fieldAliasingMapper == null) { + throw new InitializationException("No " + FieldAliasingMapper.class.getName() + " available"); } + fieldAliasingMapper.omitField(definedIn, fieldName); } + /** + * Ignore all unknown elements. + * + * @since 1.4.5 + */ + public void ignoreUnknownElements() { + ignoreUnknownElements(IGNORE_ALL); + } + + /** + * Add pattern for unknown element names to ignore. + * + * @param pattern the name pattern as regular expression + * @since 1.4.5 + */ + public void ignoreUnknownElements(final String pattern) { + ignoreUnknownElements(Pattern.compile(pattern)); + } + + /** + * Add pattern for unknown element names to ignore. + * + * @param pattern the name pattern as regular expression + * @since 1.4.5 + */ + private void ignoreUnknownElements(final Pattern pattern) { + if (fieldAliasingMapper == null) { + throw new InitializationException("No " + FieldAliasingMapper.class.getName() + " available"); + } + fieldAliasingMapper.addFieldsToIgnore(pattern); + } + + /** + * 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 (annotationMapper == null) { + throw new InitializationException("No " + AnnotationMapper.class.getName() + " available"); + } + annotationMapper.processAnnotations(types); + } + + /** + * 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 true if annotations are auto-detected + * @since 1.3 + */ + public void autodetectAnnotations(final boolean mode) { + if (annotationMapper != null) { + annotationMapper.autodetectAnnotations(mode); + } + } + + /** + * Add a new security permission. + *

+ * Permissions are evaluated in the added sequence. An instance of {@link NoTypePermission} or + * {@link AnyTypePermission} will implicitly wipe any existing permission. + *

+ * + * @param permission the permission to add + * @since 1.4.7 + */ + public void addPermission(final TypePermission permission) { + if (securityMapper != null) { + securityMapper.addPermission(permission); + } + } + + /** + * Add security permission for explicit types by name. + * + * @param names the type names to allow + * @since 1.4.7 + */ + public void allowTypes(final String... names) { + addPermission(new ExplicitTypePermission(names)); + } + + /** + * Add security permission for explicit types. + * + * @param types the types to allow + * @since 1.4.7 + */ + public void allowTypes(final Class... types) { + addPermission(new ExplicitTypePermission(types)); + } + + /** + * Add security permission for a type hierarchy. + * + * @param type the base type to allow + * @since 1.4.7 + */ + public void allowTypeHierarchy(final Class type) { + addPermission(new TypeHierarchyPermission(type)); + } + + /** + * Add security permission for types matching one of the specified regular expressions. + * + * @param regexps the regular expressions to allow type names + * @since 1.4.7 + */ + public void allowTypesByRegExp(final String... regexps) { + addPermission(new RegExpTypePermission(regexps)); + } + + /** + * Add security permission for types matching one of the specified regular expressions. + * + * @param regexps the regular expressions to allow type names + * @since 1.4.7 + */ + public void allowTypesByRegExp(final Pattern... regexps) { + addPermission(new RegExpTypePermission(regexps)); + } + + /** + * Add security permission for types matching one of the specified wildcard patterns. + *

+ * Supported are patterns with path expressions using dot as separator: + *

+ *
    + *
  • ?: one non-control character except separator, e.g. for 'java.net.Inet?Address'
  • + *
  • *: arbitrary number of non-control characters except separator, e.g. for types in a package like + * 'java.lang.*'
  • + *
  • **: arbitrary number of non-control characters including separator, e.g. for types in a package and + * subpackages like 'java.lang.**'
  • + *
+ * + * @param patterns the patterns to allow type names + * @since 1.4.7 + */ + public void allowTypesByWildcard(final String... patterns) { + addPermission(new WildcardTypePermission(patterns)); + } + + /** + * Add security permission denying another one. + * + * @param permission the permission to deny + * @since 1.4.7 + */ + public void denyPermission(final TypePermission permission) { + addPermission(new NoPermission(permission)); + } + + /** + * Add security permission forbidding explicit types by name. + * + * @param names the type names to forbid + * @since 1.4.7 + */ + public void denyTypes(final String... names) { + denyPermission(new ExplicitTypePermission(names)); + } + + /** + * Add security permission forbidding explicit types. + * + * @param types the types to forbid + * @since 1.4.7 + */ + public void denyTypes(final Class... types) { + denyPermission(new ExplicitTypePermission(types)); + } + + /** + * Add security permission forbidding a type hierarchy. + * + * @param type the base type to forbid + * @since 1.4.7 + */ + public void denyTypeHierarchy(final Class type) { + denyPermission(new TypeHierarchyPermission(type)); + } + + /** + * Add security permission forbidding types matching one of the specified regular expressions. + * + * @param regexps the regular expressions to forbid type names + * @since 1.4.7 + */ + public void denyTypesByRegExp(final String... regexps) { + denyPermission(new RegExpTypePermission(regexps)); + } + + /** + * Add security permission forbidding types matching one of the specified regular expressions. + * + * @param regexps the regular expressions to forbid type names + * @since 1.4.7 + */ + public void denyTypesByRegExp(final Pattern... regexps) { + denyPermission(new RegExpTypePermission(regexps)); + } + + /** + * Add security permission forbidding types matching one of the specified wildcard patterns. + *

+ * Supported are patterns with path expressions using dot as separator: + *

+ *
    + *
  • ?: one non-control character except separator, e.g. for 'java.net.Inet?Address'
  • + *
  • *: arbitrary number of non-control characters except separator, e.g. for types in a package like + * 'java.lang.*'
  • + *
  • **: arbitrary number of non-control characters including separator, e.g. for types in a package and + * subpackages like 'java.lang.**'
  • + *
+ * + * @param patterns the patterns to forbid names + * @since 1.4.7 + */ + public void denyTypesByWildcard(final String... patterns) { + denyPermission(new WildcardTypePermission(patterns)); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/XStreamException.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/XStreamException.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/XStreamException.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007, 2008, 2013 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 22. October 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream; + + +/** + * Base exception for all thrown exceptions with XStream. + * + * @author Joe Walnes + * @author Jörg Schaible + * @since 1.3 + */ +public class XStreamException extends RuntimeException { + + /** + * Default constructor. + * + * @since 1.3 + */ + protected XStreamException() { + this("", null); + } + + /** + * Constructs an XStreamException with a message. + * + * @param message + * @since 1.3 + */ + public XStreamException(String message) { + this(message, null); + } + + /** + * Constructs an XStreamException as wrapper for a different causing {@link Throwable}. + * + * @param cause + * @since 1.3 + */ + public XStreamException(Throwable cause) { + this("", cause); + } + + /** + * Constructs an XStreamException with a message as wrapper for a different causing + * {@link Throwable}. + * + * @param message + * @param cause + * @since 1.3 + */ + public XStreamException(String message, Throwable cause) { + super(message + (cause == null ? "" : " : " + cause.getMessage()), cause); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/XStreamer.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/XStreamer.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/XStreamer.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2006, 2007, 2014 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 13. April 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; + +import javax.xml.datatype.DatatypeFactory; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.ConverterMatcher; +import com.thoughtworks.xstream.converters.ConverterRegistry; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.javabean.JavaBeanProvider; +import com.thoughtworks.xstream.converters.reflection.FieldKeySorter; +import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.xml.XppDriver; +import com.thoughtworks.xstream.mapper.Mapper; +import com.thoughtworks.xstream.security.TypeHierarchyPermission; +import com.thoughtworks.xstream.security.TypePermission; +import com.thoughtworks.xstream.security.WildcardTypePermission; + + +/** + * Self-contained XStream generator. The class is a utility to write XML streams that contain additionally the XStream + * that was used to serialize the object graph. Such a stream can be unmarshalled using this embedded XStream instance, + * that kept any settings. + * + * @author Jörg Schaible + * @since 1.2 + */ +public class XStreamer { + + private final static TypePermission[] PERMISSIONS = { + new TypeHierarchyPermission(ConverterMatcher.class), new TypeHierarchyPermission(Mapper.class), + new TypeHierarchyPermission(XStream.class), new TypeHierarchyPermission(ReflectionProvider.class), + new TypeHierarchyPermission(JavaBeanProvider.class), new TypeHierarchyPermission(FieldKeySorter.class), + new TypeHierarchyPermission(ConverterLookup.class), new TypeHierarchyPermission(ConverterRegistry.class), + new TypeHierarchyPermission(HierarchicalStreamDriver.class), + new TypeHierarchyPermission(MarshallingStrategy.class), new TypeHierarchyPermission(MarshallingContext.class), + new TypeHierarchyPermission(UnmarshallingContext.class), new TypeHierarchyPermission(NameCoder.class), + new TypeHierarchyPermission(TypePermission.class), + new WildcardTypePermission(JVM.class.getPackage().getName() + ".**"), + new TypeHierarchyPermission(DatatypeFactory.class) // required by DurationConverter + }; + + /** + * Serialize an object including the XStream to a pretty-printed XML String. + * + * @throws ObjectStreamException if the XML contains non-serializable elements + * @throws com.thoughtworks.xstream.XStreamException if the object cannot be serialized + * @since 1.2 + * @see #toXML(XStream, Object, Writer) + */ + public String toXML(final XStream xstream, final Object obj) throws ObjectStreamException { + final Writer writer = new StringWriter(); + try { + toXML(xstream, obj, writer); + } catch (final ObjectStreamException e) { + throw e; + } catch (final IOException e) { + throw new ConversionException("Unexpected IO error from a StringWriter", e); + } + return writer.toString(); + } + + /** + * Serialize an object including the XStream to the given Writer as pretty-printed XML. + *

+ * Warning: XStream will serialize itself into this XML stream. To read such an XML code, you should use + * {@link XStreamer#fromXML(Reader)} or one of the other overloaded methods. Since a lot of internals are written + * into the stream, you cannot expect to use such an XML to work with another XStream version or with XStream + * running on different JDKs and/or versions. We have currently no JDK 1.3 support, nor will the + * PureReflectionConverter work with a JDK less than 1.5. + *

+ * + * @throws IOException if an error occurs reading from the Writer. + * @throws com.thoughtworks.xstream.XStreamException if the object cannot be serialized + * @since 1.2 + */ + public void toXML(final XStream xstream, final Object obj, final Writer out) throws IOException { + final XStream outer = new XStream(); + final ObjectOutputStream oos = outer.createObjectOutputStream(out); + try { + oos.writeObject(xstream); + oos.flush(); + xstream.toXML(obj, out); + } finally { + oos.close(); + } + } + + /** + * Deserialize a self-contained XStream with object from a String. The method will use internally an XppDriver to + * load the contained XStream instance with default permissions. + * + * @param xml the XML data + * @throws ClassNotFoundException if a class in the XML stream cannot be found + * @throws ObjectStreamException if the XML contains non-deserializable elements + * @throws com.thoughtworks.xstream.XStreamException if the object cannot be deserialized + * @since 1.2 + * @see #toXML(XStream, Object, Writer) + */ + public T fromXML(final String xml) throws ClassNotFoundException, ObjectStreamException { + try { + return fromXML(new StringReader(xml)); + } catch (final ObjectStreamException e) { + throw e; + } catch (final IOException e) { + throw new ConversionException("Unexpected IO error from a StringReader", e); + } + } + + /** + * Deserialize a self-contained XStream with object from a String. The method will use internally an XppDriver to + * load the contained XStream instance. + * + * @param xml the XML data + * @param permissions the permissions to use (ensure that they include the defaults) + * @throws ClassNotFoundException if a class in the XML stream cannot be found + * @throws ObjectStreamException if the XML contains non-deserializable elements + * @throws com.thoughtworks.xstream.XStreamException if the object cannot be deserialized + * @since 1.4.7 + * @see #toXML(XStream, Object, Writer) + */ + public T fromXML(final String xml, final TypePermission... permissions) + throws ClassNotFoundException, ObjectStreamException { + try { + return fromXML(new StringReader(xml), permissions); + } catch (final ObjectStreamException e) { + throw e; + } catch (final IOException e) { + throw new ConversionException("Unexpected IO error from a StringReader", e); + } + } + + /** + * Deserialize a self-contained XStream with object from a String. + * + * @param driver the implementation to use + * @param xml the XML data + * @throws ClassNotFoundException if a class in the XML stream cannot be found + * @throws ObjectStreamException if the XML contains non-deserializable elements + * @throws com.thoughtworks.xstream.XStreamException if the object cannot be deserialized + * @since 1.2 + * @see #toXML(XStream, Object, Writer) + */ + public T fromXML(final HierarchicalStreamDriver driver, final String xml) + throws ClassNotFoundException, ObjectStreamException { + try { + return fromXML(driver, new StringReader(xml)); + } catch (final ObjectStreamException e) { + throw e; + } catch (final IOException e) { + throw new ConversionException("Unexpected IO error from a StringReader", e); + } + } + + /** + * Deserialize a self-contained XStream with object from a String. + * + * @param driver the implementation to use + * @param xml the XML data + * @param permissions the permissions to use (ensure that they include the defaults) + * @throws ClassNotFoundException if a class in the XML stream cannot be found + * @throws ObjectStreamException if the XML contains non-deserializable elements + * @throws com.thoughtworks.xstream.XStreamException if the object cannot be deserialized + * @since 1.4.7 + * @see #toXML(XStream, Object, Writer) + */ + public T fromXML(final HierarchicalStreamDriver driver, final String xml, final TypePermission... permissions) + throws ClassNotFoundException, ObjectStreamException { + try { + return fromXML(driver, new StringReader(xml), permissions); + } catch (final ObjectStreamException e) { + throw e; + } catch (final IOException e) { + throw new ConversionException("Unexpected IO error from a StringReader", e); + } + } + + /** + * Deserialize a self-contained XStream with object from an XML Reader. The method will use internally an XppDriver + * to load the contained XStream instance with default permissions. + * + * @param xml the {@link Reader} providing the XML data + * @throws IOException if an error occurs reading from the Reader. + * @throws ClassNotFoundException if a class in the XML stream cannot be found + * @throws com.thoughtworks.xstream.XStreamException if the object cannot be deserialized + * @since 1.2 + * @see #toXML(XStream, Object, Writer) + */ + public T fromXML(final Reader xml) throws IOException, ClassNotFoundException { + return fromXML(new XppDriver(), xml); + } + + /** + * Deserialize a self-contained XStream with object from an XML Reader. The method will use internally an XppDriver + * to load the contained XStream instance. + * + * @param xml the {@link Reader} providing the XML data + * @param permissions the permissions to use (ensure that they include the defaults) + * @throws IOException if an error occurs reading from the Reader. + * @throws ClassNotFoundException if a class in the XML stream cannot be found + * @throws com.thoughtworks.xstream.XStreamException if the object cannot be deserialized + * @since 1.4.7 + * @see #toXML(XStream, Object, Writer) + */ + public T fromXML(final Reader xml, final TypePermission... permissions) + throws IOException, ClassNotFoundException { + return fromXML(new XppDriver(), xml, permissions); + } + + /** + * Deserialize a self-contained XStream with object from an XML Reader. + * + * @param driver the implementation to use + * @param xml the {@link Reader} providing the XML data + * @throws IOException if an error occurs reading from the Reader. + * @throws ClassNotFoundException if a class in the XML stream cannot be found + * @throws com.thoughtworks.xstream.XStreamException if the object cannot be deserialized + * @since 1.2 + */ + public T fromXML(final HierarchicalStreamDriver driver, final Reader xml) + throws IOException, ClassNotFoundException { + return fromXML(driver, xml, PERMISSIONS); + } + + /** + * Deserialize a self-contained XStream with object from an XML Reader. + * + * @param driver the implementation to use + * @param xml the {@link Reader} providing the XML data + * @param permissions the permissions to use (ensure that they include the defaults) + * @throws IOException if an error occurs reading from the Reader. + * @throws ClassNotFoundException if a class in the XML stream cannot be found + * @throws com.thoughtworks.xstream.XStreamException if the object cannot be deserialized + * @since 1.4.7 + */ + public T fromXML(final HierarchicalStreamDriver driver, final Reader xml, final TypePermission... permissions) + throws IOException, ClassNotFoundException { + final XStream outer = new XStream(driver); + for (final TypePermission permission : permissions) { + outer.addPermission(permission); + } + final HierarchicalStreamReader reader = driver.createReader(xml); + final ObjectInputStream configIn = outer.createObjectInputStream(reader); + try { + final XStream configured = (XStream)configIn.readObject(); + final ObjectInputStream in = configured.createObjectInputStream(reader); + try { + @SuppressWarnings("unchecked") + final T t = (T)in.readObject(); + return t; + } finally { + in.close(); + } + } finally { + configIn.close(); + } + } + + /** + * Retrieve the default permissions to unmarshal an XStream instance. + *

+ * The returned list will only cover permissions for XStream's own types. If your custom converters or mappers keep + * references to other types, you will have to add permission for those types on your own. + *

+ * + * @since 1.4.7 + */ + public static TypePermission[] getDefaultPermissions() { + return PERMISSIONS.clone(); + } +} Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/alias/CannotResolveClassException.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/alias/ClassMapper.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/alias/NameMapper.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/Annotations.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAlias.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAlias.java (.../XStreamAlias.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAlias.java (.../XStreamAlias.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,19 +1,39 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2013 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 11. August 2005 by Mauro Talevi + */ package com.thoughtworks.xstream.annotations; +import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; /** - * Annotation used to define an XStream class or field value. This annotation should only be used with classes and fields + * Annotation used to define an XStream class or field alias. * * @author Emil Kirschner * @author Chung-Onn Cheong + * @see com.thoughtworks.xstream.XStream#alias(String, Class) + * @see com.thoughtworks.xstream.XStream#alias(String, Class, Class) + * @see com.thoughtworks.xstream.XStream#addDefaultImplementation(Class, Class) */ @Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD}) public @interface XStreamAlias { /** - * The value of the class or field value + * The name of the class or field alias. */ public String value(); + /** + * A possible default implementation if the annotated type is an interface. + */ public Class impl() default Void.class; //Use Void to denote as Null } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAliasType.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAliasType.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAliasType.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2013 XStream Committers. + * All rights reserved. + * + * Created on 12.07.2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Annotation used to define an XStream type alias. + * + * @author Jörg Schaible + * @since 1.4.5 + * @see com.thoughtworks.xstream.XStream#aliasType(String, Class) + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface XStreamAliasType { + /** + * The name of the type alias. + */ + public String value(); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAsAttribute.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAsAttribute.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamAsAttribute.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2006, 2007 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 24. December 2006 by Guilherme Silveira + */ +package com.thoughtworks.xstream.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Defines that a field should be serialized as an attribute. + * + * @author Guilherme Silveira + * @since 1.2.2 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Documented +public @interface XStreamAsAttribute { +} Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamContainedType.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverter.java (.../XStreamConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverter.java (.../XStreamConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,18 +1,109 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014 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 16. September 2005 by Mauro Talevi + */ package com.thoughtworks.xstream.annotations; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.ConverterMatcher; + +import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import com.thoughtworks.xstream.converters.Converter; /** + * Annotation to declare a converter. The annotation supports additionally the injection of + * various constructor arguments provided by XStream: + *
    + *
  • {@link com.thoughtworks.xstream.mapper.Mapper}: The current mapper chain of the XStream + * instance.
  • + *
  • {@link com.thoughtworks.xstream.core.ClassLoaderReference}: The reference to the class + * loader used by the XStream instance to deserialize the objects.
  • + *
  • {@link com.thoughtworks.xstream.converters.reflection.ReflectionProvider}: The reflection + * provider used by the reflection based converters of the current XStream instance.
  • + *
  • {@link com.thoughtworks.xstream.converters.ConverterLookup}: The lookup for converters + * handling a special type.
  • + *
  • All elements provided with the individual arrays of this annotation. The provided values + * follow the declaration sequence if a constructor requires multiple arguments of the same + * type.
  • + *
  • {@link Class}: The type of the element where the annotation is declared. Note, that this + * argument is not supported when using + * {@link com.thoughtworks.xstream.annotations.XStreamConverters} or {@link #useImplicitType()} + * == false.
  • + *
  • {@link com.thoughtworks.xstream.core.JVM}: Utility e.g. to load classes.
  • + *
  • {@link ClassLoader} (deprecated since 1.4.5): The class loader used by the XStream + * instance to deserialize the objects. Use ClassLoaderReference as argument
  • + *
+ *

+ * The algorithm will try the converter's constructor with the most arguments first. + *

+ *

+ * Note, the annotation matches a {@link ConverterMatcher}. + * {@link com.thoughtworks.xstream.converters.Converter} as well as + * {@link com.thoughtworks.xstream.converters.SingleValueConverter} extend this interface. The + * {@link com.thoughtworks.xstream.mapper.AnnotationMapper} can only handle these two + * known types. + *

* * @author Chung-Onn Cheong + * @author Jörg Schaible */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) +@Target({ElementType.TYPE, ElementType.FIELD}) +@Documented public @interface XStreamConverter { - Class value(); + Class value(); + + int priority() default XStream.PRIORITY_NORMAL; + + /** + * Flag to provide the current type as implicit first Class argument to a converter's + * constructor. + * + * @return true if the current type is provided + * @since 1.4.5 + */ + boolean useImplicitType() default true; + + /** + * Provide class types as arguments for the converter's constructor arguments. + *

+ * Note, that XStream itself provides the current class type as first Class argument to a + * constructor, if the annotation is added directly to a class type (and not as part of a + * parameter declaration of a {@link XStreamConverters} annotation). The current type has + * precedence over any type provided with this method. This behavior can be overridden + * setting {@link #useImplicitType()} to false. + * + * @return the types + * @since 1.4.2 + */ + Class[] types() default {}; + + String[] strings() default {}; + + byte[] bytes() default {}; + + char[] chars() default {}; + + short[] shorts() default {}; + + int[] ints() default {}; + + long[] longs() default {}; + + float[] floats() default {}; + + double[] doubles() default {}; + + boolean[] booleans() default {}; } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverters.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverters.java (.../XStreamConverters.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamConverters.java (.../XStreamConverters.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,3 +1,14 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007 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 16. September 2005 by Mauro Talevi + */ package com.thoughtworks.xstream.annotations; import java.lang.annotation.ElementType; Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamImplicit.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamImplicit.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamImplicit.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2006, 2007, 2011 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 01. December 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An annotation for marking a field as an implicit collection or array. + * + * @author Lucio Benfante + * @author Jörg Schaible + * @since 1.2.2 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface XStreamImplicit { + /** + * Element name of the implicit collection. + */ + String itemFieldName() default ""; + /** + * Field name of map entries that are used as key for the element in the implicit map. + * @since 1.4 + */ + String keyFieldName() default ""; +} Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamImplicitCollection.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamInclude.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamInclude.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamInclude.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,29 @@ +/* + * Copyright (C) 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 13. November 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to force automated processing of further classes. + * + * @author Steven Sparling + * @since 1.3.1 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface XStreamInclude +{ + public Class[] value(); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamOmitField.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamOmitField.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/annotations/XStreamOmitField.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007 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 06. May 2005 by Guilherme Silveira + */ +package com.thoughtworks.xstream.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +/** + * Declares a field to be omitted. The result is the same as invoking the method + * omitField in a XStream instance. + * + * @author Chung-Onn Cheong + * @author Guilherme Silveira + * @since 1.2.2 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @ interface XStreamOmitField { +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConversionException.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConversionException.java (.../ConversionException.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConversionException.java (.../ConversionException.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,87 +1,115 @@ +/* + * Copyright (C) 2003, 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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.converters; -import com.thoughtworks.xstream.core.BaseException; - -import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.Map; +import com.thoughtworks.xstream.XStreamException; + + /** - * Thrown by {@link Converter} implementations when they cannot convert an object - * to/from textual data. - * - * When this exception is thrown it can be passed around to things that accept an - * {@link ErrorWriter}, allowing them to add diagnostics to the stack trace. - * + * Thrown by {@link Converter} implementations when they cannot convert an object to/from textual data. When this + * exception is thrown it can be passed around to things that accept an {@link ErrorWriter}, allowing them to add + * diagnostics to the stack trace. + * * @author Joe Walnes - * + * @author Jörg Schaible * @see ErrorWriter */ -public class ConversionException extends BaseException implements ErrorWriter { +public class ConversionException extends XStreamException implements ErrorWriter { - private Map stuff = new HashMap(); + private static final String SEPARATOR = "\n-------------------------------"; + private final Map stuff = new LinkedHashMap(); - /** - * Plays nice with JDK1.3 and JDK1.4 - */ - protected Exception cause; - - public ConversionException(String msg, Exception cause) { - super(msg); + public ConversionException(final String msg, final Throwable cause) { + super(msg, cause); if (msg != null) { add("message", msg); } if (cause != null) { add("cause-exception", cause.getClass().getName()); - add("cause-message", cause.getMessage()); - this.cause = cause; + add("cause-message", cause instanceof ConversionException + ? ((ConversionException)cause).getShortMessage() + : cause.getMessage()); } } - public ConversionException(String msg) { + public ConversionException(final String msg) { super(msg); } - public ConversionException(Exception cause) { + public ConversionException(final Throwable cause) { this(cause.getMessage(), cause); } - public String get(String errorKey) { - return (String) stuff.get(errorKey); + @Override + public String get(final String errorKey) { + return stuff.get(errorKey); } - public void add(String name, String information) { - stuff.put(name, information); + @Override + public void add(final String name, final String information) { + String key = name; + int i = 0; + while (stuff.containsKey(key)) { + final String value = stuff.get(key); + if (information.equals(value)) { + return; + } + key = name + "[" + ++i + "]"; + } + stuff.put(key, information); } - public Iterator keys() { + @Override + public void set(final String name, final String information) { + String key = name; + int i = 0; + stuff.put(key, information); // keep order + while (stuff.containsKey(key)) { + if (i != 0) { + stuff.remove(key); + } + key = name + "[" + ++i + "]"; + } + } + + @Override + public Iterator keys() { return stuff.keySet().iterator(); } + @Override public String getMessage() { - StringBuffer result = new StringBuffer(); + final StringBuilder result = new StringBuilder(); if (super.getMessage() != null) { result.append(super.getMessage()); } - result.append("\n---- Debugging information ----"); - for (Iterator iterator = keys(); iterator.hasNext();) { - String k = (String) iterator.next(); - String v = get(k); + if (!result.toString().endsWith(SEPARATOR)) { + result.append("\n---- Debugging information ----"); + } + for (final Iterator iterator = keys(); iterator.hasNext();) { + final String k = iterator.next(); + final String v = get(k); result.append('\n').append(k); - int padding = 20 - k.length(); - for (int i = 0; i < padding; i++) { - result.append(' '); - } - result.append(": ").append(v).append(' '); + result.append(" ".substring(Math.min(20, k.length()))); + result.append(": ").append(v); } - result.append("\n-------------------------------"); + result.append(SEPARATOR); return result.toString(); } - public Throwable getCause() { - return cause; - } - public String getShortMessage() { return super.getMessage(); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/Converter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/Converter.java (.../Converter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/Converter.java (.../Converter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,59 +1,66 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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.converters; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + /** - * Converter implementations are responsible marshalling Java objects - * to/from textual data. - *

- *

If an exception occurs during processing, a {@link ConversionException} - * should be thrown.

- *

- *

If working with the high level {@link com.thoughtworks.xstream.XStream} facade, - * you can register new converters using the XStream.registerConverter() method.

- *

- *

If working with the lower level API, the - * {@link com.thoughtworks.xstream.converters.ConverterLookup} implementation is - * responsible for looking up the appropriate converter.

- *

- *

{@link com.thoughtworks.xstream.converters.basic.AbstractBasicConverter} - * provides a starting point for objects that can store all information - * in a single String.

- *

- *

{@link com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter} - * provides a starting point for objects that hold a collection of other objects - * (such as Lists and Maps).

- * + * Converter implementations are responsible marshalling Java objects to/from textual data. + *

+ * If an exception occurs during processing, a {@link ConversionException} should be thrown. + *

+ *

+ * If working with the high level {@link com.thoughtworks.xstream.XStream} facade, you can register new converters using + * the XStream.registerConverter() method. + *

+ *

+ * If working with the lower level API, the {@link com.thoughtworks.xstream.converters.ConverterLookup} implementation + * is responsible for looking up the appropriate converter. + *

+ *

+ * Converters for object that can store all information in a single value should implement + * {@link com.thoughtworks.xstream.converters.SingleValueConverter}. + * {@link com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter} provides a starting point. + *

+ *

+ * {@link com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter} provides a starting point for + * objects that hold a collection of other objects (such as Lists and Maps). + *

+ * * @author Joe Walnes * @see com.thoughtworks.xstream.XStream * @see com.thoughtworks.xstream.converters.ConverterLookup - * @see com.thoughtworks.xstream.converters.basic.AbstractBasicConverter + * @see com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter * @see com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter */ -public interface Converter { +public interface Converter extends ConverterMatcher { /** - * Called by XStream to determine whether to use this converter - * instance to marshall a particular type. - */ - boolean canConvert(Class type); - - /** * Convert an object to textual data. - * - * @param source The object to be marshalled. - * @param writer A stream to write to. - * @param context A context that allows nested objects to be processed by XStream. + * + * @param source the object to be marshalled. + * @param writer a stream to write to. + * @param context a context that allows nested objects to be processed by XStream. */ void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context); /** * Convert textual data back into an object. - * - * @param reader The stream to read the text from. - * @param context - * @return The resulting object. + * + * @param reader the stream to read the text from. + * @param context a context that allows nested objects to be processed by XStream. + * @return the resulting object. */ Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context); Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterLookup.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterLookup.java (.../ConverterLookup.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterLookup.java (.../ConverterLookup.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,24 +1,30 @@ +/* + * Copyright (C) 2003, 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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.converters; /** * Responsible for looking up the correct Converter implementation for a specific type. - * + * * @author Joe Walnes * @see Converter */ public interface ConverterLookup { /** * Lookup a converter for a specific type. - *

- * This type may be any Class, including primitive and array types. It may also be null, signifying - * the value to be converted is a null type. + *

+ * This type may be any Class, including primitive and array types. It may also be null, signifying the value to be + * converted is a null type. + *

*/ - Converter lookupConverterForType(Class type); - - /** - * @deprecated As of 1.1.1 you can register Converters with priorities, making the need for a default converter redundant. - */ - Converter defaultConverter(); - + Converter lookupConverterForType(Class type); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterMatcher.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterMatcher.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterMatcher.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2006, 2007, 2014 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 15. February 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.converters; + +/** + * ConverterMatcher allows to match converters to classes by determining if a given type can be converted by the + * converter instance. ConverterMatcher is the base interface of any converter. + * + * @author Joe Walnes + * @author Jörg Schaible + * @author Mauro Talevi + * @see com.thoughtworks.xstream.converters.Converter + * @see com.thoughtworks.xstream.converters.SingleValueConverter + * @since 1.2 + */ +public interface ConverterMatcher { + + /** + * Determines whether the converter can marshal a particular type. + * + * @param type the Class representing the object type to be converted + */ + boolean canConvert(Class type); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterRegistry.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterRegistry.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ConverterRegistry.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,23 @@ +/* + * Copyright (C) 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 01. January 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters; + +/** + * An interface for the converter management. + * + * @author Jörg Schaible + * @since 1.3 + */ +public interface ConverterRegistry { + + void registerConverter(Converter converter, int priority); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/DataHolder.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/DataHolder.java (.../DataHolder.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/DataHolder.java (.../DataHolder.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,16 +1,29 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 16. August 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters; import java.util.Iterator; + /** * Holds generic data, to be used as seen fit by the user. - * + * * @author Joe Walnes */ public interface DataHolder { Object get(Object key); + void put(Object key, Object value); - Iterator keys(); + Iterator keys(); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ErrorReporter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ErrorReporter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ErrorReporter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 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 15.02.2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters; + +/** + * To aid debugging, some components expose themselves as ErrorReporter + * indicating that they can add information in case of an error.. + * + * @author Joerg Schaible + * + * @since 1.4 + */ +public interface ErrorReporter { + /** + * Append context information to an {@link ErrorWriter}. + * + * @param errorWriter the error writer + * @since 1.4 + */ + void appendErrors(ErrorWriter errorWriter); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ErrorWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ErrorWriter.java (.../ErrorWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/ErrorWriter.java (.../ErrorWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,20 +1,61 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2014 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 08. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters; +import java.util.Iterator; + + /** - * To aid debugging, some components are passed an ErrorWriter - * when things go wrong, allowing them to add information - * to the error message that may be helpful to diagnose problems. - * + * To aid debugging, some components are passed an ErrorWriter when things go wrong, allowing them to add information to + * the error message that may be helpful to diagnose problems. + * * @author Joe Walnes + * @author Jörg Schaible */ public interface ErrorWriter { /** - * Add some information to the error message. - * - * @param name Something to identify the type of information (e.g. 'XPath'). - * @param information Detail of the message (e.g. '/blah/moo[3]' + * Add some information to the error message. The information will be added even if the identifier is already in + * use. + * + * @param name something to identify the type of information (e.g. 'XPath'). + * @param information detail of the message (e.g. '/blah/moo[3]' */ void add(String name, String information); + /** + * Set some information to the error message. If the identifier is already in use, the new information will replace + * the old one. + * + * @param name something to identify the type of information (e.g. 'XPath'). + * @param information detail of the message (e.g. '/blah/moo[3]' + * @since 1.4 + */ + void set(String name, String information); + + /** + * Retrieve information of the error message. + * + * @param errorKey the key of the message + * @return the value + * @since 1.3 + */ + String get(String errorKey); + + /** + * Retrieve an iterator over all keys of the error message. + * + * @return an Iterator + * @since 1.3 + */ + Iterator keys(); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/MarshallingContext.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/MarshallingContext.java (.../MarshallingContext.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/MarshallingContext.java (.../MarshallingContext.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,8 +1,30 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007 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 06. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters; - public interface MarshallingContext extends DataHolder { + /** + * Converts another object searching for the default converter + * @param nextItem the next item to convert + */ void convertAnother(Object nextItem); + + /** + * Converts another object using the specified converter + * @param nextItem the next item to convert + * @param converter the Converter to use + * @since 1.2 + */ + void convertAnother(Object nextItem, Converter converter); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/SingleValueConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/SingleValueConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/SingleValueConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006, 2007, 2013 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 15. February 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.converters; + +/** + * SingleValueConverter implementations are marshallable to/from a single value String representation. + * + *

{@link com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter} + * provides a starting point for objects that can store all information in a single value String.

+ * + * @author Joe Walnes + * @author Jörg Schaible + * @author Mauro Talevi + * @see com.thoughtworks.xstream.converters.Converter + * @see com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter + * @since 1.2 + */ +public interface SingleValueConverter extends ConverterMatcher { + + /** + * Marshals an Object into a single value representation. + * @param obj the Object to be converted + * @return a String with the single value of the Object or null + */ + public String toString(Object obj); + + /** + * Unmarshals an Object from its single value representation. + * @param str the String with the single value of the Object + * @return the Object + */ + public Object fromString(String str); + +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/SingleValueConverterWrapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/SingleValueConverterWrapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/SingleValueConverterWrapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2006, 2007, 2011, 2014 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 20. February 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.converters; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * Wrapper to convert a {@link com.thoughtworks.xstream.converters.SingleValueConverter} into a + * {@link com.thoughtworks.xstream.converters.Converter}. + * + * @author Jörg Schaible + * @see com.thoughtworks.xstream.converters.Converter + * @see com.thoughtworks.xstream.converters.SingleValueConverter + */ +public class SingleValueConverterWrapper implements Converter, SingleValueConverter, ErrorReporter { + + private final SingleValueConverter wrapped; + + public SingleValueConverterWrapper(final SingleValueConverter wrapped) { + this.wrapped = wrapped; + } + + @Override + public boolean canConvert(final Class type) { + return wrapped.canConvert(type); + } + + @Override + public String toString(final Object obj) { + return wrapped.toString(obj); + } + + @Override + public Object fromString(final String str) { + return wrapped.fromString(str); + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + writer.setValue(toString(source)); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + return fromString(reader.getValue()); + } + + @Override + public void appendErrors(final ErrorWriter errorWriter) { + errorWriter.add("wrapped-converter", wrapped == null ? "(null)" : wrapped.getClass().getName()); + if (wrapped instanceof ErrorReporter) { + ((ErrorReporter)wrapped).appendErrors(errorWriter); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/UnmarshallingContext.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/UnmarshallingContext.java (.../UnmarshallingContext.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/UnmarshallingContext.java (.../UnmarshallingContext.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,13 +1,55 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 06. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters; public interface UnmarshallingContext extends DataHolder { - Object convertAnother(Object current, Class type); + /** + * Convert a nested object of given type. + * + * @param current the current instance (can be {@code null}) + * @param type the expected type of the nested object + * @return the unmarshalled object + */ + Object convertAnother(Object current, Class type); + /** + * Convert a nested object of given type with a specified converter. + * + * @param current the current instance (can be {@code null}) + * @param type the expected type of the nested object + * @param converter the converter to use (special cases only) + * @return the unmarshalled object + * @since 1.2 + */ + Object convertAnother(Object current, Class type, Converter converter); + + /** + * Retrieve the given root object. + * + *

This method will return only an object, if the parent object is root and the root was provided.

+ * + * @return the root object or {@code null} + * @see com.thoughtworks.xstream.XStream#unmarshal(com.thoughtworks.xstream.io.HierarchicalStreamReader, Object, DataHolder) + */ Object currentObject(); - Class getRequiredType(); + /** + * Retrieve the required type for the current conversion. + * + * @return the class type + */ + Class getRequiredType(); void addCompletionCallback(Runnable work, int priority); - + } Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/AbstractBasicConverter.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/AbstractSingleValueConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/AbstractSingleValueConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/AbstractSingleValueConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006, 2007, 2013, 2014 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 15. February 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.converters.basic; + +import com.thoughtworks.xstream.converters.SingleValueConverter; + + +/** + * Base abstract implementation of {@link SingleValueConverter}. + *

+ * Subclasses should implement methods canConvert(Class) and fromString(String) for the conversion. + *

+ * + * @author Joe Walnes + * @author Jörg Schaible + * @author Mauro Talevi + * @see com.thoughtworks.xstream.converters.SingleValueConverter + */ +public abstract class AbstractSingleValueConverter implements SingleValueConverter { + + @Override + public abstract boolean canConvert(Class type); + + @Override + public String toString(final Object obj) { + return obj == null ? null : obj.toString(); + } + + @Override + public abstract Object fromString(String str); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigDecimalConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigDecimalConverter.java (.../BigDecimalConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigDecimalConverter.java (.../BigDecimalConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,20 +1,33 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 07. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.basic; import java.math.BigDecimal; + /** - * Converts a java.math.BigDecimal to a String, retaining - * its precision. - * + * Converts a {@link BigDecimal} to a string, retaining its precision. + * * @author Joe Walnes */ -public class BigDecimalConverter extends AbstractBasicConverter { +public class BigDecimalConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(BigDecimal.class); } - protected Object fromString(String str) { + @Override + public Object fromString(final String str) { return new BigDecimal(str); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigIntegerConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigIntegerConverter.java (.../BigIntegerConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BigIntegerConverter.java (.../BigIntegerConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,19 +1,33 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 07. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.basic; import java.math.BigInteger; + /** - * Converts a java.math.BigInteger to a String. - * + * Converts a {@link BigInteger} to a string. + * * @author Joe Walnes */ -public class BigIntegerConverter extends AbstractBasicConverter { +public class BigIntegerConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(BigInteger.class); } - protected Object fromString(String str) { + @Override + public Object fromString(final String str) { return new BigInteger(str); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BooleanConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BooleanConverter.java (.../BooleanConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/BooleanConverter.java (.../BooleanConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,19 +1,69 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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.converters.basic; /** - * Converts a boolean primitive or java.lang.Boolean wrapper to - * a String. - * + * Converts a boolean primitive or {@link Boolean} wrapper to a string. + * * @author Joe Walnes + * @author David Blevins */ -public class BooleanConverter extends AbstractBasicConverter { +public class BooleanConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + public static final BooleanConverter TRUE_FALSE = new BooleanConverter("true", "false", false); + + public static final BooleanConverter YES_NO = new BooleanConverter("yes", "no", false); + + public static final BooleanConverter BINARY = new BooleanConverter("1", "0", true); + + private final String positive; + private final String negative; + private final boolean caseSensitive; + + public BooleanConverter(final String positive, final String negative, final boolean caseSensitive) { + this.positive = positive; + this.negative = negative; + this.caseSensitive = caseSensitive; + } + + public BooleanConverter() { + this("true", "false", false); + } + + /** + * @deprecated As of upcoming use {@link #canConvert(Class)} + */ + @Deprecated + public boolean shouldConvert(final Class type, final Object value) { + return true; + } + + @Override + public boolean canConvert(final Class type) { return type.equals(boolean.class) || type.equals(Boolean.class); } - protected Object fromString(String str) { - return str.equals("true") ? Boolean.TRUE : Boolean.FALSE; + @Override + public Object fromString(final String str) { + if (caseSensitive) { + return positive.equals(str) ? Boolean.TRUE : Boolean.FALSE; + } else { + return positive.equalsIgnoreCase(str) ? Boolean.TRUE : Boolean.FALSE; + } } + @Override + public String toString(final Object obj) { + final Boolean value = (Boolean)obj; + return obj == null ? null : value.booleanValue() ? positive : negative; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ByteConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ByteConverter.java (.../ByteConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ByteConverter.java (.../ByteConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,19 +1,36 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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.converters.basic; /** - * Converts a byte primitive or java.lang.Byte wrapper to - * a String. + * Converts a byte primitive or {@link Byte} wrapper to + * a string. * * @author Joe Walnes */ -public class ByteConverter extends AbstractBasicConverter { +public class ByteConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(byte.class) || type.equals(Byte.class); } - protected Object fromString(String str) { - return new Byte((byte) Integer.parseInt(str)); + @Override + public Object fromString(final String str) { + final int value = Integer.decode(str).intValue(); + if(value < Byte.MIN_VALUE || value > 0xFF) { + throw new NumberFormatException("For input string: \"" + str + '"'); + } + return new Byte((byte)value); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/CharConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/CharConverter.java (.../CharConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/CharConverter.java (.../CharConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,39 +1,66 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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.converters.basic; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; /** - * Converts a char primitive or java.lang.Character wrapper to - * a String. If char is \0, this will be marked as an attribute as - * XML does not allow this. + * Converts a char primitive or {@link Character} wrapper to + * a string. If char is '\0' the representing string is empty. * * @author Joe Walnes + * @author Jörg Schaible */ -public class CharConverter implements Converter { +public class CharConverter implements Converter, SingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(char.class) || type.equals(Character.class); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - if (source.toString().equals("\0")) { - writer.addAttribute("null", "true"); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Character ch = (Character)source; + writer.setValue(toString(ch)); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String nullAttribute = reader.getAttribute("null"); + if (nullAttribute != null && nullAttribute.equals("true")) { + return new Character('\0'); } else { - writer.setValue(source.toString()); + return fromString(reader.getValue()); } } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - String nullAttribute = reader.getAttribute("null"); - if (nullAttribute != null && nullAttribute.equals("true")) { + @Override + public Object fromString(final String str) { + if (str.length() == 0) { return new Character('\0'); } else { - return new Character(reader.getValue().charAt(0)); + return new Character(str.charAt(0)); } } + @Override + public String toString(final Object obj) { + final char ch = ((Character)obj).charValue(); + return ch == '\0' ? "" : obj.toString(); + } + } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DateConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DateConverter.java (.../DateConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DateConverter.java (.../DateConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,59 +1,242 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014 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.converters.basic; -import com.thoughtworks.xstream.converters.ConversionException; - import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.ErrorReporter; +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.core.util.ThreadSafeSimpleDateFormat; + + /** - * Converts a java.util.Date to a String as a date format, - * retaining precision down to milliseconds. - * + * Converts a {@link Date} to a string as a date format, retaining precision down to milliseconds. + *

+ * The formatted string is by default in UTC and English locale. You can provide a different {@link Locale} and + * {@link TimeZone} that are used for serialization or null to use always the current TimeZone. Note, that + * the default format uses 3-letter time zones that can be ambiguous and may cause wrong results at deserialization and + * is localized since Java 6. + *

+ *

+ * Dates in a different era are using a special default pattern that contains the era itself. + *

+ * * @author Joe Walnes + * @author Jörg Schaible */ -public class DateConverter extends AbstractBasicConverter { +public class DateConverter extends AbstractSingleValueConverter implements ErrorReporter { + private static final String[] DEFAULT_ACCEPTABLE_FORMATS; + private static final String DEFAULT_PATTERN; + private static final String DEFAULT_ERA_PATTERN; + private static final TimeZone UTC; + private static final long ERA_START; + static { + UTC = TimeZone.getTimeZone("UTC"); + + final String defaultPattern = "yyyy-MM-dd HH:mm:ss.S z"; + final String defaultEraPattern = "yyyy-MM-dd G HH:mm:ss.S z"; + final List acceptablePatterns = new ArrayList(); + final boolean utcSupported = JVM.canParseUTCDateFormat(); + DEFAULT_PATTERN = utcSupported ? defaultPattern : "yyyy-MM-dd HH:mm:ss.S 'UTC'"; + DEFAULT_ERA_PATTERN = utcSupported ? defaultEraPattern : "yyyy-MM-dd G HH:mm:ss.S 'UTC'"; + acceptablePatterns.add("yyyy-MM-dd HH:mm:ss.S z"); + if (!utcSupported) { + acceptablePatterns.add(defaultPattern); + } + acceptablePatterns.add("yyyy-MM-dd HH:mm:ss.S a"); + // TODO: JDK 1.3 needs both versions + acceptablePatterns.add("yyyy-MM-dd HH:mm:ssz"); + acceptablePatterns.add("yyyy-MM-dd HH:mm:ss z"); + if (!utcSupported) { + acceptablePatterns.add("yyyy-MM-dd HH:mm:ss 'UTC'"); + } + // backwards compatibility + acceptablePatterns.add("yyyy-MM-dd HH:mm:ssa"); + DEFAULT_ACCEPTABLE_FORMATS = acceptablePatterns.toArray(new String[acceptablePatterns.size()]); + + final Calendar cal = Calendar.getInstance(); + cal.setTimeZone(UTC); + cal.clear(); + cal.set(1, Calendar.JANUARY, 1); + ERA_START = cal.getTimeInMillis(); + } private final ThreadSafeSimpleDateFormat defaultFormat; + private final ThreadSafeSimpleDateFormat defaultEraFormat; private final ThreadSafeSimpleDateFormat[] acceptableFormats; + /** + * Construct a DateConverter with standard formats and lenient set off. + */ public DateConverter() { - this("yyyy-MM-dd HH:mm:ss.S z", - new String[] { - "yyyy-MM-dd HH:mm:ss.S a", - "yyyy-MM-dd HH:mm:ssz", "yyyy-MM-dd HH:mm:ss z", // JDK 1.3 needs both versions - "yyyy-MM-dd HH:mm:ssa" }); // backwards compatability - } + this(false); + } - public DateConverter(String defaultFormat, String[] acceptableFormats) { - this.defaultFormat = new ThreadSafeSimpleDateFormat(defaultFormat, 4, 20); - this.acceptableFormats = new ThreadSafeSimpleDateFormat[acceptableFormats.length]; - for (int i = 0; i < acceptableFormats.length; i++) { - this.acceptableFormats[i] = new ThreadSafeSimpleDateFormat(acceptableFormats[i], 1, 20); + /** + * Construct a DateConverter with standard formats, lenient set off and uses a given TimeZone for serialization. + * + * @param timeZone the TimeZone used to serialize the Date + * @since 1.4 + */ + public DateConverter(final TimeZone timeZone) { + this(DEFAULT_PATTERN, DEFAULT_ACCEPTABLE_FORMATS, timeZone); + } + + /** + * Construct a DateConverter with standard formats and using UTC. + * + * @param lenient the lenient setting of {@link SimpleDateFormat#setLenient(boolean)} + * @since 1.3 + */ + public DateConverter(final boolean lenient) { + this(DEFAULT_PATTERN, DEFAULT_ACCEPTABLE_FORMATS, lenient); + } + + /** + * Construct a DateConverter with lenient set off using UTC. + * + * @param defaultFormat the default format + * @param acceptableFormats fallback formats + */ + public DateConverter(final String defaultFormat, final String[] acceptableFormats) { + this(defaultFormat, acceptableFormats, false); + } + + /** + * Construct a DateConverter with a given TimeZone and lenient set off. + * + * @param defaultFormat the default format + * @param acceptableFormats fallback formats + * @since 1.4 + */ + public DateConverter(final String defaultFormat, final String[] acceptableFormats, final TimeZone timeZone) { + this(defaultFormat, acceptableFormats, timeZone, false); + } + + /** + * Construct a DateConverter. + * + * @param defaultFormat the default format + * @param acceptableFormats fallback formats + * @param lenient the lenient setting of {@link SimpleDateFormat#setLenient(boolean)} + * @since 1.3 + */ + public DateConverter(final String defaultFormat, final String[] acceptableFormats, final boolean lenient) { + this(defaultFormat, acceptableFormats, UTC, lenient); + } + + /** + * Construct a DateConverter. + * + * @param defaultFormat the default format + * @param acceptableFormats fallback formats + * @param timeZone the TimeZone used to serialize the Date + * @param lenient the lenient setting of {@link SimpleDateFormat#setLenient(boolean)} + * @since 1.4 + */ + public DateConverter( + final String defaultFormat, final String[] acceptableFormats, final TimeZone timeZone, final boolean lenient) { + this(DEFAULT_ERA_PATTERN, defaultFormat, acceptableFormats, Locale.ENGLISH, timeZone, lenient); + } + + /** + * Construct a DateConverter. + * + * @param defaultEraFormat the default format for dates in a different era (may be null to drop era + * support) + * @param defaultFormat the default format + * @param acceptableFormats fallback formats + * @param locale locale to use for the format + * @param timeZone the TimeZone used to serialize the Date + * @param lenient the lenient setting of {@link SimpleDateFormat#setLenient(boolean)} + * @since 1.4.4 + */ + public DateConverter( + final String defaultEraFormat, final String defaultFormat, final String[] acceptableFormats, + final Locale locale, final TimeZone timeZone, final boolean lenient) { + if (defaultEraFormat != null) { + this.defaultEraFormat = new ThreadSafeSimpleDateFormat(defaultEraFormat, timeZone, locale, 4, 20, lenient); + } else { + this.defaultEraFormat = null; } + this.defaultFormat = new ThreadSafeSimpleDateFormat(defaultFormat, timeZone, locale, 4, 20, lenient); + this.acceptableFormats = acceptableFormats != null + ? new ThreadSafeSimpleDateFormat[acceptableFormats.length] + : new ThreadSafeSimpleDateFormat[0]; + for (int i = 0; i < this.acceptableFormats.length; i++) { + this.acceptableFormats[i] = new ThreadSafeSimpleDateFormat(acceptableFormats[i], timeZone, locale, 1, 20, + lenient); + } } - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(Date.class); } - protected Object fromString(String str) { - try { - return defaultFormat.parse(str); - } catch (ParseException e) { - for (int i = 0; i < acceptableFormats.length; i++) { - try { - return acceptableFormats[i].parse(str); - } catch (ParseException e2) { - // no worries, let's try the next format. - } + @Override + public Object fromString(final String str) { + if (defaultEraFormat != null) { + try { + return defaultEraFormat.parse(str); + } catch (final ParseException e) { + // try next ... } - // no dateFormats left to try - throw new ConversionException("Cannot parse date " + str); } + if (defaultEraFormat != defaultFormat) { + try { + return defaultFormat.parse(str); + } catch (final ParseException e) { + // try next ... + } + } + for (final ThreadSafeSimpleDateFormat acceptableFormat : acceptableFormats) { + try { + return acceptableFormat.parse(str); + } catch (final ParseException e3) { + // no worries, let's try the next format. + } + } + // no dateFormats left to try + throw new ConversionException("Cannot parse date " + str); } - protected String toString(Object obj) { - return defaultFormat.format((Date) obj); + @Override + public String toString(final Object obj) { + final Date date = (Date)obj; + if (date.getTime() < ERA_START && defaultEraFormat != null) { + return defaultEraFormat.format(date); + } else { + return defaultFormat.format(date); + } } + @Override + public void appendErrors(final ErrorWriter errorWriter) { + errorWriter.add("Default date pattern", defaultFormat.toString()); + if (defaultEraFormat != null) { + errorWriter.add("Default era date pattern", defaultEraFormat.toString()); + } + for (final ThreadSafeSimpleDateFormat acceptableFormat : acceptableFormats) { + errorWriter.add("Alternative date pattern", acceptableFormat.toString()); + } + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DoubleConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DoubleConverter.java (.../DoubleConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/DoubleConverter.java (.../DoubleConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,18 +1,30 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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.converters.basic; /** - * Converts a double primitive or java.lang.Double wrapper to - * a String. - * + * Converts a double primitive or {@link Double} wrapper to a string. + * * @author Joe Walnes */ -public class DoubleConverter extends AbstractBasicConverter { +public class DoubleConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(double.class) || type.equals(Double.class); } - protected Object fromString(String str) { + @Override + public Object fromString(final String str) { return Double.valueOf(str); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/FloatConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/FloatConverter.java (.../FloatConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/FloatConverter.java (.../FloatConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,18 +1,30 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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.converters.basic; /** - * Converts a float primitive or java.lang.Float wrapper to - * a String. - * + * Converts a float primitive or {@link Float} wrapper to a string. + * * @author Joe Walnes */ -public class FloatConverter extends AbstractBasicConverter { +public class FloatConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(float.class) || type.equals(Float.class); } - protected Object fromString(String str) { + @Override + public Object fromString(final String str) { return Float.valueOf(str); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/IntConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/IntConverter.java (.../IntConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/IntConverter.java (.../IntConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,19 +1,35 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007 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.converters.basic; /** - * Converts an int primitive or java.lang.Integer wrapper to - * a String. - * + * Converts an int primitive or {@link Integer} wrapper to a string. + * * @author Joe Walnes */ -public class IntConverter extends AbstractBasicConverter { +public class IntConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(int.class) || type.equals(Integer.class); } - protected Object fromString(String str) { - return Integer.decode(str); + @Override + public Object fromString(final String str) { + final long value = Long.decode(str).longValue(); + if (value < Integer.MIN_VALUE || value > 0xFFFFFFFFl) { + throw new NumberFormatException("For input string: \"" + str + '"'); + } + return new Integer((int)value); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/LongConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/LongConverter.java (.../LongConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/LongConverter.java (.../LongConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,19 +1,58 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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.converters.basic; /** - * Converts a long primitive or java.lang.Long wrapper to - * a String. - * + * Converts a long primitive or {@link Long} wrapper to a string. + * * @author Joe Walnes */ -public class LongConverter extends AbstractBasicConverter { +public class LongConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(long.class) || type.equals(Long.class); } - protected Object fromString(String str) { - return Long.valueOf(str); + @Override + public Object fromString(final String str) { + final int len = str.length(); + if (len == 0) { + throw new NumberFormatException("For input string: \"\""); + } + if (len < 17) { + return Long.decode(str); + } + final char c0 = str.charAt(0); + if (c0 != '0' && c0 != '#') { + return Long.decode(str); + } + final char c1 = str.charAt(1); + final long high; + final long low; + if (c0 == '#' && len == 17) { + high = Long.parseLong(str.substring(1, 9), 16) << 32; + low = Long.parseLong(str.substring(9, 17), 16); + } else if ((c1 == 'x' || c1 == 'X') && len == 18) { + high = Long.parseLong(str.substring(2, 10), 16) << 32; + low = Long.parseLong(str.substring(10, 18), 16); + } else if (len == 23 && c1 == '1') { + high = Long.parseLong(str.substring(1, 12), 8) << 33; + low = Long.parseLong(str.substring(12, 23), 8); + } else { + return Long.decode(str); + } + final long num = high | low; + return new Long(num); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/NullConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/NullConverter.java (.../NullConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/NullConverter.java (.../NullConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,28 +1,45 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2012, 2014 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 03. October 2003 by Joe Walnes + */ package com.thoughtworks.xstream.converters.basic; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + /** - * Special converter to signify nulls at the root level. - * + * Special converter to signify nulls at the root level or in collection types. + * * @author Joe Walnes */ public class NullConverter implements Converter { - public boolean canConvert(Class type) { - return type == null; + @Override + public boolean canConvert(final Class type) { + return type == null || Mapper.Null.class.isAssignableFrom(type); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - writer.startNode("null"); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + ExtendedHierarchicalStreamWriterHelper.startNode(writer, "null", Mapper.Null.class); writer.endNode(); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { return null; } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ShortConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ShortConverter.java (.../ShortConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ShortConverter.java (.../ShortConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,19 +1,35 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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.converters.basic; /** - * Converts a short primitive or java.lang.Short wrapper to - * a String. - * + * Converts a short primitive or {@link Short} wrapper to a string. + * * @author Joe Walnes */ -public class ShortConverter extends AbstractBasicConverter { +public class ShortConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(short.class) || type.equals(Short.class); } - protected Object fromString(String str) { - return Short.valueOf(str); + @Override + public Object fromString(final String str) { + final int value = Integer.decode(str).intValue(); + if (value < Short.MIN_VALUE || value > 0xFFFF) { + throw new NumberFormatException("For input string: \"" + str + '"'); + } + return new Short((short)value); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringBufferConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringBufferConverter.java (.../StringBufferConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringBufferConverter.java (.../StringBufferConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,17 +1,30 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 29. September 2003 by Joe Walnes + */ package com.thoughtworks.xstream.converters.basic; /** - * Converts the contents of a StringBuffer to XML. - * + * Converts the contents of a {@link StringBuffer} to a string. + * * @author Joe Walnes */ -public class StringBufferConverter extends AbstractBasicConverter { +public class StringBufferConverter extends AbstractSingleValueConverter { - protected Object fromString(String str) { - return new StringBuffer(str); + @Override + public boolean canConvert(final Class type) { + return type.equals(StringBuffer.class); } - public boolean canConvert(Class type) { - return type.equals(StringBuffer.class); + @Override + public Object fromString(final String str) { + return new StringBuffer(str); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringBuilderConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringBuilderConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringBuilderConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2008, 2014 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 04. January 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.basic; + +/** + * Converts the contents of a {@link StringBuilder} to a string. + * + * @author Jörg Schaible + */ +public class StringBuilderConverter extends AbstractSingleValueConverter { + + @Override + public boolean canConvert(final Class type) { + return type.equals(StringBuilder.class); + } + + @Override + public Object fromString(final String str) { + return new StringBuilder(str); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringConverter.java (.../StringConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/StringConverter.java (.../StringConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,22 +1,103 @@ +/* + * Copyright (C) 2003, 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2011, 2014 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.converters.basic; +import java.util.Collections; +import java.util.Map; + +import com.thoughtworks.xstream.core.util.WeakCache; + + /** - * Converts a String to a String ;). Well ok, it doesn't - * actually do any conversion. - *

The converter always calls intern() on the returned - * String to encourage the JVM to reuse instances.

- * + * Converts a {@link String} to a string ;). + *

+ * Well ok, it doesn't actually do any conversion. The converter uses by default a map with weak references to + * reuse instances of strings that do not exceed a length limit. This limit is by default 38 characters to cache typical + * strings containing UUIDs. Only shorter strings are typically repeated more often in XML values. + *

+ * * @author Joe Walnes - * @see String#intern() + * @author Rene Schwietzke + * @author Jörg Schaible */ -public class StringConverter extends AbstractBasicConverter { +public class StringConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { - return type.equals(String.class); + private static final int LENGTH_LIMIT = 38; + + /** + * A Map to store strings as long as needed to map similar strings onto the same instance and conserve memory. The + * map can be set from the outside during construction, so it can be a LRU map or a weak map, synchronized or not. + */ + private final Map cache; + private final int lengthLimit; + + /** + * Construct a StringConverter using a map-based cache for strings not exceeding the length limit. + * + * @param map the map to use for the instances to reuse (may be null to not cache at all) + * @param lengthLimit maximum string length of a cached string, -1 to cache all, 0 to turn off the cache + * @since 1.4.2 + */ + public StringConverter(final Map map, final int lengthLimit) { + cache = map; + this.lengthLimit = lengthLimit; } - protected Object fromString(String str) { - return str.intern(); + /** + * Construct a StringConverter using a map-based cache for strings not exceeding 38 characters. + * + * @param map the map to use for the instances to reuse (may be null to not cache at all) + */ + public StringConverter(final Map map) { + this(map, LENGTH_LIMIT); } + /** + * Construct a StringConverter using a cache with weak references for strings not exceeding the length limit. + * + * @param lengthLimit maximum string length of a cached string, -1 to cache all, 0 to turn off the cache + * @since 1.4.2 + */ + public StringConverter(final int lengthLimit) { + this(Collections.synchronizedMap(new WeakCache()), lengthLimit); + } + + /** + * Construct a StringConverter using a cache with weak references for strings not exceeding 38 characters. + */ + public StringConverter() { + this(LENGTH_LIMIT); + } + + @Override + public boolean canConvert(final Class type) { + return type.equals(String.class); + } + + @Override + public Object fromString(final String str) { + if (cache != null && str != null && (lengthLimit < 0 || str.length() <= lengthLimit)) { + String s = cache.get(str); + + if (s == null) { + // fill cache + cache.put(str, str); + + s = str; + } + + return s; + } else { + return str; + } + } } Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/ThreadSafeSimpleDateFormat.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/URIConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/URIConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/URIConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2010, 2014 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 3. August 2010 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.basic; + +import java.net.URI; +import java.net.URISyntaxException; + +import com.thoughtworks.xstream.converters.ConversionException; + + +/** + * Converts a {@link URI} to a string. + * + * @author Carlos Roman + */ +public class URIConverter extends AbstractSingleValueConverter { + + @Override + public boolean canConvert(final Class type) { + return type.equals(URI.class); + } + + @Override + public Object fromString(final String str) { + try { + return new URI(str); + } catch (final URISyntaxException e) { + throw new ConversionException(e); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/URLConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/URLConverter.java (.../URLConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/URLConverter.java (.../URLConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,25 +1,39 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 25. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.basic; -import com.thoughtworks.xstream.converters.ConversionException; - import java.net.MalformedURLException; import java.net.URL; +import com.thoughtworks.xstream.converters.ConversionException; + + /** - * Converts a java.net.URL to a string. - * + * Converts a {@link URL} to a string. + * * @author J. Matthew Pryor */ -public class URLConverter extends AbstractBasicConverter { +public class URLConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(URL.class); } - protected Object fromString(String str) { + @Override + public Object fromString(final String str) { try { return new URL(str); - } catch (MalformedURLException e) { + } catch (final MalformedURLException e) { throw new ConversionException(e); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/UUIDConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/UUIDConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/UUIDConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008, 2014 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 04. January 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.basic; + +import java.util.UUID; + +import com.thoughtworks.xstream.converters.ConversionException; + + +/** + * Converts a {@link UUID} to a string. + * + * @author Jörg Schaible + */ +public class UUIDConverter extends AbstractSingleValueConverter { + + @Override + public boolean canConvert(final Class type) { + return type.equals(UUID.class); + } + + @Override + public Object fromString(final String str) { + try { + return UUID.fromString(str); + } catch (final IllegalArgumentException e) { + throw new ConversionException("Cannot create UUID instance", e); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/package.html =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/package.html (.../package.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/basic/package.html (.../package.html) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,3 +1,15 @@ + +

Converters for common basic types in Java. These include primitives (int, boolean, etc), wrapper objects (Integer, Boolean, etc), String, StringBuffer, java.util.Date, null, java.net.URL, @@ -7,3 +19,4 @@

All of the basic converters will convert the item into a single String, with no nested elements.

+ \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/AbstractCollectionConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/AbstractCollectionConverter.java (.../AbstractCollectionConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/AbstractCollectionConverter.java (.../AbstractCollectionConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,94 +1,85 @@ +/* + * Copyright (C) 2003, 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014 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.converters.collections; -import com.thoughtworks.xstream.alias.ClassMapper; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; + /** - * Base helper class for converters that need to handle - * collections of items (arrays, Lists, Maps, etc). - *

- *

Typically, subclasses of this will converter the outer - * structure of the collection, loop through the contents and - * call readItem() or writeItem() for each item.

- * + * Base helper class for converters that need to handle collections of items (arrays, Lists, Maps, etc). + *

+ * Typically, subclasses of this will converter the outer structure of the collection, loop through the contents and + * call readItem() or writeItem() for each item. + *

+ * * @author Joe Walnes */ public abstract class AbstractCollectionConverter implements Converter { private final Mapper mapper; - /** - * @deprecated As of 1.1.1, use {@link #mapper()} - */ - protected ClassMapper classMapper; + @Override + public abstract boolean canConvert(Class type); - /** - * @deprecated As of 1.1.1, use {@link #mapper()} - */ - protected String classAttributeIdentifier; - - public abstract boolean canConvert(Class type); - - /** - * @deprecated As of 1.1.1, use other constructor. - */ - public AbstractCollectionConverter(ClassMapper classMapper, String classAttributeIdentifier) { - // TODO: this classAttributeIdentifer should be optional - most uses of XStream don't need it. - this.classMapper = classMapper; - this.classAttributeIdentifier = classAttributeIdentifier; - this.mapper = classMapper; - } - - public AbstractCollectionConverter(Mapper mapper) { + public AbstractCollectionConverter(final Mapper mapper) { this.mapper = mapper; } protected Mapper mapper() { return mapper; } + @Override public abstract void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context); + @Override public abstract Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context); - protected void writeItem(Object item, MarshallingContext context, HierarchicalStreamWriter writer) { - // PUBLISHED API METHOD! If changing signature, ensure backwards compatability. + protected void writeItem(final Object item, final MarshallingContext context, final HierarchicalStreamWriter writer) { + // PUBLISHED API METHOD! If changing signature, ensure backwards compatibility. if (item == null) { // todo: this is duplicated in TreeMarshaller.start() - writer.startNode(mapper().serializedClass(ClassMapper.Null.class)); + final String name = mapper().serializedClass(null); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, Mapper.Null.class); writer.endNode(); } else { - writer.startNode(mapper().serializedClass(item.getClass())); + final String name = mapper().serializedClass(item.getClass()); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, item.getClass()); context.convertAnother(item); writer.endNode(); } } - protected Object readItem(HierarchicalStreamReader reader, UnmarshallingContext context, Object current) { - // PUBLISHED API METHOD! If changing signature, ensure backwards compatability. - String classAttribute = reader.getAttribute(mapper().attributeForImplementationClass()); - Class type; - if (classAttribute == null) { - type = mapper().realClass(reader.getNodeName()); - } else { - type = mapper().realClass(classAttribute); - } + protected Object readItem(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Object current) { + final Class type = HierarchicalStreams.readClassType(reader, mapper()); return context.convertAnother(current, type); } - protected Object createCollection(Class type) { - Class defaultType = mapper().defaultImplementationOf(type); + protected Object createCollection(final Class type) { + final Class defaultType = mapper().defaultImplementationOf(type); try { return defaultType.newInstance(); - } catch (InstantiationException e) { + } catch (final InstantiationException e) { throw new ConversionException("Cannot instantiate " + defaultType.getName(), e); - } catch (IllegalAccessException e) { + } catch (final IllegalAccessException e) { throw new ConversionException("Cannot instantiate " + defaultType.getName(), e); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/ArrayConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/ArrayConverter.java (.../ArrayConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/ArrayConverter.java (.../ArrayConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,64 +1,69 @@ +/* + * Copyright (C) 2003, 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 03. October 2003 by Joe Walnes + */ package com.thoughtworks.xstream.converters.collections; -import com.thoughtworks.xstream.alias.ClassMapper; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; + import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; /** - * Converts an array of objects or primitives to XML, using - * a nested child element for each item. - * + * Converts an array of objects or primitives, using a nested child element for each item. + * * @author Joe Walnes + * @see com.thoughtworks.xstream.converters.extended.NamedArrayConverter */ public class ArrayConverter extends AbstractCollectionConverter { - /** - * @deprecated As of 1.1.1, use other constructor. - */ - public ArrayConverter(ClassMapper classMapper, String classAttributeIdentifier) { - super(classMapper, classAttributeIdentifier); - } - - public ArrayConverter(Mapper mapper) { + public ArrayConverter(final Mapper mapper) { super(mapper); } - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.isArray(); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - int length = Array.getLength(source); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final int length = Array.getLength(source); for (int i = 0; i < length; i++) { - Object item = Array.get(source, i); + final Object item = Array.get(source, i); writeItem(item, context, writer); } + } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - // read the items from xml into a list - List items = new ArrayList(); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + // read the items from xml into a list (the array size is not known until all items have been read) + final List items = new ArrayList(); while (reader.hasMoreChildren()) { reader.moveDown(); - Object item = readItem(reader, context, null); // TODO: arg, what should replace null? + final Object item = readItem(reader, context, null); // TODO: arg, what should replace null? items.add(item); reader.moveUp(); } // now convertAnother the list into an array - // (this has to be done as a separate list as the array size is not - // known until all items have been read) - Object array = Array.newInstance(context.getRequiredType().getComponentType(), items.size()); + final Object array = Array.newInstance(context.getRequiredType().getComponentType(), items.size()); int i = 0; - for (Iterator iterator = items.iterator(); iterator.hasNext();) { - Array.set(array, i++, iterator.next()); + for (final Object item : items) { + Array.set(array, i++, item); } return array; } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/BitSetConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/BitSetConverter.java (.../BitSetConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/BitSetConverter.java (.../BitSetConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,29 +1,42 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.collections; +import java.util.BitSet; +import java.util.StringTokenizer; + import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import java.util.BitSet; -import java.util.StringTokenizer; /** - * Converts a java.util.BitSet to XML, as a compact - * comma delimited list of ones and zeros. - * + * Converts a {@link BitSet}, as a compact comma delimited list of ones and zeros. + * * @author Joe Walnes */ public class BitSetConverter implements Converter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(BitSet.class); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - BitSet bitSet = (BitSet) source; - StringBuffer buffer = new StringBuffer(); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final BitSet bitSet = (BitSet)source; + final StringBuilder buffer = new StringBuilder(); boolean seenFirst = false; for (int i = 0; i < bitSet.length(); i++) { if (bitSet.get(i)) { @@ -38,11 +51,12 @@ writer.setValue(buffer.toString()); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - BitSet result = new BitSet(); - StringTokenizer tokenizer = new StringTokenizer(reader.getValue(), ",", false); + @Override + public BitSet unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final BitSet result = new BitSet(); + final StringTokenizer tokenizer = new StringTokenizer(reader.getValue(), ",", false); while (tokenizer.hasMoreTokens()) { - int index = Integer.parseInt(tokenizer.nextToken()); + final int index = Integer.parseInt(tokenizer.nextToken()); result.set(index); } return result; Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CharArrayConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CharArrayConverter.java (.../CharArrayConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CharArrayConverter.java (.../CharArrayConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,3 +1,14 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 06. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.collections; import com.thoughtworks.xstream.converters.Converter; @@ -6,24 +17,27 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + /** - * Converts a char[] to XML, storing the contents as a single - * String. - * + * Converts a char[] as a single string. + * * @author Joe Walnes */ public class CharArrayConverter implements Converter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.isArray() && type.getComponentType().equals(char.class); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - char[] chars = (char[]) source; + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + char[] chars = (char[])source; writer.setValue(new String(chars)); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + @Override + public char[] unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { return reader.getValue().toCharArray(); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CollectionConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CollectionConverter.java (.../CollectionConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/CollectionConverter.java (.../CollectionConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,66 +1,116 @@ +/* + * Copyright (C) 2003, 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014 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 01. October 2003 by Joe Walnes + */ package com.thoughtworks.xstream.converters.collections; -import com.thoughtworks.xstream.alias.ClassMapper; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.Vector; + import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.core.JVM; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; -import java.util.*; /** - * Converts most common Collections (Lists and Sets) to XML, specifying a nested - * element for each item. - *

- *

Supports java.util.ArrayList, java.util.HashSet, - * java.util.LinkedList, java.util.Vector and java.util.LinkedHashSet.

- * + * Converts most common Collections (Lists and Sets), specifying a nested element for each item. + *

+ * Supports {@link ArrayList}, {@link HashSet}, {@link LinkedList}, {@link Vector} and {@link LinkedHashSet}. + *

+ * * @author Joe Walnes + * @see com.thoughtworks.xstream.converters.extended.NamedCollectionConverter */ public class CollectionConverter extends AbstractCollectionConverter { - /** - * @deprecated As of 1.1.1, use other constructor. - */ - public CollectionConverter(ClassMapper classMapper, String classAttributeIdentifier) { - super(classMapper, classAttributeIdentifier); + private final Class> type; + + public CollectionConverter(final Mapper mapper) { + this(mapper, null); } - public CollectionConverter(Mapper mapper) { + /** + * Construct a CollectionConverter for a special Collection type. + * + * @param mapper the mapper + * @param type the Collection type to handle + * @since 1.4.5 + */ + public CollectionConverter(final Mapper mapper, @SuppressWarnings("rawtypes") final Class type) { super(mapper); + @SuppressWarnings("unchecked") + final Class> checkedType = (Class>)type; + this.type = checkedType; + if (type != null && !Collection.class.isAssignableFrom(type)) { + throw new IllegalArgumentException(type + " not of type " + Collection.class); + } } - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { + if (this.type != null) { + return type.equals(this.type); + } return type.equals(ArrayList.class) - || type.equals(HashSet.class) - || type.equals(LinkedList.class) - || type.equals(Vector.class) - || (JVM.is14() && type.getName().equals("java.util.LinkedHashSet")); + || type.equals(HashSet.class) + || type.equals(LinkedList.class) + || type.equals(Vector.class) + || type.equals(LinkedHashSet.class); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - Collection collection = (Collection) source; - for (Iterator iterator = collection.iterator(); iterator.hasNext();) { - Object item = iterator.next(); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Collection collection = (Collection)source; + for (final Object item : collection) { writeItem(item, context, writer); } } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - Collection collection = (Collection) createCollection(context.getRequiredType()); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Class collectionType = context.getRequiredType(); + final Collection collection = createCollection(collectionType); populateCollection(reader, context, collection); return collection; } - protected void populateCollection(HierarchicalStreamReader reader, UnmarshallingContext context, Collection collection) { + protected void populateCollection(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Collection collection) { + populateCollection(reader, context, collection, collection); + } + + protected void populateCollection(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Collection collection, final Collection target) { while (reader.hasMoreChildren()) { reader.moveDown(); - Object item = readItem(reader, context, collection); - collection.add(item); + addCurrentElementToCollection(reader, context, collection, target); reader.moveUp(); } } + protected void addCurrentElementToCollection(final HierarchicalStreamReader reader, + final UnmarshallingContext context, final Collection collection, final Collection target) { + final Object item = readItem(reader, context, collection); + @SuppressWarnings("unchecked") + final Collection targetCollection = (Collection)target; + targetCollection.add(item); + } + + @Override + protected Collection createCollection(final Class type) { + return (Collection)super.createCollection(this.type != null ? this.type : type); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/MapConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/MapConverter.java (.../MapConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/MapConverter.java (.../MapConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,51 +1,88 @@ +/* + * Copyright (C) 2003, 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014 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.converters.collections; -import com.thoughtworks.xstream.alias.ClassMapper; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; /** - * Converts a java.util.Map to XML, specifying an 'entry' - * element with 'key' and 'value' children. - *

- *

Supports java.util.HashMap, java.util.Hashtable and - * java.util.LinkedHashMap.

- * + * Converts a {@link Map}, specifying an 'entry' element with 'key' and 'value' children. + *

+ * Note: 'key' and 'value' is not the name of the generated tag. The children are serialized as normal elements and the + * implementation expects them in the order 'key'/'value'. + *

+ *

+ * Supports {@link HashMap}, {@link Hashtable}, {@link LinkedHashMap}, {@link ConcurrentHashMap} and + * sun.font.AttributeMap. + *

+ * + * @see com.thoughtworks.xstream.converters.extended.NamedMapConverter * @author Joe Walnes */ public class MapConverter extends AbstractCollectionConverter { - /** - * @deprecated As of 1.1.1, use other constructor. - */ - public MapConverter(ClassMapper classMapper, String classAttributeIdentifier) { - super(classMapper, classAttributeIdentifier); + private final Class> type; + + public MapConverter(final Mapper mapper) { + this(mapper, null); } - public MapConverter(Mapper mapper) { + /** + * Construct a MapConverter for a special Map type. + * + * @param mapper the mapper + * @param type the type to handle + * @since 1.4.5 + */ + public MapConverter(final Mapper mapper, @SuppressWarnings("rawtypes") final Class type) { super(mapper); + @SuppressWarnings("unchecked") + final Class> checkedType = (Class>)type; + this.type = checkedType; + if (type != null && !Map.class.isAssignableFrom(type)) { + throw new IllegalArgumentException(type + " not of type " + Map.class); + } } - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { + if (this.type != null) { + return type.equals(this.type); + } return type.equals(HashMap.class) - || type.equals(Hashtable.class) - || (JVM.is14() && type.getName().equals("java.util.LinkedHashMap")); + || type.equals(Hashtable.class) + || type.equals(LinkedHashMap.class) + || type.equals(ConcurrentHashMap.class) + || type.getName().equals("sun.font.AttributeMap") // Used by java.awt.Font since JDK 6 + ; } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - Map map = (Map) source; - for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) { - Map.Entry entry = (Map.Entry) iterator.next(); - writer.startNode(mapper().serializedClass(Map.Entry.class)); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Map map = (Map)source; + final String entryName = mapper().serializedClass(Map.Entry.class); + for (final Map.Entry entry : map.entrySet()) { + ExtendedHierarchicalStreamWriterHelper.startNode(writer, entryName, entry.getClass()); writeItem(entry.getKey(), context, writer); writeItem(entry.getValue(), context, writer); @@ -54,28 +91,45 @@ } } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - Map map = (Map) createCollection(context.getRequiredType()); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Class requiredType = context.getRequiredType(); + final Map map = createCollection(requiredType); populateMap(reader, context, map); return map; } - protected void populateMap(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) { + protected void populateMap(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Map map) { + populateMap(reader, context, map, map); + } + + protected void populateMap(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Map map, final Map target) { while (reader.hasMoreChildren()) { reader.moveDown(); - - reader.moveDown(); - Object key = readItem(reader, context, map); + putCurrentEntryIntoMap(reader, context, map, target); reader.moveUp(); + } + } - reader.moveDown(); - Object value = readItem(reader, context, map); - reader.moveUp(); + protected void putCurrentEntryIntoMap(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Map map, final Map target) { + reader.moveDown(); + final Object key = readItem(reader, context, map); + reader.moveUp(); - map.put(key, value); + reader.moveDown(); + final Object value = readItem(reader, context, map); + reader.moveUp(); - reader.moveUp(); - } + @SuppressWarnings("unchecked") + final Map targetMap = (Map)target; + targetMap.put(key, value); } + @Override + protected Map createCollection(final Class type) { + return (Map)super.createCollection(this.type != null ? this.type : type); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java (.../PropertiesConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java (.../PropertiesConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,70 +1,104 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014 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 23. February 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.collections; +import java.lang.reflect.Field; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; + import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.core.util.Fields; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.core.util.Fields; -import java.util.Iterator; -import java.util.Map; -import java.util.Properties; -import java.lang.reflect.Field; /** - * Special converter for java.util.Properties that stores - * properties in a more compact form than java.util.Map. - *

- *

Because all entries of a Properties instance - * are Strings, a single element is used for each property - * with two attributes; one for key and one for value.

- *

Additionally, default properties are also serialized, if they are present.

- * + * Special converter for {@link Properties} that stores properties in a more compact form than java.util.Map. + *

+ * Because all entries of a Properties instance are Strings, a single element is used for each property with two + * attributes; one for key and one for value. + *

+ *

+ * Additionally, default properties are also serialized, if they are present or if a SecurityManager is set, and it has + * permissions for SecurityManager.checkPackageAccess, SecurityManager.checkMemberAccess(this, EnumSet.MEMBER) and + * ReflectPermission("suppressAccessChecks"). + *

+ * * @author Joe Walnes * @author Kevin Ring */ public class PropertiesConverter implements Converter { - private final Field defaultsField = Fields.find(Properties.class, "defaults"); + private final static Field defaultsField = Fields.locate(Properties.class, Properties.class, false); + private final boolean sort; - public boolean canConvert(Class type) { + public PropertiesConverter() { + this(false); + } + + public PropertiesConverter(final boolean sort) { + this.sort = sort; + } + + @Override + public boolean canConvert(final Class type) { return Properties.class == type; } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - Properties properties = (Properties) source; - for (Iterator iterator = properties.entrySet().iterator(); iterator.hasNext();) { - Map.Entry entry = (Map.Entry) iterator.next(); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Properties properties = (Properties)source; + final Map map = sort ? new TreeMap(properties) : properties; + for (final Map.Entry entry : map.entrySet()) { writer.startNode("property"); writer.addAttribute("name", entry.getKey().toString()); writer.addAttribute("value", entry.getValue().toString()); writer.endNode(); } - Properties defaults = (Properties) Fields.read(defaultsField, properties); - if (defaults != null) { - writer.startNode("defaults"); - marshal(defaults, writer, context); - writer.endNode(); + if (defaultsField != null) { + final Properties defaults = (Properties)Fields.read(defaultsField, properties); + if (defaults != null) { + writer.startNode("defaults"); + marshal(defaults, writer, context); + writer.endNode(); + } } } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - Properties properties = new Properties(); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Properties properties = new Properties(); + Properties defaults = null; while (reader.hasMoreChildren()) { reader.moveDown(); if (reader.getNodeName().equals("defaults")) { - Properties defaults = (Properties) unmarshal(reader, context); - Fields.write(defaultsField, properties, defaults); + defaults = (Properties)unmarshal(reader, context); } else { - String name = reader.getAttribute("name"); - String value = reader.getAttribute("value"); + final String name = reader.getAttribute("name"); + final String value = reader.getAttribute("value"); properties.setProperty(name, value); } reader.moveUp(); } - return properties; + if (defaults == null) { + return properties; + } else { + final Properties propertiesWithDefaults = new Properties(defaults); + propertiesWithDefaults.putAll(properties); + return propertiesWithDefaults; + } } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/SingletonCollectionConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/SingletonCollectionConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/SingletonCollectionConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011, 2014 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 11. October 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.collections; + +import java.util.Collection; +import java.util.Collections; + +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Converts singleton collections (list and set) to XML, specifying a nested element for the item. + *

+ * Supports Collections.singleton(Object) and Collections.singletonList(Object). + *

+ * + * @author Jörg Schaible + * @since 1.4.2 + */ +public class SingletonCollectionConverter extends CollectionConverter { + + private static final Class LIST = Collections.singletonList(Boolean.TRUE).getClass(); + private static final Class SET = Collections.singleton(Boolean.TRUE).getClass(); + + /** + * Construct a SingletonCollectionConverter. + * + * @param mapper the mapper + * @since 1.4.2 + */ + public SingletonCollectionConverter(final Mapper mapper) { + super(mapper); + } + + @Override + public boolean canConvert(final Class type) { + return LIST == type || SET == type; + } + + @Override + public Collection unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + reader.moveDown(); + final Object item = readItem(reader, context, null); + reader.moveUp(); + return context.getRequiredType() == LIST ? Collections.singletonList(item) : Collections.singleton(item); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/SingletonMapConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/SingletonMapConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/SingletonMapConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011, 2014 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 11. October 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.collections; + +import java.util.Collections; +import java.util.Map; + +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Converts a singleton map to XML, specifying an 'entry' element with 'key' and 'value' children. + *

+ * Note: 'key' and 'value' is not the name of the generated tag. The children are serialized as normal elements and the + * implementation expects them in the order 'key'/'value'. + *

+ *

+ * Supports Collections.singletonMap. + *

+ * + * @author Jörg Schaible + * @since 1.4.2 + */ +public class SingletonMapConverter extends MapConverter { + + private static final Class MAP = Collections.singletonMap(Boolean.TRUE, null).getClass(); + + /** + * Construct a SingletonMapConverter. + * + * @param mapper + * @since 1.4.2 + */ + public SingletonMapConverter(final Mapper mapper) { + super(mapper); + } + + @Override + public boolean canConvert(final Class type) { + return MAP == type; + } + + @Override + public Map unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + reader.moveDown(); + reader.moveDown(); + final Object key = readItem(reader, context, null); + reader.moveUp(); + + reader.moveDown(); + final Object value = readItem(reader, context, null); + reader.moveUp(); + reader.moveUp(); + + return Collections.singletonMap(key, value); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java (.../TreeMapConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java (.../TreeMapConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,69 +1,143 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014 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 08. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.collections; -import com.thoughtworks.xstream.alias.ClassMapper; +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.SortedMap; +import java.util.TreeMap; + import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.core.util.Fields; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.core.util.PresortedMap; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; -import java.util.Comparator; -import java.util.TreeMap; /** - * Converts a java.util.TreeMap to XML, and serializes - * the associated java.util.Comparator. - * + * Converts a {@link TreeMap} to XML, and serializes the associated {@link Comparator}. + *

+ * The converter assumes that the entries in the XML are already sorted according the comparator. + *

+ * * @author Joe Walnes + * @author Jörg Schaible */ public class TreeMapConverter extends MapConverter { - /** - * @deprecated As of 1.1.1, use other constructor. - */ - public TreeMapConverter(ClassMapper classMapper, String classAttributeIdentifier) { - super(classMapper, classAttributeIdentifier); + private static final class NullComparator extends Mapper.Null implements Comparator> { + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public int compare(final Comparable o1, final Comparable o2) { + return o1.compareTo(o2); + } } - public TreeMapConverter(Mapper mapper) { - super(mapper); + @SuppressWarnings("rawtypes") + private final static Comparator NULL_MARKER = new NullComparator(); + private final static Field comparatorField = Fields.locate(TreeMap.class, Comparator.class, false); + + public TreeMapConverter(final Mapper mapper) { + super(mapper, TreeMap.class); } - public boolean canConvert(Class type) { - return type.equals(TreeMap.class); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final SortedMap sortedMap = (SortedMap)source; + marshalComparator(sortedMap.comparator(), writer, context); + super.marshal(source, writer, context); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - TreeMap treeMap = (TreeMap) source; - Comparator comparator = treeMap.comparator(); - if (comparator == null) { - writer.startNode("no-comparator"); - writer.endNode(); - } else { + protected void marshalComparator(final Comparator comparator, final HierarchicalStreamWriter writer, + final MarshallingContext context) { + if (comparator != null) { writer.startNode("comparator"); - writer.addAttribute("class", mapper().serializedClass(comparator.getClass())); + writer.addAttribute(mapper().aliasForSystemAttribute("class"), mapper().serializedClass( + comparator.getClass())); context.convertAnother(comparator); writer.endNode(); } - super.marshal(source, writer, context); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - reader.moveDown(); - TreeMap result; - if (reader.getNodeName().equals("comparator")) { - String comparatorClass = reader.getAttribute("class"); - Comparator comparator = (Comparator) context.convertAnother(null, mapper().realClass(comparatorClass)); - result = new TreeMap(comparator); - } else if (reader.getNodeName().equals("no-comparator")) { - result = new TreeMap(); - } else { - throw new ConversionException("TreeMap does not contain element"); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + TreeMap result = comparatorField != null ? new TreeMap() : null; + @SuppressWarnings("unchecked") + final Comparator comparator = (Comparator)unmarshalComparator(reader, context, result); + if (result == null) { + result = comparator == null ? new TreeMap() : new TreeMap(comparator); } - reader.moveUp(); - super.populateMap(reader, context, result); + populateTreeMap(reader, context, result, comparator); return result; } + protected Comparator unmarshalComparator(final HierarchicalStreamReader reader, + final UnmarshallingContext context, final TreeMap result) { + final Comparator comparator; + if (reader.hasMoreChildren()) { + reader.moveDown(); + if (reader.getNodeName().equals("comparator")) { + final Class comparatorClass = HierarchicalStreams.readClassType(reader, mapper()); + comparator = (Comparator)context.convertAnother(result, comparatorClass); + } else if (reader.getNodeName().equals("no-comparator")) { // pre 1.4 format + comparator = null; + } else { + // we are already within the first entry + return NULL_MARKER; + } + reader.moveUp(); + } else { + comparator = null; + } + return comparator; + } + + protected void populateTreeMap(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final TreeMap result, Comparator comparator) { + final boolean inFirstElement = comparator == NULL_MARKER; + if (inFirstElement) { + comparator = null; + } + @SuppressWarnings("unchecked") + final SortedMap sortedMap = new PresortedMap( + (Comparator)(comparator != null && JVM.hasOptimizedTreeMapPutAll() ? comparator : null)); + if (inFirstElement) { + // we are already within the first entry + putCurrentEntryIntoMap(reader, context, result, sortedMap); + reader.moveUp(); + } + populateMap(reader, context, result, sortedMap); + @SuppressWarnings("unchecked") + final TreeMap typedResult = (TreeMap)result; + try { + if (JVM.hasOptimizedTreeMapPutAll()) { + if (comparator != null && comparatorField != null) { + comparatorField.set(result, comparator); + } + typedResult.putAll(sortedMap); // internal optimization will not call comparator + } else if (comparatorField != null) { + comparatorField.set(result, sortedMap.comparator()); + typedResult.putAll(sortedMap); // "sort" by index + comparatorField.set(result, comparator); + } else { + typedResult.putAll(sortedMap); // will use comparator for already sorted map + } + } catch (final IllegalAccessException e) { + throw new ConversionException("Cannot set comparator of TreeMap", e); + } + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java (.../TreeSetConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java (.../TreeSetConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,69 +1,141 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014 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 08. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.collections; -import com.thoughtworks.xstream.alias.ClassMapper; +import java.lang.reflect.Field; +import java.util.AbstractList; +import java.util.Comparator; +import java.util.Map; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.core.util.Fields; +import com.thoughtworks.xstream.core.util.PresortedSet; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; -import java.util.Comparator; -import java.util.TreeSet; /** - * Converts a java.util.TreeSet to XML, and serializes - * the associated java.util.Comparator. - * + * Converts a {@link TreeSet} to XML, and serializes the associated {@link Comparator}. + *

+ * The converter assumes that the elements in the XML are already sorted according the comparator. + *

+ * * @author Joe Walnes + * @author Jörg Schaible */ public class TreeSetConverter extends CollectionConverter { + private transient TreeMapConverter treeMapConverter; + private final static Field sortedMapField = JVM.hasOptimizedTreeSetAddAll() ? Fields.locate(TreeSet.class, + SortedMap.class, false) : null; - /** - * @deprecated As of 1.1.1, use other constructor. - */ - public TreeSetConverter(ClassMapper classMapper, String classAttributeIdentifier) { - super(classMapper, classAttributeIdentifier); + public TreeSetConverter(final Mapper mapper) { + super(mapper, TreeSet.class); + readResolve(); } - public TreeSetConverter(Mapper mapper) { - super(mapper); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final SortedSet sortedSet = (SortedSet)source; + treeMapConverter.marshalComparator(sortedSet.comparator(), writer, context); + super.marshal(source, writer, context); } - public boolean canConvert(Class type) { - return type.equals(TreeSet.class); - } - - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - TreeSet treeSet = (TreeSet) source; - Comparator comparator = treeSet.comparator(); - if (comparator == null) { - writer.startNode("no-comparator"); - writer.endNode(); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + TreeSet result = null; + final TreeMap treeMap; + final Comparator unmarshalledComparator = treeMapConverter.unmarshalComparator(reader, context, null); + final boolean inFirstElement = unmarshalledComparator instanceof Mapper.Null; + @SuppressWarnings("unchecked") + final Comparator comparator = inFirstElement ? null : (Comparator)unmarshalledComparator; + if (sortedMapField != null) { + final TreeSet possibleResult = comparator == null ? new TreeSet() : new TreeSet( + comparator); + Object backingMap = null; + try { + backingMap = sortedMapField.get(possibleResult); + } catch (final IllegalAccessException e) { + throw new ConversionException("Cannot get backing map of TreeSet", e); + } + if (backingMap instanceof TreeMap) { + treeMap = (TreeMap)backingMap; + result = possibleResult; + } else { + treeMap = null; + } } else { - writer.startNode("comparator"); - writer.addAttribute("class", mapper().serializedClass(comparator.getClass())); - context.convertAnother(comparator); - writer.endNode(); + treeMap = null; } - super.marshal(source, writer, context); - } - - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - reader.moveDown(); - TreeSet result; - if (reader.getNodeName().equals("comparator")) { - String comparatorClass = reader.getAttribute("class"); - Comparator comparator = (Comparator) context.convertAnother(null, mapper().realClass(comparatorClass)); - result = new TreeSet(comparator); - } else if (reader.getNodeName().equals("no-comparator")) { - result = new TreeSet(); + if (treeMap == null) { + final PresortedSet set = new PresortedSet(comparator); + result = comparator == null ? new TreeSet() : new TreeSet(comparator); + if (inFirstElement) { + // we are already within the first element + addCurrentElementToCollection(reader, context, result, set); + reader.moveUp(); + } + populateCollection(reader, context, result, set); + if (set.size() > 0) { + result.addAll(set); // comparator will not be called if internally optimized + } } else { - throw new ConversionException("TreeSet does not contain element"); + treeMapConverter.populateTreeMap(reader, context, treeMap, unmarshalledComparator); } - reader.moveUp(); - super.populateCollection(reader, context, result); return result; } + private Object readResolve() { + treeMapConverter = new TreeMapConverter(mapper()) { + + @Override + protected void populateMap(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Map map, final Map target) { + populateCollection(reader, context, new AbstractList() { + @Override + public boolean add(final Object object) { + @SuppressWarnings("unchecked") + final Map collectionTarget = (Map)target; + return collectionTarget.put(object, object) != null; + } + + @Override + public Object get(final int location) { + return null; + } + + @Override + public int size() { + return target.size(); + } + }); + } + + @Override + protected void putCurrentEntryIntoMap(final HierarchicalStreamReader reader, + final UnmarshallingContext context, final Map map, final Map target) { + final Object key = readItem(reader, context, map); + @SuppressWarnings("unchecked") + final Map checkedTarget = (Map)target; + checkedTarget.put(key, key); + } + }; + return this; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/package.html =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/package.html (.../package.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/collections/package.html (.../package.html) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,4 +1,17 @@ -

Converters for collection objects that write their items -as nested elements, such as arrays, Lists, Sets and Maps.

+ + +

Converters for collection objects that write their items as +nested elements, such as arrays, Lists, Sets and Maps.

-

All the converters in this package are enabled by default.

\ No newline at end of file +

All the converters in this package are enabled by default.

+ Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumConverter.java (.../EnumConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumConverter.java (.../EnumConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,3 +1,15 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2013, 2014 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 18. March 2005 by Joe Walnes + */ + // ***** READ THIS ***** // This class will only compile with JDK 1.5.0 or above as it test Java enums. // If you are using an earlier version of Java, just don't try to build this class. XStream should work fine without it. @@ -7,31 +19,55 @@ import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.EnumMapper; + /** - * Converter for JDK 1.5 enums. Combined with EnumMapper this also deals with polymorphic enums. - * - * @author Eric Snell + * Converter for {@link Enum} types. + *

+ * Combined with {@link EnumMapper} this also deals with polymorphic enums. + *

+ * + * @author Eric Snell * @author Bryan Coleman */ public class EnumConverter implements Converter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.isEnum() || Enum.class.isAssignableFrom(type); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - writer.setValue(((Enum) source).name()); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + writer.setValue(((Enum)source).name()); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - Class type = context.getRequiredType(); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + Class type = context.getRequiredType(); if (type.getSuperclass() != Enum.class) { type = type.getSuperclass(); // polymorphic enums } - return Enum.valueOf(type, reader.getValue()); + final String name = reader.getValue(); + try { + @SuppressWarnings("rawtypes") + final Class rawType = type; + @SuppressWarnings("unchecked") + final Enum enumValue = Enum.valueOf(rawType, name); + return enumValue; + } catch (final IllegalArgumentException e) { + // failed to find it, do a case insensitive match + for (final Enum c : (Enum[])type.getEnumConstants()) { + if (c.name().equalsIgnoreCase(name)) { + return c; + } + } + // all else failed + throw e; + } } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java (.../EnumMapConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java (.../EnumMapConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,47 +1,71 @@ -// ***** READ THIS ***** -// This class will only compile with JDK 1.5.0 or above as it test Java enums. -// If you are using an earlier version of Java, just don't try to build this class. XStream should work fine without it. +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014 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 06. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.converters.enums; -import com.thoughtworks.xstream.converters.collections.MapConverter; +import java.lang.reflect.Field; +import java.util.EnumMap; + +import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.mapper.Mapper; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.converters.collections.MapConverter; import com.thoughtworks.xstream.core.util.Fields; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; -import java.util.EnumMap; -import java.lang.reflect.Field; /** - * Serializes an Java 5 EnumMap, including the type of Enum it's for. - * + * Converts an {@link EnumMap}, including the type of Enum it's for. + *

+ * If a {@link SecurityManager} is set, the converter will only work with permissions for SecurityManager.checkPackageAccess, + * SecurityManager.checkMemberAccess(this, EnumSet.MEMBER) and ReflectPermission("suppressAccessChecks"). + *

+ * * @author Joe Walnes */ public class EnumMapConverter extends MapConverter { - private final Field typeField; + private final static Field typeField = Fields.locate(EnumMap.class, Class.class, false); - public EnumMapConverter(Mapper mapper) { + public EnumMapConverter(final Mapper mapper) { super(mapper); - typeField = Fields.find(EnumMap.class, "keyType"); } - public boolean canConvert(Class type) { - return type == EnumMap.class; + @Override + public boolean canConvert(final Class type) { + return typeField != null && type == EnumMap.class; } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - Class type = (Class) Fields.read(typeField, source); - writer.addAttribute(mapper().attributeForEnumType(), mapper().serializedClass(type)); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Class type = (Class)Fields.read(typeField, source); + final String attributeName = mapper().aliasForSystemAttribute("enum-type"); + if (attributeName != null) { + writer.addAttribute(attributeName, mapper().serializedClass(type)); + } super.marshal(source, writer, context); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - Class type = mapper().realClass(reader.getAttribute(mapper().attributeForEnumType())); - EnumMap map = new EnumMap(type); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String attributeName = mapper().aliasForSystemAttribute("enum-type"); + if (attributeName == null) { + throw new ConversionException("No EnumType specified for EnumMap"); + } + final Class type = mapper().realClass(reader.getAttribute(attributeName)); + @SuppressWarnings({"rawtypes", "unchecked"}) + final EnumMap map = new EnumMap(type); populateMap(reader, context, map); return map; } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java (.../EnumSetConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java (.../EnumSetConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,52 +1,69 @@ -// ***** READ THIS ***** -// This class will only compile with JDK 1.5.0 or above as it test Java enums. -// If you are using an earlier version of Java, just don't try to build this class. XStream should work fine without it. +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2014 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 06. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.converters.enums; +import java.lang.reflect.Field; +import java.util.EnumSet; + +import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.util.Fields; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; -import com.thoughtworks.xstream.core.util.Fields; -import java.lang.reflect.Field; -import java.util.EnumSet; -import java.util.Iterator; /** - * Serializes a Java 5 EnumSet. - * + * Converts an {@link EnumSet}. + *

+ * If a SecurityManager is set, the converter will only work with permissions for SecurityManager.checkPackageAccess, + * SecurityManager.checkMemberAccess(this, EnumSet.MEMBER) and ReflectPermission("suppressAccessChecks"). + *

+ * * @author Joe Walnes + * @author Jörg Schaible */ public class EnumSetConverter implements Converter { - private final Field typeField; + private final static Field typeField = Fields.locate(EnumSet.class, Class.class, false); private final Mapper mapper; - public EnumSetConverter(Mapper mapper) { + public EnumSetConverter(final Mapper mapper) { this.mapper = mapper; - typeField = Fields.find(EnumSet.class, "elementType"); } - public boolean canConvert(Class type) { - return EnumSet.class.isAssignableFrom(type); + @Override + public boolean canConvert(final Class type) { + return typeField != null && EnumSet.class.isAssignableFrom(type); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - EnumSet set = (EnumSet) source; - Class enumTypeForSet = (Class) Fields.read(typeField, set); - writer.addAttribute(mapper.attributeForEnumType(), mapper.serializedClass(enumTypeForSet)); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final EnumSet set = (EnumSet)source; + final Class enumTypeForSet = (Class)Fields.read(typeField, set); + final String attributeName = mapper.aliasForSystemAttribute("enum-type"); + if (attributeName != null) { + writer.addAttribute(attributeName, mapper.serializedClass(enumTypeForSet)); + } writer.setValue(joinEnumValues(set)); } - private String joinEnumValues(EnumSet set) { + private String joinEnumValues(final EnumSet set) { boolean seenFirst = false; - StringBuffer result = new StringBuffer(); - for (Iterator iterator = set.iterator(); iterator.hasNext();) { - Enum value = (Enum) iterator.next(); + final StringBuilder result = new StringBuilder(); + for (final Enum value : set) { if (seenFirst) { result.append(','); } else { @@ -57,14 +74,26 @@ return result.toString(); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - Class enumTypeForSet = mapper.realClass(reader.getAttribute(mapper.attributeForEnumType())); - EnumSet set = EnumSet.noneOf(enumTypeForSet); - String[] enumValues = reader.getValue().split(","); - for (int i = 0; i < enumValues.length; i++) { - String enumValue = enumValues[i]; - if(enumValue.length() > 0) { - set.add(Enum.valueOf(enumTypeForSet, enumValue)); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String attributeName = mapper.aliasForSystemAttribute("enum-type"); + if (attributeName == null) { + throw new ConversionException("No EnumType specified for EnumSet"); + } + @SuppressWarnings("rawtypes") + final Class enumTypeForSet = mapper.realClass(reader.getAttribute(attributeName)); + @SuppressWarnings("unchecked") + final EnumSet set = create(enumTypeForSet, reader.getValue()); + return set; + } + + private > EnumSet create(final Class type, final String s) { + final String[] enumValues = s.split(","); + final EnumSet set = EnumSet.noneOf(type); + for (final String enumValue : enumValues) { + if (enumValue.length() > 0) { + final T value = Enum.valueOf(type, enumValue); + set.add(value); } } return set; Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumSingleValueConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumSingleValueConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumSingleValueConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008, 2009, 2010, 2013, 2014 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 12. February 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.enums; + +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + +/** + * A single value converter for a special enum type. Converter is internally automatically instantiated for enum types. + * + * @author Jörg Schaible + * @since 1.3 + */ +public class EnumSingleValueConverter> extends AbstractSingleValueConverter { + + private final Class enumType; + + public EnumSingleValueConverter(final Class type) { + if (!Enum.class.isAssignableFrom(type) && !Enum.class.equals(type)) { + throw new IllegalArgumentException("Converter can only handle defined enums"); + } + enumType = type; + } + + @Override + public boolean canConvert(final Class type) { + return enumType.isAssignableFrom(type); + } + + @Override + public String toString(final Object obj) { + return Enum.class.cast(obj).name(); + } + + @Override + public Object fromString(final String str) { + return Enum.valueOf(enumType, str); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumToStringConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumToStringConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/enums/EnumToStringConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2013, 2014 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 14. March 2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.enums; + +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + +/** + * A single value converter for a special enum type using its string representation. + * + * @author Jörg Schaible + * @since 1.4.5 + */ +public class EnumToStringConverter> extends AbstractSingleValueConverter { + + private final Class enumType; + private final Map strings; + private final EnumMap values; + + public EnumToStringConverter(final Class type) { + this(type, extractStringMap(type), null); + } + + public EnumToStringConverter(final Class type, final Map strings) { + this(type, strings, buildValueMap(type, strings)); + } + + private EnumToStringConverter(final Class type, final Map strings, final EnumMap values) { + enumType = type; + this.strings = strings; + this.values = values; + } + + private static > Map extractStringMap(final Class type) { + checkType(type); + final EnumSet values = EnumSet.allOf(type); + final Map strings = new HashMap(values.size()); + for (final T value : values) { + if (strings.put(value.toString(), value) != null) { + throw new IllegalArgumentException("Enum type " + + type.getName() + + " does not have unique string representations for its values"); + } + } + return strings; + } + + private static void checkType(final Class type) { + if (!Enum.class.isAssignableFrom(type) && type != Enum.class) { + throw new IllegalArgumentException("Converter can only handle enum types"); + } + } + + private static > EnumMap buildValueMap(final Class type, + final Map strings) { + final EnumMap values = new EnumMap(type); + for (final Map.Entry entry : strings.entrySet()) { + values.put(entry.getValue(), entry.getKey()); + } + return values; + } + + @Override + public boolean canConvert(final Class type) { + return enumType.isAssignableFrom(type); + } + + @Override + public String toString(final Object obj) { + return values == null ? obj.toString() : values.get(obj); + } + + @Override + public Object fromString(final String str) { + if (str == null) { + return null; + } + final T result = strings.get(str); + if (result == null) { + throw new ConversionException("Invalid string representation for enum type " + + enumType.getName() + + ": <" + + str + + ">"); + } + return result; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/CharsetConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/CharsetConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/CharsetConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006, 2007, 2014 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 07. April 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.nio.charset.Charset; + +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + +/** + * Converts a {@link Charset} to a string. + * + * @author Jörg Schaible + * @since 1.2 + */ +public class CharsetConverter extends AbstractSingleValueConverter { + + @Override + public boolean canConvert(final Class type) { + return Charset.class.isAssignableFrom(type); + } + + @Override + public String toString(final Object obj) { + return ((Charset)obj).name(); + } + + @Override + public Object fromString(final String str) { + return Charset.forName(str); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ColorConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ColorConverter.java (.../ColorConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ColorConverter.java (.../ColorConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,54 +1,67 @@ +/* + * Copyright (C) 2003, 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 01. October 2003 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; +import java.awt.Color; +import java.util.HashMap; +import java.util.Map; + import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import java.awt.*; -import java.util.HashMap; -import java.util.Map; /** - * Converts a java.awt.Color to XML, using four nested elements: - * red, green, blue, alpha. - * + * Converts an AWT {@link Color}, using four nested elements: red, green, blue, alpha. + * * @author Joe Walnes */ public class ColorConverter implements Converter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { // String comparison is used here because Color.class loads the class which in turns instantiates AWT, // which is nasty if you don't want it. return type.getName().equals("java.awt.Color"); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - Color color = (Color) source; + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Color color = (Color)source; write("red", color.getRed(), writer); write("green", color.getGreen(), writer); write("blue", color.getBlue(), writer); write("alpha", color.getAlpha(), writer); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - Map elements = new HashMap(); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Map elements = new HashMap(); while (reader.hasMoreChildren()) { reader.moveDown(); elements.put(reader.getNodeName(), Integer.valueOf(reader.getValue())); reader.moveUp(); } - return new Color(((Integer) elements.get("red")).intValue(), - ((Integer) elements.get("green")).intValue(), - ((Integer) elements.get("blue")).intValue(), - ((Integer) elements.get("alpha")).intValue()); + return new Color(elements.get("red").intValue(), elements.get("green").intValue(), elements + .get("blue") + .intValue(), elements.get("alpha").intValue()); } - private void write(String fieldName, int value, HierarchicalStreamWriter writer) { - writer.startNode(fieldName); + private void write(final String fieldName, final int value, final HierarchicalStreamWriter writer) { + ExtendedHierarchicalStreamWriterHelper.startNode(writer, fieldName, int.class); writer.setValue(String.valueOf(value)); writer.endNode(); } - } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/CurrencyConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/CurrencyConverter.java (.../CurrencyConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/CurrencyConverter.java (.../CurrencyConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,25 +1,40 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 24. July 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; - -import java.sql.Date; import java.util.Currency; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + /** - * Converts a java.util.Currency to String. Despite the name of this class, it has nothing to do with converting - * currencies between exchange rates! It makes sense in the context of XStream. - * - * @author Jose A. Illescas + * Converts a {@link Currency} to a string. + *

+ * Despite the name of this class, it has nothing to do with converting currencies between exchange rates! It makes + * sense in the context of XStream. + *

+ * + * @author Jose A. Illescas * @author Joe Walnes */ -public class CurrencyConverter extends AbstractBasicConverter { +public class CurrencyConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(Currency.class); } - protected Object fromString(String str) { + @Override + public Object fromString(final String str) { return Currency.getInstance(str); } - } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/DurationConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/DurationConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/DurationConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007, 2008, 2011, 2014 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 21.09.2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.Duration; + +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + +/** + * A Converter for the XML Schema datatype duration and the + * Java type {@link Duration}. + *

+ * The implementation uses a {@link DatatypeFactory} to create Duration objects. If no factory is provided and the + * instantiation of the internal factory fails with a {@link DatatypeConfigurationException} , the converter will not + * claim the responsibility for Duration objects. + *

+ * + * @author John Kristian + * @author Jörg Schaible + * @since 1.3 + */ +public class DurationConverter extends AbstractSingleValueConverter { + private final DatatypeFactory factory; + + public DurationConverter() { + this(new Object() { + DatatypeFactory getFactory() { + try { + return DatatypeFactory.newInstance(); + } catch (final DatatypeConfigurationException e) { + return null; + } + } + }.getFactory()); + } + + public DurationConverter(final DatatypeFactory factory) { + this.factory = factory; + } + + @Override + public boolean canConvert(final Class c) { + return factory != null && Duration.class.isAssignableFrom(c); + } + + @Override + public Object fromString(final String s) { + return factory.newDuration(s); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java (.../DynamicProxyConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java (.../DynamicProxyConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,81 +1,142 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2010, 2013, 2014 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 25. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.List; + import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.ClassLoaderReference; +import com.thoughtworks.xstream.core.util.Fields; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.DynamicProxyMapper; import com.thoughtworks.xstream.mapper.Mapper; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.List; /** - * Converts a dynamic proxy to XML, storing the implemented - * interfaces and handler. - * + * Converts a dynamic proxy to XML, storing the implemented interfaces and handler. + * * @author Joe Walnes */ public class DynamicProxyConverter implements Converter { - private ClassLoader classLoader; - private Mapper mapper; + private final ClassLoaderReference classLoaderReference; + private final Mapper mapper; + private static final Field HANDLER = Fields.locate(Proxy.class, InvocationHandler.class, false); + private static final InvocationHandler DUMMY = new InvocationHandler() { + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { + return null; + } + }; - public DynamicProxyConverter(Mapper mapper) { + /** + * @deprecated As of 1.4.5 use {@link #DynamicProxyConverter(Mapper, ClassLoaderReference)} + */ + @Deprecated + public DynamicProxyConverter(final Mapper mapper) { this(mapper, DynamicProxyConverter.class.getClassLoader()); } - public DynamicProxyConverter(Mapper mapper, ClassLoader classLoader) { - this.classLoader = classLoader; + /** + * Construct a DynamicProxyConverter. + * + * @param mapper the Mapper chain + * @param classLoaderReference the reference to the {@link ClassLoader} of the XStream instance + * @since 1.4.5 + */ + public DynamicProxyConverter(final Mapper mapper, final ClassLoaderReference classLoaderReference) { + this.classLoaderReference = classLoaderReference; this.mapper = mapper; } - public boolean canConvert(Class type) { + /** + * @deprecated As of 1.4.5 use {@link #DynamicProxyConverter(Mapper, ClassLoaderReference)} + */ + @Deprecated + public DynamicProxyConverter(final Mapper mapper, final ClassLoader classLoader) { + this(mapper, new ClassLoaderReference(classLoader)); + } + + @Override + public boolean canConvert(final Class type) { return type.equals(DynamicProxyMapper.DynamicProxy.class) || Proxy.isProxyClass(type); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - InvocationHandler invocationHandler = Proxy.getInvocationHandler(source); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final InvocationHandler invocationHandler = Proxy.getInvocationHandler(source); addInterfacesToXml(source, writer); writer.startNode("handler"); - writer.addAttribute("class", mapper.serializedClass(invocationHandler.getClass())); + final String attributeName = mapper.aliasForSystemAttribute("class"); + if (attributeName != null) { + writer.addAttribute(attributeName, mapper.serializedClass(invocationHandler.getClass())); + } context.convertAnother(invocationHandler); writer.endNode(); } - private void addInterfacesToXml(Object source, HierarchicalStreamWriter writer) { - Class[] interfaces = source.getClass().getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - Class currentInterface = interfaces[i]; + private void addInterfacesToXml(final Object source, final HierarchicalStreamWriter writer) { + final Class[] interfaces = source.getClass().getInterfaces(); + for (final Class currentInterface : interfaces) { writer.startNode("interface"); writer.setValue(mapper.serializedClass(currentInterface)); writer.endNode(); } } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - List interfaces = new ArrayList(); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final List> interfaces = new ArrayList>(); InvocationHandler handler = null; + Class handlerType = null; while (reader.hasMoreChildren()) { reader.moveDown(); - String elementName = reader.getNodeName(); + final String elementName = reader.getNodeName(); if (elementName.equals("interface")) { interfaces.add(mapper.realClass(reader.getValue())); } else if (elementName.equals("handler")) { - Class handlerType = mapper.realClass(reader.getAttribute("class")); - handler = (InvocationHandler) context.convertAnother(null, handlerType); + final String attributeName = mapper.aliasForSystemAttribute("class"); + if (attributeName != null) { + handlerType = mapper.realClass(reader.getAttribute(attributeName)); + break; + } } reader.moveUp(); } - if (handler == null) { + if (handlerType == null) { throw new ConversionException("No InvocationHandler specified for dynamic proxy"); } - Class[] interfacesAsArray = new Class[interfaces.size()]; + final Class[] interfacesAsArray = new Class[interfaces.size()]; interfaces.toArray(interfacesAsArray); - return Proxy.newProxyInstance(classLoader, interfacesAsArray, handler); + Object proxy = null; + if (HANDLER != null) { // we will not be able to resolve references to the proxy + proxy = Proxy.newProxyInstance(classLoaderReference.getReference(), interfacesAsArray, DUMMY); + } + handler = (InvocationHandler)context.convertAnother(proxy, handlerType); + reader.moveUp(); + if (HANDLER != null) { + Fields.write(HANDLER, proxy, handler); + } else { + proxy = Proxy.newProxyInstance(classLoaderReference.getReference(), interfacesAsArray, handler); + } + return proxy; } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverter.java (.../EncodedByteArrayConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverter.java (.../EncodedByteArrayConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,63 +1,87 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2010, 2014 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 03. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; +import java.util.ArrayList; +import java.util.List; + import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.basic.ByteConverter; import com.thoughtworks.xstream.core.util.Base64Encoder; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; /** * Converts a byte array to a single Base64 encoding string. - * + * * @author Joe Walnes + * @author Jörg Schaible */ -public class EncodedByteArrayConverter implements Converter { +public class EncodedByteArrayConverter implements Converter, SingleValueConverter { - private final Base64Encoder base64 = new Base64Encoder(); - private final ByteConverter byteConverter = new ByteConverter(); + private static final Base64Encoder base64 = new Base64Encoder(); + private static final ByteConverter byteConverter = new ByteConverter(); - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.isArray() && type.getComponentType().equals(byte.class); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - writer.setValue(base64.encode((byte[]) source)); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + writer.setValue(toString(source)); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - String data = reader.getValue(); // needs to be called before hasMoreChildren. + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String data = reader.getValue(); // needs to be called before hasMoreChildren. if (!reader.hasMoreChildren()) { - return base64.decode(data); + return fromString(data); } else { - // backwards compatability ... try to unmarshal byte arrays that haven't been encoded + // backwards compatibility ... try to unmarshal byte arrays that haven't been encoded return unmarshalIndividualByteElements(reader, context); } } - private Object unmarshalIndividualByteElements(HierarchicalStreamReader reader, UnmarshallingContext context) { - List bytes = new ArrayList(); // have to create a temporary list because don't know the size of the array + private Object unmarshalIndividualByteElements(final HierarchicalStreamReader reader, + final UnmarshallingContext context) { + // have to create a temporary list because we don't know the size of the array + final List bytes = new ArrayList(); boolean firstIteration = true; while (firstIteration || reader.hasMoreChildren()) { // hangover from previous hasMoreChildren reader.moveDown(); - bytes.add(byteConverter.unmarshal(reader, context)); + bytes.add((Byte)byteConverter.fromString(reader.getValue())); reader.moveUp(); firstIteration = false; } // copy into real array - byte[] result = new byte[bytes.size()]; - int i = 0; - for (Iterator iterator = bytes.iterator(); iterator.hasNext();) { - Byte b = (Byte) iterator.next(); - result[i] = b.byteValue(); - i++; + final byte[] result = new byte[bytes.size()]; + for (int i = 0; i < result.length; ++i) { + result[i] = bytes.get(i).byteValue(); } return result; } + @Override + public String toString(final Object obj) { + return base64.encode((byte[])obj); + } + + @Override + public Object fromString(final String str) { + return base64.decode(str); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FileConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FileConverter.java (.../FileConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FileConverter.java (.../FileConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,27 +1,44 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 13. January 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; - import java.io.File; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + /** - * This converter will take care of storing and retrieving File with either - * an absolute path OR a relative path depending on how they were created. - * + * Converts a {@link File}. + * + *

This converter will take care of storing and retrieving {@link File} with either an absolute path OR a relative path + * depending on how they were created.

+ * * @author Joe Walnes */ -public class FileConverter extends AbstractBasicConverter { +public class FileConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(File.class); } - protected Object fromString(String str) { + @Override + public Object fromString(final String str) { return new File(str); } - protected String toString(Object obj) { - return ((File) obj).getPath(); + @Override + public String toString(final Object obj) { + return ((File)obj).getPath(); } -} \ No newline at end of file +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FontConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FontConverter.java (.../FontConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/FontConverter.java (.../FontConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,36 +1,134 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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 08. July 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; +import java.awt.Font; +import java.awt.font.TextAttribute; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.swing.plaf.FontUIResource; + import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; -import javax.swing.plaf.FontUIResource; -import java.awt.*; -import java.util.Map; +/** + * Converts an AWT {@link Font}. + */ public class FontConverter implements Converter { - public boolean canConvert(Class type) { + private final SingleValueConverter textAttributeConverter; + private final Mapper mapper; + + /** + * Constructs a FontConverter. + * + * @deprecated As of 1.4.5 + */ + @Deprecated + public FontConverter() { + this(null); + } + + /** + * Constructs a FontConverter. + * + * @param mapper + * @since 1.4.5 + */ + public FontConverter(final Mapper mapper) { + this.mapper = mapper; + if (mapper == null) { + textAttributeConverter = null; + } else { + textAttributeConverter = new TextAttributeConverter(); + } + } + + @Override + public boolean canConvert(final Class type) { // String comparison is used here because Font.class loads the class which in turns instantiates AWT, // which is nasty if you don't want it. return type.getName().equals("java.awt.Font") || type.getName().equals("javax.swing.plaf.FontUIResource"); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - Font font = (Font) source; - Map attributes = font.getAttributes(); - writer.startNode("attributes"); // - context.convertAnother(attributes); - writer.endNode(); // + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Font font = (Font)source; + final Map attributes = font.getAttributes(); + if (mapper != null) { + final String classAlias = mapper.aliasForSystemAttribute("class"); + for (final Map.Entry entry : attributes.entrySet()) { + final String name = textAttributeConverter.toString(entry.getKey()); + final Object value = entry.getValue(); + final Class type = value != null ? value.getClass() : Mapper.Null.class; + ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, type); + writer.addAttribute(classAlias, mapper.serializedClass(type)); + if (value != null) { + context.convertAnother(value); + } + writer.endNode(); + } + } else { + writer.startNode("attributes"); // + context.convertAnother(attributes); + writer.endNode(); // + } } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - reader.moveDown(); // into - Map attributes = (Map) context.convertAnother(null, Map.class); - reader.moveUp(); // out of - Font font = Font.getFont(attributes); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Map attributes; + if (reader.hasMoreChildren()) { + reader.moveDown(); + if (!reader.getNodeName().equals("attributes")) { + final String classAlias = mapper.aliasForSystemAttribute("class"); + attributes = new HashMap(); + do { + if (!attributes.isEmpty()) { + reader.moveDown(); + } + final Class type = mapper.realClass(reader.getAttribute(classAlias)); + final TextAttribute attribute = (TextAttribute)textAttributeConverter.fromString(reader.getNodeName()); + final Object value = type == Mapper.Null.class ? null : context.convertAnother(null, type); + attributes.put(attribute, value); + reader.moveUp(); + } while (reader.hasMoreChildren()); + } else { + // in + @SuppressWarnings("unchecked") + final Map typedAttributes = (Map)context.convertAnother( + null, Map.class); + attributes = typedAttributes; + reader.moveUp(); // out of + } + } else { + attributes = Collections.emptyMap(); + } + for (final Iterator iter = attributes.values().iterator(); iter.hasNext();) { + if (iter.next() == null) { + iter.remove(); + } + } + final Font font = Font.getFont(attributes); if (context.getRequiredType() == FontUIResource.class) { return new FontUIResource(font); } else { Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverter.java (.../GregorianCalendarConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverter.java (.../GregorianCalendarConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,42 +1,60 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2014 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 24. July 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; -import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + /** - * Converts a java.util.GregorianCalendar to XML. Note that although it currently only contains one field, it nests - * it inside a child element, to allow for other fields to be stored in the future. - * + * Converts a {@link GregorianCalendar}. + *

+ * Note that although it currently only contains one field, it nests it inside a child element, to allow for other + * fields to be stored in the future. + *

+ * * @author Joe Walnes * @author Jörg Schaible */ public class GregorianCalendarConverter implements Converter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(GregorianCalendar.class); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - GregorianCalendar calendar = (GregorianCalendar) source; - writer.startNode("time"); - long timeInMillis = calendar.getTime().getTime(); // calendar.getTimeInMillis() not available under JDK 1.3 + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final GregorianCalendar calendar = (GregorianCalendar)source; + ExtendedHierarchicalStreamWriterHelper.startNode(writer, "time", long.class); + final long timeInMillis = calendar.getTimeInMillis(); writer.setValue(String.valueOf(timeInMillis)); writer.endNode(); - writer.startNode("timezone"); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, "timezone", String.class); writer.setValue(calendar.getTimeZone().getID()); writer.endNode(); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { reader.moveDown(); - long timeInMillis = Long.parseLong(reader.getValue()); + final long timeInMillis = Long.parseLong(reader.getValue()); reader.moveUp(); final String timeZone; if (reader.hasMoreChildren()) { @@ -47,9 +65,9 @@ timeZone = TimeZone.getDefault().getID(); } - GregorianCalendar result = new GregorianCalendar(); + final GregorianCalendar result = new GregorianCalendar(); result.setTimeZone(TimeZone.getTimeZone(timeZone)); - result.setTime(new Date(timeInMillis)); // calendar.setTimeInMillis() not available under JDK 1.3 + result.setTimeInMillis(timeInMillis); return result; } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601DateConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601DateConverter.java (.../ISO8601DateConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601DateConverter.java (.../ISO8601DateConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,29 +1,47 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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 22. November 2004 by Mauro Talevi + */ package com.thoughtworks.xstream.converters.extended; import java.util.Calendar; import java.util.Date; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + /** - * A DateConverter conforming to the ISO8601 standard. - * http://www.iso.ch/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780 + * A converter for {@link Date} conforming to the ISO8601 standard. * + * @see ISO 8601 * @author Mauro Talevi * @author Jörg Schaible */ -public class ISO8601DateConverter extends ISO8601GregorianCalendarConverter { +public class ISO8601DateConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + private final ISO8601GregorianCalendarConverter converter = new ISO8601GregorianCalendarConverter(); + + @Override + public boolean canConvert(final Class type) { return type.equals(Date.class); } - protected Object fromString(String str) { - return ((Calendar)super.fromString(str)).getTime(); + @Override + public Object fromString(final String str) { + return ((Calendar)converter.fromString(str)).getTime(); } - protected String toString(Object obj) { - Calendar calendar = Calendar.getInstance(); + @Override + public String toString(final Object obj) { + final Calendar calendar = Calendar.getInstance(); calendar.setTime((Date)obj); - return super.toString(calendar); + return converter.toString(calendar); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter.java (.../ISO8601GregorianCalendarConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter.java (.../ISO8601GregorianCalendarConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,104 +1,123 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2011, 2013, 2014 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 03. October 2005 by Joerg Schaible + */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.TimeZone; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.Locale; -import java.util.TimeZone; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; /** - * A GregorianCalendarConverter conforming to the ISO8601 standard. - * http://www.iso.ch/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780 + * A converter for {@link GregorianCalendar} conforming to the ISO8601 standard. + *

+ * The converter will always serialize the calendar value in UTC and deserialize it to a value in the current default + * time zone. + *

* * @author Mauro Talevi * @author Jörg Schaible + * @see ISO 8601 + * @since 1.1.3 */ -public class ISO8601GregorianCalendarConverter extends AbstractBasicConverter { - private static final DateTimeFormatter[] formattersUTC = new DateTimeFormatter[]{ - ISODateTimeFormat.dateTime(), - ISODateTimeFormat.dateTimeNoMillis(), - ISODateTimeFormat.basicDateTime(), - ISODateTimeFormat.basicOrdinalDateTime(), - ISODateTimeFormat.basicOrdinalDateTimeNoMillis(), - ISODateTimeFormat.basicTime(), - ISODateTimeFormat.basicTimeNoMillis(), - ISODateTimeFormat.basicTTime(), - ISODateTimeFormat.basicTTimeNoMillis(), - ISODateTimeFormat.basicWeekDateTime(), - ISODateTimeFormat.basicWeekDateTimeNoMillis(), - ISODateTimeFormat.ordinalDateTime(), - ISODateTimeFormat.ordinalDateTimeNoMillis(), - ISODateTimeFormat.time(), - ISODateTimeFormat.timeNoMillis(), - ISODateTimeFormat.tTime(), - ISODateTimeFormat.tTimeNoMillis(), - ISODateTimeFormat.weekDateTime(), - ISODateTimeFormat.weekDateTimeNoMillis(),}; - private static final DateTimeFormatter[] formattersNoUTC = new DateTimeFormatter[]{ - ISODateTimeFormat.basicDate(), - ISODateTimeFormat.basicOrdinalDate(), - ISODateTimeFormat.basicWeekDate(), - ISODateTimeFormat.date(), - ISODateTimeFormat.dateHour(), - ISODateTimeFormat.dateHourMinute(), - ISODateTimeFormat.dateHourMinuteSecond(), - ISODateTimeFormat.dateHourMinuteSecondFraction(), - ISODateTimeFormat.dateHourMinuteSecondMillis(), - ISODateTimeFormat.hour(), - ISODateTimeFormat.hourMinute(), - ISODateTimeFormat.hourMinuteSecond(), - ISODateTimeFormat.hourMinuteSecondFraction(), - ISODateTimeFormat.hourMinuteSecondMillis(), - ISODateTimeFormat.ordinalDate(), - ISODateTimeFormat.weekDate(), - ISODateTimeFormat.year(), - ISODateTimeFormat.yearMonth(), - ISODateTimeFormat.yearMonthDay(), - ISODateTimeFormat.weekyear(), - ISODateTimeFormat.weekyearWeek(), - ISODateTimeFormat.weekyearWeekDay(),}; +public class ISO8601GregorianCalendarConverter extends AbstractSingleValueConverter { + private static final DateTimeFormatter[] formattersUTC = new DateTimeFormatter[]{ // + ISODateTimeFormat.dateTime(), // + ISODateTimeFormat.dateTimeNoMillis(), // + ISODateTimeFormat.basicDateTime(), // + ISODateTimeFormat.basicOrdinalDateTime(), // + ISODateTimeFormat.basicOrdinalDateTimeNoMillis(), // + ISODateTimeFormat.basicTime(), // + ISODateTimeFormat.basicTimeNoMillis(), // + ISODateTimeFormat.basicTTime(), // + ISODateTimeFormat.basicTTimeNoMillis(), // + ISODateTimeFormat.basicWeekDateTime(), // + ISODateTimeFormat.basicWeekDateTimeNoMillis(), // + ISODateTimeFormat.ordinalDateTime(), // + ISODateTimeFormat.ordinalDateTimeNoMillis(), // + ISODateTimeFormat.time(), // + ISODateTimeFormat.timeNoMillis(), // + ISODateTimeFormat.tTime(), // + ISODateTimeFormat.tTimeNoMillis(), // + ISODateTimeFormat.weekDateTime(), // + ISODateTimeFormat.weekDateTimeNoMillis() // + }; + private static final DateTimeFormatter[] formattersNoUTC = new DateTimeFormatter[]{ // + ISODateTimeFormat.basicDate(), // + ISODateTimeFormat.basicOrdinalDate(), // + ISODateTimeFormat.basicWeekDate(), // + ISODateTimeFormat.date(), // + ISODateTimeFormat.dateHour(), // + ISODateTimeFormat.dateHourMinute(), // + ISODateTimeFormat.dateHourMinuteSecond(), // + ISODateTimeFormat.dateHourMinuteSecondFraction(), // + ISODateTimeFormat.dateHourMinuteSecondMillis(), // + ISODateTimeFormat.hour(), // + ISODateTimeFormat.hourMinute(), // + ISODateTimeFormat.hourMinuteSecond(), // + ISODateTimeFormat.hourMinuteSecondFraction(), // + ISODateTimeFormat.hourMinuteSecondMillis(), // + ISODateTimeFormat.ordinalDate(), // + ISODateTimeFormat.weekDate(), // + ISODateTimeFormat.year(), // + ISODateTimeFormat.yearMonth(), // + ISODateTimeFormat.yearMonthDay(), // + ISODateTimeFormat.weekyear(), // + ISODateTimeFormat.weekyearWeek(), // + ISODateTimeFormat.weekyearWeekDay() // + }; - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(GregorianCalendar.class); } - protected Object fromString(String str) { - for (int i = 0; i < formattersUTC.length; i++) { - DateTimeFormatter formatter = formattersUTC[i]; + @Override + public Object fromString(final String str) { + for (final DateTimeFormatter formatter : formattersUTC) { try { - DateTime dt = formatter.parseDateTime(str); - Calendar calendar = dt.toCalendar(Locale.getDefault()); + final DateTime dt = formatter.parseDateTime(str); + final Calendar calendar = dt.toGregorianCalendar(); calendar.setTimeZone(TimeZone.getDefault()); return calendar; - } catch (IllegalArgumentException e) { + } catch (final IllegalArgumentException e) { // try with next formatter } } - String timeZoneID = TimeZone.getDefault().getID(); - for (int i = 0; i < formattersNoUTC.length; i++) { + final String timeZoneID = TimeZone.getDefault().getID(); + for (final DateTimeFormatter element : formattersNoUTC) { try { - DateTimeFormatter formatter = formattersNoUTC[i].withZone(DateTimeZone.forID(timeZoneID)); - DateTime dt = formatter.parseDateTime(str); - Calendar calendar = dt.toCalendar(Locale.getDefault()); + final DateTimeFormatter formatter = element.withZone(DateTimeZone.forID(timeZoneID)); + final DateTime dt = formatter.parseDateTime(str); + final Calendar calendar = dt.toGregorianCalendar(); calendar.setTimeZone(TimeZone.getDefault()); return calendar; - } catch (IllegalArgumentException e) { + } catch (final IllegalArgumentException e) { // try with next formatter } } throw new ConversionException("Cannot parse date " + str); } - protected String toString(Object obj) { - DateTime dt = new DateTime(obj); + @Override + public String toString(final Object obj) { + final DateTime dt = new DateTime(obj); return dt.toString(formattersUTC[0]); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverter.java (.../ISO8601SqlTimestampConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverter.java (.../ISO8601SqlTimestampConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,31 +1,45 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 03. October 2005 by Joerg Schaible + */ package com.thoughtworks.xstream.converters.extended; import java.sql.Timestamp; import java.util.Date; /** - * A SqlTimestampConverter conforming to the ISO8601 standard. - * http://www.iso.ch/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780 + * A converter for {@link Timestamp} conforming to the ISO8601 standard. * + * @see ISO 8601 * @author Jörg Schaible - * @since 1.2 + * @since 1.1.3 */ public class ISO8601SqlTimestampConverter extends ISO8601DateConverter { - final static String PADDING = "000000000"; + private final static String PADDING = "000000000"; - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(Timestamp.class); } - protected Object fromString(String str) { + @Override + public Object fromString(String str) { final int idxFraction = str.lastIndexOf('.'); int nanos = 0; if (idxFraction > 0) { int idx; - for (idx = idxFraction + 1; Character.isDigit(str.charAt(idx)); ++idx) + for (idx = idxFraction + 1; Character.isDigit(str.charAt(idx)); ++idx) { ; + } nanos = Integer.parseInt(str.substring(idxFraction + 1, idx)); str = str.substring(0, idxFraction) + str.substring(idx); } @@ -35,15 +49,16 @@ return timestamp; } - protected String toString(Object obj) { + @Override + public String toString(final Object obj) { final Timestamp timestamp = (Timestamp)obj; - String str = super.toString(new Date((timestamp.getTime() / 1000) * 1000)); + String str = super.toString(new Date(timestamp.getTime() / 1000 * 1000)); final String nanos = String.valueOf(timestamp.getNanos()); final int idxFraction = str.lastIndexOf('.'); str = str.substring(0, idxFraction + 1) - + PADDING.substring(nanos.length()) - + nanos - + str.substring(idxFraction + 4); + + PADDING.substring(nanos.length()) + + nanos + + str.substring(idxFraction + 4); return str; } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaClassConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaClassConverter.java (.../JavaClassConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaClassConverter.java (.../JavaClassConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,54 +1,81 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2014 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 04. April 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; +import com.thoughtworks.xstream.core.ClassLoaderReference; +import com.thoughtworks.xstream.mapper.CannotResolveClassException; +import com.thoughtworks.xstream.mapper.DefaultMapper; +import com.thoughtworks.xstream.mapper.Mapper; + /** - * Converts a java.lang.Class to XML. + * Converts a {@link Class} to a string. * * @author Aslak Hellesøy * @author Joe Walnes * @author Matthew Sandoz + * @author Jörg Schaible */ -public class JavaClassConverter extends AbstractBasicConverter { +public class JavaClassConverter extends AbstractSingleValueConverter { - private ClassLoader classLoader; + private final Mapper mapper; /** - * @deprecated As of 1.1.1 - use other constructor and explicitly supply a ClassLoader. + * Construct a JavaClassConverter. + * + * @param classLoaderReference the reference to the {@link ClassLoader} of the XStream instance + * @since 1.4.5 */ - public JavaClassConverter() { - this(Thread.currentThread().getContextClassLoader()); + public JavaClassConverter(final ClassLoaderReference classLoaderReference) { + this(new DefaultMapper(classLoaderReference)); } - public JavaClassConverter(ClassLoader classLoader) { - this.classLoader = classLoader; + /** + * @deprecated As of 1.4.5 use {@link #JavaClassConverter(ClassLoaderReference)} + */ + @Deprecated + public JavaClassConverter(final ClassLoader classLoader) { + this(new ClassLoaderReference(classLoader)); } - public boolean canConvert(Class clazz) { + /** + * Construct a JavaClassConverter that uses a provided mapper. Depending on the mapper chain it will not only be + * used to load classes, but also to support type aliases. + * + * @param mapper to use + * @since 1.4.5 + */ + protected JavaClassConverter(final Mapper mapper) { + this.mapper = mapper; + } + + @Override + public boolean canConvert(final Class clazz) { return Class.class.equals(clazz); // :) } - protected String toString(Object obj) { - return ((Class) obj).getName(); + @Override + public String toString(final Object obj) { + return mapper.serializedClass((Class)obj); } - protected Object fromString(String str) { + @Override + public Object fromString(final String str) { try { - return - str.equals("void") ? void.class : - str.equals("byte") ? byte.class : - str.equals("int") ? int.class : - str.equals("long") ? long.class : - str.equals("float") ? float.class : - str.equals("boolean") ? boolean.class : - str.equals("double") ? double.class : - str.equals("char") ? char.class : - str.equals("short") ? short.class : - Class.forName(str, false, classLoader); - } catch (ClassNotFoundException e) { - throw new ConversionException("Cannot load java class " + str, e); + return mapper.realClass(str); + } catch (final CannotResolveClassException e) { + throw new ConversionException("Cannot load java class " + str, e.getCause()); } } - } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaFieldConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaFieldConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaFieldConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2009, 2013, 2014 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 17. April 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.lang.reflect.Field; + +import com.thoughtworks.xstream.InitializationException; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.ClassLoaderReference; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.DefaultMapper; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Converts a {@link Field}. + * + * @author Jörg Schaible + */ +public class JavaFieldConverter implements Converter { + + private final SingleValueConverter javaClassConverter; + private final Mapper mapper; + + /** + * Construct a JavaFieldConverter. + * + * @param classLoaderReference the reference to the {@link ClassLoader} of the XStream instance + * @since 1.4.5 + */ + public JavaFieldConverter(final ClassLoaderReference classLoaderReference) { + this(new JavaClassConverter(classLoaderReference), new DefaultMapper(classLoaderReference)); + } + + /** + * @deprecated As of 1.4.5 use {@link #JavaFieldConverter(ClassLoaderReference)} + */ + @Deprecated + public JavaFieldConverter(final ClassLoader classLoader) { + this(new ClassLoaderReference(classLoader)); + } + + /** + * Construct a JavaFieldConverter. Depending on the mapper chain the converter will also respect aliases. + * + * @param javaClassConverter the converter to use + * @param mapper to use + * @since 1.4.5 + */ + protected JavaFieldConverter(final SingleValueConverter javaClassConverter, final Mapper mapper) { + if (!javaClassConverter.canConvert(Class.class)) { + throw new InitializationException("Java Class Converter cannot handle Class types"); + } + this.javaClassConverter = javaClassConverter; + this.mapper = mapper; + } + + @Override + public boolean canConvert(final Class type) { + return type.equals(Field.class); + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Field field = (Field)source; + final Class type = field.getDeclaringClass(); + + writer.startNode("name"); + writer.setValue(mapper.serializedMember(type, field.getName())); + writer.endNode(); + + writer.startNode("clazz"); + writer.setValue(javaClassConverter.toString(type)); + writer.endNode(); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + String methodName = null; + String declaringClassName = null; + + while ((methodName == null || declaringClassName == null) && reader.hasMoreChildren()) { + reader.moveDown(); + + if (reader.getNodeName().equals("name")) { + methodName = reader.getValue(); + } else if (reader.getNodeName().equals("clazz")) { + declaringClassName = reader.getValue(); + } + reader.moveUp(); + } + + final Class declaringClass = (Class)javaClassConverter.fromString(declaringClassName); + try { + return declaringClass.getDeclaredField(mapper.realMember(declaringClass, methodName)); + } catch (final NoSuchFieldException e) { + throw new ConversionException(e); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java (.../JavaMethodConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java (.../JavaMethodConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,51 +1,93 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2013, 2014 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 04. April 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import com.thoughtworks.xstream.InitializationException; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.ClassLoaderReference; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; /** - * Converts a java.lang.reflect.Method to XML. - * + * Converts a {@link Method}. + * * @author Aslak Hellesøy + * @author Jörg Schaible */ public class JavaMethodConverter implements Converter { - private final ClassLoader classLoader; + private final SingleValueConverter javaClassConverter; - public JavaMethodConverter() { - this(JavaMethodConverter.class.getClassLoader()); + /** + * Construct a JavaMethodConverter. + * + * @param classLoaderReference the reference to the {@link ClassLoader} of the XStream instance + * @since 1.4.5 + */ + public JavaMethodConverter(final ClassLoaderReference classLoaderReference) { + this(new JavaClassConverter(classLoaderReference)); } - public JavaMethodConverter(ClassLoader classLoader) { - this.classLoader = classLoader; + /** + * @deprecated As of 1.4.5 use {@link #JavaMethodConverter(ClassLoaderReference)} + */ + @Deprecated + public JavaMethodConverter(final ClassLoader classLoader) { + this(new ClassLoaderReference(classLoader)); } - public boolean canConvert(Class type) { + /** + * Construct a JavaMethodConverter. + * + * @param javaClassConverter the converter to use + * @since 1.4.5 + */ + protected JavaMethodConverter(final SingleValueConverter javaClassConverter) { + if (!javaClassConverter.canConvert(Class.class)) { + throw new InitializationException("Java Class Converter cannot handle Class types"); + } + this.javaClassConverter = javaClassConverter; + } + + @Override + public boolean canConvert(final Class type) { return type.equals(Method.class) || type.equals(Constructor.class); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { if (source instanceof Method) { - Method method = (Method) source; - String declaringClassName = method.getDeclaringClass().getName(); + final Method method = (Method)source; + final String declaringClassName = javaClassConverter.toString(method.getDeclaringClass()); marshalMethod(writer, declaringClassName, method.getName(), method.getParameterTypes()); } else { - Constructor method = (Constructor) source; - String declaringClassName = method.getDeclaringClass().getName(); + final Constructor method = (Constructor)source; + final String declaringClassName = javaClassConverter.toString(method.getDeclaringClass()); marshalMethod(writer, declaringClassName, null, method.getParameterTypes()); } } - private void marshalMethod(HierarchicalStreamWriter writer, String declaringClassName, String methodName, Class[] parameterTypes) { + private void marshalMethod(final HierarchicalStreamWriter writer, final String declaringClassName, + final String methodName, final Class[] parameterTypes) { writer.startNode("class"); writer.setValue(declaringClassName); @@ -59,22 +101,22 @@ } writer.startNode("parameter-types"); - for (int i = 0; i < parameterTypes.length; i++) { - Class parameterType = parameterTypes[i]; + for (final Class parameterType : parameterTypes) { writer.startNode("class"); - writer.setValue(parameterType.getName()); + writer.setValue(javaClassConverter.toString(parameterType)); writer.endNode(); } writer.endNode(); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { try { - boolean isMethodNotConstructor = context.getRequiredType().equals(Method.class); + final boolean isMethodNotConstructor = context.getRequiredType().equals(Method.class); reader.moveDown(); - String declaringClassName = reader.getValue(); - Class declaringClass = loadClass(declaringClassName); + final String declaringClassName = reader.getValue(); + final Class declaringClass = (Class)javaClassConverter.fromString(declaringClassName); reader.moveUp(); String methodName = null; @@ -85,49 +127,23 @@ } reader.moveDown(); - List parameterTypeList = new ArrayList(); + final List> parameterTypeList = new ArrayList>(); while (reader.hasMoreChildren()) { reader.moveDown(); - String parameterTypeName = reader.getValue(); - parameterTypeList.add(loadClass(parameterTypeName)); + final String parameterTypeName = reader.getValue(); + parameterTypeList.add((Class)javaClassConverter.fromString(parameterTypeName)); reader.moveUp(); } - Class[] parameterTypes = (Class[]) parameterTypeList.toArray(new Class[parameterTypeList.size()]); + final Class[] parameterTypes = parameterTypeList.toArray(new Class[parameterTypeList.size()]); reader.moveUp(); if (isMethodNotConstructor) { return declaringClass.getDeclaredMethod(methodName, parameterTypes); } else { return declaringClass.getDeclaredConstructor(parameterTypes); } - } catch (ClassNotFoundException e) { + } catch (final NoSuchMethodException e) { throw new ConversionException(e); - } catch (NoSuchMethodException e) { - throw new ConversionException(e); } } - - private Class loadClass(String className) throws ClassNotFoundException { - Class primitiveClass = primitiveClassForName(className); - if( primitiveClass != null ){ - return primitiveClass; - } - return classLoader.loadClass(className); - } - - /** - * Lookup table for primitive types. - */ - private Class primitiveClassForName(String name) { - return name.equals("void") ? Void.TYPE : - name.equals("boolean") ? Boolean.TYPE : - name.equals("byte") ? Byte.TYPE : - name.equals("char") ? Character.TYPE : - name.equals("short") ? Short.TYPE : - name.equals("int") ? Integer.TYPE : - name.equals("long") ? Long.TYPE : - name.equals("float") ? Float.TYPE : - name.equals("double") ? Double.TYPE : - null; - } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/LocaleConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/LocaleConverter.java (.../LocaleConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/LocaleConverter.java (.../LocaleConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,23 +1,37 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 24. July 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; - import java.util.Locale; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + /** - * Converts a java.util.Locale to a string. - * + * Converts a {@link Locale} to a string. + * * @author Jose A. Illescas * @author Joe Walnes */ -public class LocaleConverter extends AbstractBasicConverter { +public class LocaleConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(Locale.class); } - protected Object fromString(String str) { - int[] underscorePositions = underscorePositions(str); + @Override + public Object fromString(final String str) { + final int[] underscorePositions = underscorePositions(str); String language, country, variant; if (underscorePositions[0] == -1) { // "language" language = str; @@ -35,13 +49,13 @@ return new Locale(language, country, variant); } - private int[] underscorePositions(String in) { - int[] result = new int[2]; + private int[] underscorePositions(final String in) { + final int[] result = new int[2]; for (int i = 0; i < result.length; i++) { - int last = i == 0 ? 0 : result[i - 1]; + final int last = i == 0 ? 0 : result[i - 1]; result[i] = in.indexOf('_', last + 1); } return result; } -} \ No newline at end of file +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/LookAndFeelConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/LookAndFeelConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/LookAndFeelConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007, 2008, 2013, 2014 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 08.12.2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.io.NotSerializableException; + +import javax.swing.LookAndFeel; + +import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; +import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * A converter for Swing {@link LookAndFeel} implementations. + *

+ * The JDK's implementations are serializable for historical reasons but will throw a {@link NotSerializableException} + * in their writeObject method. Therefore XStream will use an implementation based on the ReflectionConverter. + *

+ * + * @author Jörg Schaible + * @since 1.3 + */ +public class LookAndFeelConverter extends ReflectionConverter { + + /** + * Constructs a LookAndFeelConverter. + * + * @param mapper the mapper + * @param reflectionProvider the reflection provider + * @since 1.3 + */ + public LookAndFeelConverter(final Mapper mapper, final ReflectionProvider reflectionProvider) { + super(mapper, reflectionProvider); + } + + @Override + public boolean canConvert(final Class type) { + return LookAndFeel.class.isAssignableFrom(type) && canAccess(type); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/NamedArrayConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/NamedArrayConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/NamedArrayConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2013, 2014 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 03. December 2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.core.util.Primitives; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * An array converter that uses predefined names for its items. + *

+ * To be used as local converter. + *

+ * + * @author Jörg Schaible + * @since 1.4.6 + */ +public class NamedArrayConverter implements Converter { + + private final Class arrayType; + private final String itemName; + private final Mapper mapper; + + /** + * Construct a NamedArrayConverter. + * + * @param arrayType + * @param mapper + * @param itemName + * @since 1.4.6 + */ + public NamedArrayConverter(final Class arrayType, final Mapper mapper, final String itemName) { + if (!arrayType.isArray()) { + throw new IllegalArgumentException(arrayType.getName() + " is not an array"); + } + this.arrayType = arrayType; + this.mapper = mapper; + this.itemName = itemName; + } + + @Override + public boolean canConvert(final Class type) { + return type == arrayType; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final int length = Array.getLength(source); + for (int i = 0; i < length; ++i) { + final Object item = Array.get(source, i); + final Class itemType = item == null ? Mapper.Null.class : arrayType.getComponentType().isPrimitive() + ? Primitives.unbox(item.getClass()) + : item.getClass(); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, itemName, itemType); + if (!itemType.equals(arrayType.getComponentType())) { + final String attributeName = mapper.aliasForSystemAttribute("class"); + if (attributeName != null) { + writer.addAttribute(attributeName, mapper.serializedClass(itemType)); + } + } + if (item != null) { + context.convertAnother(item); + } + writer.endNode(); + } + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final List list = new ArrayList(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + final Object item; + final String className = HierarchicalStreams.readClassAttribute(reader, mapper); + final Class itemType = className == null ? arrayType.getComponentType() : mapper.realClass(className); + if (Mapper.Null.class.equals(itemType)) { + item = null; + } else { + item = context.convertAnother(null, itemType); + } + list.add(item); + reader.moveUp(); + } + final Object array = Array.newInstance(arrayType.getComponentType(), list.size()); + for (int i = 0; i < list.size(); ++i) { + Array.set(array, i, list.get(i)); + } + return array; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/NamedCollectionConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/NamedCollectionConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/NamedCollectionConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2013, 2014 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 19. September 2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.util.Collection; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.collections.CollectionConverter; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * A collection converter that uses predefined names for its items. + *

+ * To be used as local converter. Note, suppress the usage of the implicit type argument, if registered with annotation. + *

+ * + * @author Jörg Schaible + * @since 1.4.5 + */ +public class NamedCollectionConverter extends CollectionConverter { + + private final String name; + private final Class type; + + /** + * Constructs a NamedCollectionConverter. + * + * @param mapper the mapper + * @param itemName the name of the items + * @param itemType the base type of the items + * @since 1.4.5 + */ + public NamedCollectionConverter(final Mapper mapper, final String itemName, final Class itemType) { + this(null, mapper, itemName, itemType); + } + + /** + * Constructs a NamedCollectionConverter handling an explicit Collection type. + * + * @param type the Collection type to handle + * @param mapper the mapper + * @param itemName the name of the items + * @param itemType the base type of the items + * @since 1.4.5 + */ + public NamedCollectionConverter( + @SuppressWarnings("rawtypes") final Class type, final Mapper mapper, + final String itemName, final Class itemType) { + super(mapper, type); + name = itemName; + this.type = itemType; + } + + @Override + protected void writeItem(final Object item, final MarshallingContext context, final HierarchicalStreamWriter writer) { + final Class itemType = item == null ? Mapper.Null.class : item.getClass(); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, itemType); + if (!itemType.equals(type)) { + final String attributeName = mapper().aliasForSystemAttribute("class"); + if (attributeName != null) { + writer.addAttribute(attributeName, mapper().serializedClass(itemType)); + } + } + if (item != null) { + context.convertAnother(item); + } + writer.endNode(); + } + + @Override + protected Object readItem(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Object current) { + final String className = HierarchicalStreams.readClassAttribute(reader, mapper()); + final Class itemType = className == null ? type : mapper().realClass(className); + if (Mapper.Null.class.equals(itemType)) { + return null; + } else { + return context.convertAnother(current, itemType); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/NamedMapConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/NamedMapConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/NamedMapConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2013, 2014 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 20. September 2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.util.Map; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.collections.MapConverter; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * A map converter that uses predefined names for its elements. + *

+ * To be used as local converter. Note, suppress the usage of the implicit type argument, if registered with annotation. + * Depending on the constructor arguments it is possible to support various formats: + *

+ *
    + *
  • new NamedMapConverter(xstream.getMapper(), "entry", "key", String.class, "value", Integer.class); + * + *
    + * <map>
    + *   <entry>
    + *     <key>keyValue</key>
    + *     <value>0</value>
    + *   </entry>
    + * </map>
    + * 
    + * + *
  • + *
  • new NamedMapConverter(xstream.getMapper(), null, "key", String.class, "value", Integer.class); + * + *
    + * <map>
    + *   <key>keyValue</key>
    + *   <value>0</value>
    + * </map>
    + * 
    + * + *
  • + *
  • new NamedMapConverter(xstream.getMapper(), "entry", "key", String.class, "value", Integer.class, true, true, + * xstream.getConverterLookup()); + * + *
    + * <map>
    + *   <entry> key="keyValue" value="0"/>
    + * </map>
    + * 
    + * + *
  • + *
  • new NamedMapConverter(xstream.getMapper(), "entry", "key", String.class, "value", Integer.class, true, false, + * xstream.getConverterLookup()); + * + *
    + * <map>
    + *   <entry key="keyValue">
    + *     <value>0</value>
    + *   </entry>
    + * </map>
    + * 
    + * + *
  • + *
  • new NamedMapConverter(xstream.getMapper(), "entry", "key", String.class, "value", Integer.class, false, true, + * xstream.getConverterLookup()); + * + *
    + * <map>
    + *   <entry value="0">
    + *     <key>keyValue</key>
    + *   </entry>
    + * </map>
    + * 
    + * + *
  • + *
  • new NamedMapConverter(xstream.getMapper(), "entry", "key", String.class, null, Integer.class, true, false, + * xstream.getConverterLookup()); + * + *
    + * <map>
    + *   <entry key="keyValue">0</entry>
    + * </map>
    + * 
    + * + *
  • + *
+ * + * @author Jörg Schaible + * @since 1.4.5 + */ +public class NamedMapConverter extends MapConverter { + + private final String entryName; + private final String keyName; + private final Class keyType; + private final String valueName; + private final Class valueType; + private final boolean keyAsAttribute; + private final boolean valueAsAttribute; + private final ConverterLookup lookup; + private final Mapper enumMapper; + + /** + * Constructs a NamedMapConverter. + * + * @param mapper the mapper + * @param entryName the name of the entry elements + * @param keyName the name of the key elements + * @param keyType the base type of key elements + * @param valueName the name of the value elements + * @param valueType the base type of value elements + * @since 1.4.5 + */ + public NamedMapConverter( + final Mapper mapper, final String entryName, final String keyName, final Class keyType, + final String valueName, final Class valueType) { + this(mapper, entryName, keyName, keyType, valueName, valueType, false, false, null); + } + + /** + * Constructs a NamedMapConverter handling an explicit Map type. + * + * @param type the Map type this instance will handle + * @param mapper the mapper + * @param entryName the name of the entry elements + * @param keyName the name of the key elements + * @param keyType the base type of key elements + * @param valueName the name of the value elements + * @param valueType the base type of value elements + * @since 1.4.5 + */ + public NamedMapConverter( + @SuppressWarnings("rawtypes") final Class type, final Mapper mapper, final String entryName, + final String keyName, final Class keyType, final String valueName, final Class valueType) { + this(type, mapper, entryName, keyName, keyType, valueName, valueType, false, false, null); + } + + /** + * Constructs a NamedMapConverter with attribute support. + * + * @param mapper the mapper + * @param entryName the name of the entry elements + * @param keyName the name of the key elements + * @param keyType the base type of key elements + * @param valueName the name of the value elements + * @param valueType the base type of value elements + * @param keyAsAttribute flag to write key as attribute of entry element + * @param valueAsAttribute flag to write value as attribute of entry element + * @param lookup used to lookup SingleValueConverter for attributes + * @since 1.4.5 + */ + public NamedMapConverter( + final Mapper mapper, final String entryName, final String keyName, final Class keyType, + final String valueName, final Class valueType, final boolean keyAsAttribute, + final boolean valueAsAttribute, final ConverterLookup lookup) { + this(null, mapper, entryName, keyName, keyType, valueName, valueType, keyAsAttribute, valueAsAttribute, lookup); + } + + /** + * Constructs a NamedMapConverter with attribute support handling an explicit Map type. + * + * @param type the Map type this instance will handle + * @param mapper the mapper + * @param entryName the name of the entry elements + * @param keyName the name of the key elements + * @param keyType the base type of key elements + * @param valueName the name of the value elements + * @param valueType the base type of value elements + * @param keyAsAttribute flag to write key as attribute of entry element + * @param valueAsAttribute flag to write value as attribute of entry element + * @param lookup used to lookup SingleValueConverter for attributes + * @since 1.4.5 + */ + public NamedMapConverter( + @SuppressWarnings("rawtypes") final Class type, final Mapper mapper, final String entryName, + final String keyName, final Class keyType, final String valueName, final Class valueType, + final boolean keyAsAttribute, final boolean valueAsAttribute, final ConverterLookup lookup) { + super(mapper, type); + this.entryName = entryName != null && entryName.length() == 0 ? null : entryName; + this.keyName = keyName != null && keyName.length() == 0 ? null : keyName; + this.keyType = keyType; + this.valueName = valueName != null && valueName.length() == 0 ? null : valueName; + this.valueType = valueType; + this.keyAsAttribute = keyAsAttribute; + this.valueAsAttribute = valueAsAttribute; + this.lookup = lookup; + enumMapper = UseAttributeForEnumMapper.createEnumMapper(mapper); + + if (keyType == null || valueType == null) { + throw new IllegalArgumentException("Class types of key and value are mandatory"); + } + if (entryName == null) { + if (keyAsAttribute || valueAsAttribute) { + throw new IllegalArgumentException("Cannot write attributes to map entry, if map entry must be omitted"); + } + if (valueName == null) { + throw new IllegalArgumentException("Cannot write value as text of entry, if entry must be omitted"); + } + } + if (keyName == null) { + throw new IllegalArgumentException("Cannot write key without name"); + } + if (valueName == null) { + if (valueAsAttribute) { + throw new IllegalArgumentException("Cannot write value as attribute without name"); + } else if (!keyAsAttribute) { + throw new IllegalArgumentException("Cannot write value as text of entry, if key is also child element"); + } + } + if (keyAsAttribute && valueAsAttribute && keyName.equals(valueName)) { + throw new IllegalArgumentException("Cannot write key and value with same attribute name"); + } + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Map map = (Map)source; + SingleValueConverter keyConverter = null; + SingleValueConverter valueConverter = null; + if (keyAsAttribute) { + final SingleValueConverter singleValueConverter = getSingleValueConverter(keyType); + keyConverter = singleValueConverter; + } + if (valueAsAttribute || valueName == null) { + final SingleValueConverter singleValueConverter = getSingleValueConverter(valueType); + valueConverter = singleValueConverter; + } + for (final Map.Entry entry : map.entrySet()) { + final Object key = entry.getKey(); + final Object value = entry.getValue(); + if (entryName != null) { + ExtendedHierarchicalStreamWriterHelper.startNode(writer, entryName, entry.getClass()); + if (keyConverter != null && key != null) { + writer.addAttribute(keyName, keyConverter.toString(key)); + } + if (valueName != null && valueConverter != null && value != null) { + writer.addAttribute(valueName, valueConverter.toString(value)); + } + } + + if (keyConverter == null) { + writeItem(keyName, keyType, key, context, writer); + } + if (valueConverter == null) { + writeItem(valueName, valueType, value, context, writer); + } else if (valueName == null) { + writer.setValue(valueConverter.toString(value)); + } + + if (entryName != null) { + writer.endNode(); + } + } + } + + @Override + protected void populateMap(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Map map, final Map target) { + SingleValueConverter keyConverter = null; + SingleValueConverter valueConverter = null; + if (keyAsAttribute) { + keyConverter = getSingleValueConverter(keyType); + } + if (valueAsAttribute || valueName == null) { + valueConverter = getSingleValueConverter(valueType); + } + + while (reader.hasMoreChildren()) { + Object key = null; + Object value = null; + + if (entryName != null) { + reader.moveDown(); + + if (keyConverter != null) { + final String attribute = reader.getAttribute(keyName); + if (attribute != null) { + key = keyConverter.fromString(attribute); + } + } + + if (valueAsAttribute && valueConverter != null) { + final String attribute = reader.getAttribute(valueName); + if (attribute != null) { + value = valueConverter.fromString(attribute); + } + } + } + + if (keyConverter == null) { + reader.moveDown(); + if (valueConverter == null && !keyName.equals(valueName) && reader.getNodeName().equals(valueName)) { + value = readItem(valueType, reader, context, map); + } else { + key = readItem(keyType, reader, context, map); + } + reader.moveUp(); + } + + if (valueConverter == null) { + reader.moveDown(); + if (keyConverter == null && key == null && value != null) { + key = readItem(keyType, reader, context, map); + } else { + value = readItem(valueType, reader, context, map); + } + reader.moveUp(); + } else if (!valueAsAttribute) { + value = reader.getValue(); + } + + @SuppressWarnings("unchecked") + final Map targetMap = (Map)target; + targetMap.put(key, value); + + if (entryName != null) { + reader.moveUp(); + } + } + } + + private SingleValueConverter getSingleValueConverter(final Class type) { + SingleValueConverter conv = Enum.class.isAssignableFrom(type) ? enumMapper.getConverterFromItemType(null, type, + null) : mapper().getConverterFromItemType(null, type, null); + if (conv == null) { + final Converter converter = lookup.lookupConverterForType(type); + if (converter instanceof SingleValueConverter) { + conv = (SingleValueConverter)converter; + } else { + throw new ConversionException("No SingleValueConverter for key available"); + } + } + return conv; + } + + protected void writeItem(final String name, final Class type, final Object item, + final MarshallingContext context, final HierarchicalStreamWriter writer) { + final Class itemType = item == null ? Mapper.Null.class : item.getClass(); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, itemType); + if (!itemType.equals(type)) { + final String attributeName = mapper().aliasForSystemAttribute("class"); + if (attributeName != null) { + writer.addAttribute(attributeName, mapper().serializedClass(itemType)); + } + } + if (item != null) { + context.convertAnother(item); + } + writer.endNode(); + } + + protected Object readItem(final Class type, final HierarchicalStreamReader reader, + final UnmarshallingContext context, final Object current) { + final String className = HierarchicalStreams.readClassAttribute(reader, mapper()); + final Class itemType = className == null ? type : mapper().realClass(className); + if (Mapper.Null.class.equals(itemType)) { + return null; + } else { + return context.convertAnother(current, itemType); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/PropertyEditorCapableConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/PropertyEditorCapableConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/PropertyEditorCapableConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007, 2008, 2014 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 20.09.2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.beans.PropertyEditor; + +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.core.util.ThreadSafePropertyEditor; + + +/** + * A SingleValueConverter that can utilize a {@link PropertyEditor} implementation used for a specific type. The + * converter ensures that the editors can be used concurrently. + * + * @author Jukka Lindström + * @author Jörg Schaible + * @since 1.3 + */ +public class PropertyEditorCapableConverter implements SingleValueConverter { + + private final ThreadSafePropertyEditor editor; + private final Class type; + + public PropertyEditorCapableConverter(final Class propertyEditorType, final Class type) { + this.type = type; + editor = new ThreadSafePropertyEditor(propertyEditorType, 2, 5); + } + + @Override + public boolean canConvert(final Class type) { + return this.type == type; + } + + @Override + public Object fromString(final String str) { + return editor.setAsText(str); + } + + @Override + public String toString(final Object obj) { + return editor.getAsText(obj); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/RegexPatternConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/RegexPatternConverter.java (.../RegexPatternConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/RegexPatternConverter.java (.../RegexPatternConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,35 +1,74 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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 31. July 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; +import java.util.regex.Pattern; + import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import java.util.regex.Pattern; /** - * Ensures java.util.regex.Pattern is compiled upon deserialization. + * Converts a {@link Pattern} using two nested elements for the pattern itself and its flags. + *

+ * Ensures that the pattern is compiled upon deserialization. + *

+ * + * @author Joe Walnes + * @author Jörg Schaible */ public class RegexPatternConverter implements Converter { - private Converter defaultConverter; + /** + * @since 1.4.5 + */ + public RegexPatternConverter() { + } - public RegexPatternConverter(Converter defaultConverter) { - this.defaultConverter = defaultConverter; + /** + * @deprecated As of 1.4.5, use {@link #RegexPatternConverter()} instead + */ + @Deprecated + public RegexPatternConverter(final Converter defaultConverter) { } - public boolean canConvert(final Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(Pattern.class); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - defaultConverter.marshal(source, writer, context); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Pattern pattern = (Pattern)source; + writer.startNode("pattern"); + writer.setValue(pattern.pattern()); + writer.endNode(); + writer.startNode("flags"); + writer.setValue(String.valueOf(pattern.flags())); + writer.endNode(); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - Pattern notCompiled = (Pattern) defaultConverter.unmarshal(reader, context); - return Pattern.compile(notCompiled.pattern(), notCompiled.flags()); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + reader.moveDown(); + final String pattern = reader.getValue(); + reader.moveUp(); + reader.moveDown(); + final int flags = Integer.parseInt(reader.getValue()); + reader.moveUp(); + return Pattern.compile(pattern, flags); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlDateConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlDateConverter.java (.../SqlDateConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlDateConverter.java (.../SqlDateConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,22 +1,35 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 24. July 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; - import java.sql.Date; -import java.sql.Time; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + /** - * Converts a java.sql.Date to text. - * - * @author Jose A. Illescas + * Converts a {@link Date} to a string. + * + * @author Jose A. Illescas */ -public class SqlDateConverter extends AbstractBasicConverter { +public class SqlDateConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(Date.class); } - protected Object fromString(String str) { + @Override + public Object fromString(final String str) { return Date.valueOf(str); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimeConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimeConverter.java (.../SqlTimeConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimeConverter.java (.../SqlTimeConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,21 +1,38 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 24. July 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; - import java.sql.Time; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + /** - * Converts a java.sql.Time to text. Warning: Any granularity smaller than seconds is lost. - * + * Converts a {@link Time} to a string. + *

+ * Warning: Any granularity smaller than seconds is lost. + *

+ * * @author Jose A. Illescas */ -public class SqlTimeConverter extends AbstractBasicConverter { +public class SqlTimeConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(Time.class); } - protected Object fromString(String str) { + @Override + public Object fromString(final String str) { return Time.valueOf(str); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimestampConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimestampConverter.java (.../SqlTimestampConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SqlTimestampConverter.java (.../SqlTimestampConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,22 +1,77 @@ +/* + * Copyright (C) 2003, 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2012, 2014 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 01. October 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; - import java.sql.Timestamp; +import java.text.ParseException; +import java.util.TimeZone; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; +import com.thoughtworks.xstream.core.util.ThreadSafeSimpleDateFormat; + + /** - * Converts a java.sql.Timestamp to text. - * + * Converts a {@link Timestamp} to a string. + * * @author Joe Walnes + * @author Jörg Schaible */ -public class SqlTimestampConverter extends AbstractBasicConverter { +public class SqlTimestampConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + private final ThreadSafeSimpleDateFormat format = new ThreadSafeSimpleDateFormat("yyyy-MM-dd HH:mm:ss", TimeZone + .getTimeZone("UTC"), 0, 5, false); + + @Override + public boolean canConvert(final Class type) { return type.equals(Timestamp.class); } - protected Object fromString(String str) { - return Timestamp.valueOf(str); + @Override + public String toString(final Object obj) { + final Timestamp timestamp = (Timestamp)obj; + final StringBuilder buffer = new StringBuilder(format.format(timestamp)).append('.'); + if (timestamp.getNanos() == 0) { + buffer.append('0'); + } else { + final String nanos = String.valueOf(timestamp.getNanos() + 1000000000); + int last = 10; + while (last > 2 && nanos.charAt(last - 1) == '0') { + --last; + } + buffer.append(nanos.subSequence(1, last)); + } + return buffer.toString(); } + @Override + public Object fromString(final String str) { + final int idx = str.lastIndexOf('.'); + if (idx < 0 || str.length() - idx < 2 || str.length() - idx > 10) { + throw new ConversionException("Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]"); + } + try { + final Timestamp timestamp = new Timestamp(format.parse(str.substring(0, idx)).getTime()); + final StringBuilder buffer = new StringBuilder(str.substring(idx + 1)); + while (buffer.length() != 9) { + buffer.append('0'); + } + timestamp.setNanos(Integer.parseInt(buffer.toString())); + return timestamp; + } catch (final NumberFormatException e) { + throw new ConversionException("Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]", e); + } catch (final ParseException e) { + throw new ConversionException("Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]"); + } + } + } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter.java (.../StackTraceElementConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter.java (.../StackTraceElementConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,52 +1,70 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 29. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.converters.basic.AbstractBasicConverter; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; - -import java.lang.reflect.Field; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + /** - * Converter for StackTraceElement (the lines of a stack trace) - JDK 1.4+ only. - * + * Converter for {@link StackTraceElement} (the lines of a stack trace) to a string. + * * @author B. K. Oxley (binkley) * @author Joe Walnes */ -public class StackTraceElementConverter extends AbstractBasicConverter { +public class StackTraceElementConverter extends AbstractSingleValueConverter { // Regular expression to parse a line of a stack trace. Returns 4 groups. // - // Example: com.blah.MyClass.doStuff(MyClass.java:123) - // |-------1------| |--2--| |----3-----| |4| + // Example: + // com.blah.MyClass.doStuff(MyClass.java:123) + // |-------1------| |--2--| |----3-----| |4| // (Note group 4 is optional is optional and only present if a colon char exists.) private static final Pattern PATTERN = Pattern.compile("^(.+)\\.([^\\(]+)\\(([^:]*)(:(\\d+))?\\)$"); + private static final StackTraceElementFactory FACTORY = new StackTraceElementFactory(); - private final StackTraceElementFactory factory = new StackTraceElementFactory(); - - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return StackTraceElement.class.equals(type); } - protected Object fromString(String str) { - Matcher matcher = PATTERN.matcher(str); + @Override + public String toString(final Object obj) { + final String s = super.toString(obj); + // JRockit adds ":???" for invalid line number + return s.replaceFirst(":\\?\\?\\?", ""); + } + + @Override + public Object fromString(final String str) { + final Matcher matcher = PATTERN.matcher(str); if (matcher.matches()) { - String declaringClass = matcher.group(1); - String methodName = matcher.group(2); - String fileName = matcher.group(3); + final String declaringClass = matcher.group(1); + final String methodName = matcher.group(2); + final String fileName = matcher.group(3); if (fileName.equals("Unknown Source")) { - return factory.unknownSourceElement(declaringClass, methodName); + return FACTORY.unknownSourceElement(declaringClass, methodName); } else if (fileName.equals("Native Method")) { - return factory.nativeMethodElement(declaringClass, methodName); + return FACTORY.nativeMethodElement(declaringClass, methodName); } else { if (matcher.group(4) != null) { - int lineNumber = Integer.parseInt(matcher.group(5)); - return factory.element(declaringClass, methodName, fileName, lineNumber); + final int lineNumber = Integer.parseInt(matcher.group(5)); + return FACTORY.element(declaringClass, methodName, fileName, lineNumber); } else { - return factory.element(declaringClass, methodName, fileName); + return FACTORY.element(declaringClass, methodName, fileName); } } } else { Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementFactory.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementFactory.java (.../StackTraceElementFactory.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/StackTraceElementFactory.java (.../StackTraceElementFactory.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,16 +1,24 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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 30. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.xstream.converters.ConversionException; - -import java.lang.reflect.Field; - /** * Factory for creating StackTraceElements. - * Factory for creating StackTraceElements. * * @author B. K. Oxley (binkley) * @author Joe Walnes + * @deprecated As of upcoming, it is an internal helper class */ +@Deprecated public class StackTraceElementFactory { public StackTraceElement nativeMethodElement(String declaringClass, String methodName) { @@ -30,22 +38,6 @@ } private StackTraceElement create(String declaringClass, String methodName, String fileName, int lineNumber) { - StackTraceElement result = new Throwable().getStackTrace()[0]; - setField(result, "declaringClass", declaringClass); - setField(result, "methodName", methodName); - setField(result, "fileName", fileName); - setField(result, "lineNumber", new Integer(lineNumber)); - return result; + return new StackTraceElement(declaringClass, methodName, fileName, lineNumber); } - - private void setField(StackTraceElement element, String fieldName, Object value) { - try { - final Field field = StackTraceElement.class.getDeclaredField(fieldName); - field.setAccessible(true); - field.set(element, value); - } catch (Exception e) { - throw new ConversionException(e); - } - } - } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SubjectConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SubjectConverter.java (.../SubjectConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/SubjectConverter.java (.../SubjectConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,100 +1,123 @@ +/* + * Copyright (C) 2006, 2007, 2014 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 12. January 2006 by Joerg Schaible + */ package com.thoughtworks.xstream.converters.extended; +import java.security.Principal; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import javax.security.auth.Subject; + import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; -import javax.security.auth.Subject; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - /** - * Converts a {@link Subject} instance. Note, that this Converter does only convert the contained Principals as - * it is done by JDK serialization, but not any credentials. For other behaviour you can derive your own converter, - * overload the appropriate methods and register it in the {@link com.thoughtworks.xstream.XStream}. - * + * Converts a {@link Subject} instance. + *

+ * Note, that this Converter does only convert the contained Principals as it is done by JDK serialization, but not any + * credentials. For other behavior you can derive your own converter, overload the appropriate methods and register it + * in the {@link com.thoughtworks.xstream.XStream}. + *

+ * * @author Jörg Schaible + * @since 1.1.3 */ public class SubjectConverter extends AbstractCollectionConverter { - public SubjectConverter(Mapper mapper) { + public SubjectConverter(final Mapper mapper) { super(mapper); } - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(Subject.class); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - Subject subject = (Subject) source; + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Subject subject = (Subject)source; marshalPrincipals(subject.getPrincipals(), writer, context); marshalPublicCredentials(subject.getPublicCredentials(), writer, context); marshalPrivateCredentials(subject.getPrivateCredentials(), writer, context); marshalReadOnly(subject.isReadOnly(), writer); } - - protected void marshalPrincipals(Set principals, HierarchicalStreamWriter writer, MarshallingContext context) { + + protected void marshalPrincipals(final Set principals, final HierarchicalStreamWriter writer, + final MarshallingContext context) { writer.startNode("principals"); - for (final Iterator iter = principals.iterator(); iter.hasNext();) { - final Object principal = iter.next(); // pre jdk 1.4 a Principal was also in javax.security + for (final Principal principal : principals) { writeItem(principal, context, writer); } writer.endNode(); }; - - protected void marshalPublicCredentials(Set pubCredentials, HierarchicalStreamWriter writer, MarshallingContext context) { + + protected void marshalPublicCredentials(final Set pubCredentials, final HierarchicalStreamWriter writer, + final MarshallingContext context) { }; - protected void marshalPrivateCredentials(Set privCredentials, HierarchicalStreamWriter writer, MarshallingContext context) { + protected void marshalPrivateCredentials(final Set privCredentials, final HierarchicalStreamWriter writer, + final MarshallingContext context) { }; - - protected void marshalReadOnly(boolean readOnly, HierarchicalStreamWriter writer) { + + protected void marshalReadOnly(final boolean readOnly, final HierarchicalStreamWriter writer) { writer.startNode("readOnly"); writer.setValue(String.valueOf(readOnly)); writer.endNode(); }; - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - Set principals = unmarshalPrincipals(reader, context); - Set publicCredentials = unmarshalPublicCredentials(reader, context); - Set privateCredentials = unmarshalPrivateCredentials(reader, context); - boolean readOnly = unmarshalReadOnly(reader); + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Set principals = unmarshalPrincipals(reader, context); + final Set publicCredentials = unmarshalPublicCredentials(reader, context); + final Set privateCredentials = unmarshalPrivateCredentials(reader, context); + final boolean readOnly = unmarshalReadOnly(reader); return new Subject(readOnly, principals, publicCredentials, privateCredentials); } - - protected Set unmarshalPrincipals(HierarchicalStreamReader reader, UnmarshallingContext context) { + + protected Set unmarshalPrincipals(final HierarchicalStreamReader reader, + final UnmarshallingContext context) { return populateSet(reader, context); }; - - protected Set unmarshalPublicCredentials(HierarchicalStreamReader reader, UnmarshallingContext context) { - return Collections.EMPTY_SET; + + protected Set unmarshalPublicCredentials(final HierarchicalStreamReader reader, + final UnmarshallingContext context) { + return Collections.emptySet(); }; - protected Set unmarshalPrivateCredentials(HierarchicalStreamReader reader, UnmarshallingContext context) { - return Collections.EMPTY_SET; + protected Set unmarshalPrivateCredentials(final HierarchicalStreamReader reader, + final UnmarshallingContext context) { + return Collections.emptySet(); }; - protected boolean unmarshalReadOnly(HierarchicalStreamReader reader) { + protected boolean unmarshalReadOnly(final HierarchicalStreamReader reader) { reader.moveDown(); - boolean readOnly = Boolean.getBoolean(reader.getValue()); + final boolean readOnly = Boolean.getBoolean(reader.getValue()); reader.moveUp(); return readOnly; }; - protected Set populateSet(HierarchicalStreamReader reader, UnmarshallingContext context) { - Set set = new HashSet(); + protected Set populateSet(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Set set = new HashSet(); reader.moveDown(); while (reader.hasMoreChildren()) { reader.moveDown(); - Object elementl = readItem(reader, context, set); + final Principal principal = (Principal)readItem(reader, context, set); reader.moveUp(); - set.add(elementl); + set.add(principal); } reader.moveUp(); return set; Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/TextAttributeConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/TextAttributeConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/TextAttributeConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2006, 2007, 2014 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 25. March 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.awt.font.TextAttribute; + +import com.thoughtworks.xstream.converters.reflection.AbstractAttributedCharacterIteratorAttributeConverter; + + +/** + * A converter for {@link TextAttribute} constants to a string. + * + * @author Jörg Schaible + * @since 1.2 + */ +public class TextAttributeConverter extends AbstractAttributedCharacterIteratorAttributeConverter { + + /** + * Constructs a TextAttributeConverter. + * + * @since 1.2.2 + */ + public TextAttributeConverter() { + super(TextAttribute.class); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ThrowableConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ThrowableConverter.java (.../ThrowableConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ThrowableConverter.java (.../ThrowableConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,40 +1,78 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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 29. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.extended; import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.List; /** - * Converter for Throwable (and Exception) that retains stack trace, for JDK1.4 only. - * + * Converter for {@link Throwable} (and {@link Exception}) that retains stack trace. + * * @author B. K. Oxley (binkley) * @author Joe Walnes + * @author Jörg Schaible */ public class ThrowableConverter implements Converter { private Converter defaultConverter; + private final ConverterLookup lookup; - public ThrowableConverter(Converter defaultConverter) { + /** + * @deprecated As of 1.4.5 use {@link #ThrowableConverter(ConverterLookup)} + */ + @Deprecated + public ThrowableConverter(final Converter defaultConverter) { this.defaultConverter = defaultConverter; + lookup = null; } - public boolean canConvert(final Class type) { + /** + * @since 1.4.5 + */ + public ThrowableConverter(final ConverterLookup lookup) { + this.lookup = lookup; + } + + @Override + public boolean canConvert(final Class type) { return Throwable.class.isAssignableFrom(type); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - Throwable throwable = (Throwable) source; - throwable.getStackTrace(); // Force stackTrace field to be lazy loaded by special JVM native witchcraft (outside our control). - defaultConverter.marshal(throwable, writer, context); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Throwable throwable = (Throwable)source; + if (throwable.getCause() == null) { + try { + throwable.initCause(null); + } catch (final IllegalStateException e) { + // ignore, initCause failed, cause was already set + } + } + // force stackTrace field to be lazy loaded by special JVM native witchcraft (outside our control). + throwable.getStackTrace(); + getConverter().marshal(throwable, writer, context); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { - return defaultConverter.unmarshal(reader, context); + private Converter getConverter() { + return defaultConverter != null ? defaultConverter : lookup.lookupConverterForType(Object.class); } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + return getConverter().unmarshal(reader, context); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2011, 2013, 2014 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 30. July 2011 by Joerg Schaible + */ + +package com.thoughtworks.xstream.converters.extended; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.ConverterMatcher; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.DuplicateFieldException; +import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; +import com.thoughtworks.xstream.core.util.FastField; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.core.util.Primitives; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Converter that supports the definition of one field member that will be written as value and all other field members + * are written as attributes. + *

+ * The converter requires that all the field types (expect the one with the value) are handled by a + * {@link SingleValueConverter}. The value field is defined using the name of the type that declares the field and the + * field name itself. Therefore it is possible to define an inherited field as value. It is also possible to provide no + * value field at all, so that all fields are written as attributes. + *

+ * + * @author Jörg Schaible + * @since 1.4 + */ +public class ToAttributedValueConverter implements Converter { + private static final String STRUCTURE_MARKER = ""; + private final Class type; + private final Mapper mapper; + private final Mapper enumMapper; + private final ReflectionProvider reflectionProvider; + private final ConverterLookup lookup; + private final Field valueField; + + /** + * Creates a new ToAttributedValueConverter instance. + * + * @param type the type that is handled by this converter instance + * @param mapper the mapper in use + * @param reflectionProvider the reflection provider in use + * @param lookup the converter lookup in use + * @param valueFieldName the field defining the tag's value (may be null) + */ + public ToAttributedValueConverter( + final Class type, final Mapper mapper, final ReflectionProvider reflectionProvider, + final ConverterLookup lookup, final String valueFieldName) { + this(type, mapper, reflectionProvider, lookup, valueFieldName, null); + } + + /** + * Creates a new ToAttributedValueConverter instance. + * + * @param type the type that is handled by this converter instance + * @param mapper the mapper in use + * @param reflectionProvider the reflection provider in use + * @param lookup the converter lookup in use + * @param valueFieldName the field defining the tag's value (may be null) + * @param valueDefinedIn the type defining the field + */ + public ToAttributedValueConverter( + final Class type, final Mapper mapper, final ReflectionProvider reflectionProvider, + final ConverterLookup lookup, final String valueFieldName, final Class valueDefinedIn) { + this.type = type; + this.mapper = mapper; + this.reflectionProvider = reflectionProvider; + this.lookup = lookup; + + if (valueFieldName == null) { + valueField = null; + } else { + Field field = null; + try { + field = (valueDefinedIn != null ? valueDefinedIn : type).getDeclaredField(valueFieldName); + if (!field.isAccessible()) { + field.setAccessible(true); + } + } catch (final NoSuchFieldException e) { + throw new IllegalArgumentException(e.getMessage() + ": " + valueFieldName); + } + valueField = field; + } + enumMapper = UseAttributeForEnumMapper.createEnumMapper(mapper); + } + + @Override + public boolean canConvert(final Class type) { + return this.type == type; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Class sourceType = source.getClass(); + final Map defaultFieldDefinition = new HashMap(); + final String[] tagValue = new String[1]; + final Object[] realValue = new Object[1]; + final Class[] fieldType = new Class[1]; + final Class[] definingType = new Class[1]; + reflectionProvider.visitSerializableFields(source, new ReflectionProvider.Visitor() { + @Override + public void visit(final String fieldName, final Class type, final Class definedIn, final Object value) { + if (!mapper.shouldSerializeMember(definedIn, fieldName)) { + return; + } + + final FastField field = new FastField(definedIn, fieldName); + final String alias = mapper.serializedMember(definedIn, fieldName); + if (!defaultFieldDefinition.containsKey(alias)) { + final Class lookupType = sourceType; + defaultFieldDefinition.put(alias, reflectionProvider.getField(lookupType, fieldName)); + } else if (!fieldIsEqual(field)) { + final ConversionException exception = new ConversionException( + "Cannot write attribute twice for object"); + exception.add("alias", alias); + exception.add("type", sourceType.getName()); + throw exception; + } + + ConverterMatcher converter = Enum.class.isAssignableFrom(type) ? (ConverterMatcher)enumMapper + .getConverterFromItemType(null, type, null) : (ConverterMatcher)mapper.getLocalConverter(definedIn, + fieldName); + if (converter == null) { + converter = lookup.lookupConverterForType(type); + } + + if (value != null) { + final boolean isValueField = valueField != null && fieldIsEqual(field); + if (isValueField) { + definingType[0] = definedIn; + fieldType[0] = type; + realValue[0] = value; + tagValue[0] = STRUCTURE_MARKER; + } + if (converter instanceof SingleValueConverter) { + final String str = ((SingleValueConverter)converter).toString(value); + + if (isValueField) { + tagValue[0] = str; + } else { + if (str != null) { + writer.addAttribute(alias, str); + } + } + } else { + if (!isValueField) { + final ConversionException exception = new ConversionException( + "Cannot write element as attribute"); + exception.add("alias", alias); + exception.add("type", sourceType.getName()); + throw exception; + } + } + } + } + }); + + if (tagValue[0] != null) { + final Class actualType = realValue[0].getClass(); + final Class defaultType = mapper.defaultImplementationOf(fieldType[0]); + if (!actualType.equals(defaultType)) { + final String serializedClassName = mapper.serializedClass(actualType); + if (!serializedClassName.equals(mapper.serializedClass(defaultType))) { + final String attributeName = mapper.aliasForSystemAttribute("class"); + if (attributeName != null) { + writer.addAttribute(attributeName, serializedClassName); + } + } + } + + if (tagValue[0] == STRUCTURE_MARKER) { + context.convertAnother(realValue[0]); + } else { + writer.setValue(tagValue[0]); + } + } + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Object result = reflectionProvider.newInstance(context.getRequiredType()); + final Class resultType = result.getClass(); + + final Set seenFields = new HashSet(); + final Iterator it = reader.getAttributeNames(); + + final Set systemAttributes = new HashSet(); + systemAttributes.add(mapper.aliasForSystemAttribute("class")); + + // Process attributes before recursing into child elements. + while (it.hasNext()) { + final String attrName = it.next(); + if (systemAttributes.contains(attrName)) { + continue; + } + + final String fieldName = mapper.realMember(resultType, attrName); + final Field field = reflectionProvider.getFieldOrNull(resultType, fieldName); + if (field != null) { + if (Modifier.isTransient(field.getModifiers())) { + continue; + } + + Class type = field.getType(); + final Class declaringClass = field.getDeclaringClass(); + ConverterMatcher converter = Enum.class.isAssignableFrom(type) ? (ConverterMatcher)enumMapper + .getConverterFromItemType(null, type, null) : (ConverterMatcher)mapper.getLocalConverter( + declaringClass, fieldName); + if (converter == null) { + converter = lookup.lookupConverterForType(type); + } + + if (!(converter instanceof SingleValueConverter)) { + final ConversionException exception = new ConversionException( + "Cannot read field as a single value for object"); + exception.add("field", fieldName); + exception.add("type", resultType.getName()); + throw exception; + } + + if (converter != null) { + final Object value = ((SingleValueConverter)converter).fromString(reader.getAttribute(attrName)); + if (type.isPrimitive()) { + type = Primitives.box(type); + } + + if (value != null && !type.isAssignableFrom(value.getClass())) { + final ConversionException exception = new ConversionException("Cannot assign object to type"); + exception.add("object type", value.getClass().getName()); + exception.add("target type", type.getName()); + throw exception; + } + + reflectionProvider.writeField(result, fieldName, value, declaringClass); + if (!seenFields.add(new FastField(declaringClass, fieldName))) { + throw new DuplicateFieldException(fieldName + " [" + declaringClass.getName() + "]"); + } + } + } + } + + if (valueField != null) { + final Class classDefiningField = valueField.getDeclaringClass(); + final String fieldName = valueField.getName(); + final Field field = fieldName == null ? null : reflectionProvider.getField(classDefiningField, fieldName); + if (fieldName == null || field == null) { + final ConversionException exception = new ConversionException("Cannot assign value to field of type"); + exception.add("element", reader.getNodeName()); + exception.add("field", fieldName); + exception.add("target type", context.getRequiredType().getName()); + throw exception; + } + + Class type; + final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper); + if (classAttribute != null) { + type = mapper.realClass(classAttribute); + } else { + type = mapper.defaultImplementationOf(reflectionProvider.getFieldType(result, fieldName, + classDefiningField)); + } + + final Object value = context.convertAnother(result, type, mapper.getLocalConverter(field + .getDeclaringClass(), field.getName())); + + final Class definedType = reflectionProvider.getFieldType(result, fieldName, classDefiningField); + if (!definedType.isPrimitive()) { + type = definedType; + } + + if (value != null && !type.isAssignableFrom(value.getClass())) { + final ConversionException exception = new ConversionException("Cannot assign object to type"); + exception.add("object type", value.getClass().getName()); + exception.add("target type", type.getName()); + throw exception; + } + + reflectionProvider.writeField(result, fieldName, value, classDefiningField); + if (!seenFields.add(new FastField(classDefiningField, fieldName))) { + throw new DuplicateFieldException(fieldName + " [" + classDefiningField.getName() + "]"); + } + } + return result; + } + + private boolean fieldIsEqual(final FastField field) { + return valueField.getName().equals(field.getName()) + && valueField.getDeclaringClass().getName().equals(field.getDeclaringClass()); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ToStringConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ToStringConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/ToStringConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006, 2007, 2014 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 07. July 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.converters.extended; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + + +/** + * Convenient converter for classes with natural string representation. + *

+ * Converter for classes that adopt the following convention: - a constructor that takes a single string parameter - a + * toString() that is overloaded to issue a string that is meaningful + *

+ * + * @author Paul Hammant + */ +public class ToStringConverter extends AbstractSingleValueConverter { + private final Class clazz; + private final Constructor ctor; + + public ToStringConverter(final Class clazz) throws NoSuchMethodException { + this.clazz = clazz; + ctor = clazz.getConstructor(String.class); + } + + @Override + public boolean canConvert(final Class type) { + return type.equals(clazz); + } + + @Override + public String toString(final Object obj) { + return obj == null ? null : obj.toString(); + } + + @Override + public Object fromString(final String str) { + try { + return ctor.newInstance(str); + } catch (final InstantiationException e) { + throw new ConversionException("Unable to instantiate single String param constructor", e); + } catch (final IllegalAccessException e) { + throw new ConversionException("Unable to access single String param constructor", e); + } catch (final InvocationTargetException e) { + throw new ConversionException("Unable to target single String param constructor", e.getTargetException()); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/UseAttributeForEnumMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/UseAttributeForEnumMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/UseAttributeForEnumMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2013, 2014 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 25. September 2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.mapper.AttributeMapper; +import com.thoughtworks.xstream.mapper.DefaultMapper; +import com.thoughtworks.xstream.mapper.EnumMapper; +import com.thoughtworks.xstream.mapper.Mapper; + + +class UseAttributeForEnumMapper extends AttributeMapper { + + public UseAttributeForEnumMapper(final Mapper wrapped) { + super(wrapped, null, null); + } + + @Override + public boolean shouldLookForSingleValueConverter(final String fieldName, final Class type, + final Class definedIn) { + return Enum.class.isAssignableFrom(type); + } + + @Override + public SingleValueConverter getConverterFromItemType(final String fieldName, final Class type, + final Class definedIn) { + return null; + } + + @Override + public SingleValueConverter getConverterFromAttribute(final Class definedIn, final String attribute, + final Class type) { + return null; + } + + static Mapper createEnumMapper(final Mapper mapper) { + return new EnumMapper(new UseAttributeForEnumMapper(mapper.lookupMapperOfType(DefaultMapper.class))); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/package.html =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/package.html (.../package.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/extended/package.html (.../package.html) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,2 +1,14 @@ -

Extra converters that are not enabled in XStream -by default.

\ No newline at end of file + + +

Extra converters that may not be enabled in XStream by default.

+ Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProperty.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProperty.java (.../BeanProperty.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProperty.java (.../BeanProperty.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,56 +1,65 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2014 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 12. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.converters.javabean; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.UndeclaredThrowableException; + /** * Provide access to a bean property. * * @author Andrea Aime + * @deprecated As of 1.3.1, no longer in use */ +@Deprecated public class BeanProperty { /** the target class */ - private Class memberClass; + private final Class memberClass; /** the property name */ - private String propertyName; + private final String propertyName; /** the property type */ - private Class type; + private final Class type; /** the getter */ protected Method getter; /** the setter */ private Method setter; - - private static final Object[] EMPTY_ARGS = new Object[0]; /** - * Creates a new {@link BeanProperty}that gets the specified property from - * the specified class. + * Creates a new {@link BeanProperty}that gets the specified property from the specified class. */ - public BeanProperty(Class memberClass, String propertyName, Class propertyType) { + public BeanProperty(final Class memberClass, final String propertyName, final Class propertyType) { this.memberClass = memberClass; this.propertyName = propertyName; - this.type = propertyType; + type = propertyType; } /** * Gets the base class that this getter accesses. */ - public Class getBeanClass() { + public Class getBeanClass() { return memberClass; } /** * Returns the property type - * - * @return */ - public Class getType() { + public Class getType() { return type; } @@ -65,62 +74,65 @@ * Gets whether this property can get get. */ public boolean isReadable() { - return (getter != null); + return getter != null; } /** * Gets whether this property can be set. */ public boolean isWritable() { - return (setter != null); + return setter != null; } /** * Gets the value of this property for the specified Object. + * * @throws IllegalAccessException * @throws IllegalArgumentException */ - public Object get(Object member) throws IllegalArgumentException, IllegalAccessException { - if (!isReadable()) - throw new IllegalStateException("Property " + propertyName + " of " + memberClass - + " not readable"); + public Object get(final Object member) throws IllegalArgumentException, IllegalAccessException { + if (!isReadable()) { + throw new IllegalStateException("Property " + propertyName + " of " + memberClass + " not readable"); + } try { - return getter.invoke(member, EMPTY_ARGS); - } catch (InvocationTargetException e) { + return getter.invoke(member); + } catch (final InvocationTargetException e) { throw new UndeclaredThrowableException(e.getTargetException()); } } /** * Sets the value of this property for the specified Object. + * * @throws IllegalAccessException * @throws IllegalArgumentException */ - public Object set(Object member, Object newValue) throws IllegalArgumentException, IllegalAccessException { - if (!isWritable()) - throw new IllegalStateException("Property " + propertyName + " of " + memberClass - + " not writable"); + public Object set(final Object member, final Object newValue) + throws IllegalArgumentException, IllegalAccessException { + if (!isWritable()) { + throw new IllegalStateException("Property " + propertyName + " of " + memberClass + " not writable"); + } try { - return setter.invoke(member, new Object[] { newValue }); - } catch (InvocationTargetException e) { + return setter.invoke(member, newValue); + } catch (final InvocationTargetException e) { throw new UndeclaredThrowableException(e.getTargetException()); } } /** * @param method */ - public void setGetterMethod(Method method) { - this.getter = method; + public void setGetterMethod(final Method method) { + getter = method; } /** * @param method */ - public void setSetterMethod(Method method) { - this.setter = method; + public void setSetterMethod(final Method method) { + setter = method; } -} \ No newline at end of file +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProvider.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProvider.java (.../BeanProvider.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/BeanProvider.java (.../BeanProvider.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,143 +1,192 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014 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 12. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.converters.javabean; +import java.beans.PropertyDescriptor; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Comparator; import java.util.Iterator; +import java.util.List; import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; -/** - * Pure Java ObjectFactory that instantiates objects using standard Java - * reflection, however the types of objects that can be constructed are limited. - *

Can newInstance: classes with public visibility, outer classes, static - * inner classes, classes with default constructors and any class that - * implements java.io.Serializable. Cannot newInstance: classes without public - * visibility, non-static inner classes, classes without default constructors. - * Note that any code in the constructor of a class will be executed when the - * ObjectFactory instantiates the object. - *

- */ -public class BeanProvider { -// private final Map serializedDataCache = Collections.synchronizedMap(new HashMap()); -// - protected PropertyDictionary propertyDictionary = new PropertyDictionary(); - +public class BeanProvider implements JavaBeanProvider { + + /** + * @deprecated As of 1.4.6 + */ + @Deprecated protected static final Object[] NO_PARAMS = new Object[0]; + protected PropertyDictionary propertyDictionary; - public Object newInstance(Class type) { + /** + * Construct a BeanProvider that will process the bean properties in their natural order. + */ + public BeanProvider() { + this(new PropertyDictionary(new NativePropertySorter())); + } + + /** + * Construct a BeanProvider with a comparator to sort the bean properties by name in the dictionary. + * + * @param propertyNameComparator the comparator + */ + public BeanProvider(final Comparator propertyNameComparator) { + this(new PropertyDictionary(new ComparingPropertySorter(propertyNameComparator))); + } + + /** + * Construct a BeanProvider with a provided property dictionary. + * + * @param propertyDictionary the property dictionary to use + * @since 1.4 + */ + public BeanProvider(final PropertyDictionary propertyDictionary) { + this.propertyDictionary = propertyDictionary; + } + + @Override + public Object newInstance(final Class type) { try { - return getDefaultConstrutor(type).newInstance(NO_PARAMS); - } catch (InstantiationException e) { + return type.newInstance(); + } catch (final InstantiationException e) { throw new ObjectAccessException("Cannot construct " + type.getName(), e); - } catch (IllegalAccessException e) { + } catch (final IllegalAccessException e) { throw new ObjectAccessException("Cannot construct " + type.getName(), e); - } catch (InvocationTargetException e) { - if (e.getTargetException() instanceof RuntimeException) { - throw (RuntimeException) e.getTargetException(); - } else if (e.getTargetException() instanceof Error) { - throw (Error) e.getTargetException(); - } else { - throw new ObjectAccessException("Constructor for " + type.getName() - + " threw an exception", e); - } + } catch (final SecurityException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (final ExceptionInInitializerError e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); } } -// private Object instantiateUsingSerialization(Class type) { -// try { -// byte[] data; -// if (serializedDataCache.containsKey(type)) { -// data = (byte[]) serializedDataCache.get(type); -// } else { -// ByteArrayOutputStream bytes = new ByteArrayOutputStream(); -// DataOutputStream stream = new DataOutputStream(bytes); -// stream.writeShort(ObjectStreamConstants.STREAM_MAGIC); -// stream.writeShort(ObjectStreamConstants.STREAM_VERSION); -// stream.writeByte(ObjectStreamConstants.TC_OBJECT); -// stream.writeByte(ObjectStreamConstants.TC_CLASSDESC); -// stream.writeUTF(type.getName()); -// stream.writeLong(ObjectStreamClass.lookup(type).getSerialVersionUID()); -// stream.writeByte(2); // classDescFlags (2 = Serializable) -// stream.writeShort(0); // field count -// stream.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); -// stream.writeByte(ObjectStreamConstants.TC_NULL); -// data = bytes.toByteArray(); -// serializedDataCache.put(type, data); -// } -// -// ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data)); -// return in.readObject(); -// } catch (IOException e) { -// throw new ObjectAccessException("", e); -// } catch (ClassNotFoundException e) { -// throw new ObjectAccessException("", e); -// } -// } - - public void visitSerializableProperties(Object object, Visitor visitor) { - for (Iterator iterator = propertyDictionary.serializablePropertiesFor(object.getClass()); iterator - .hasNext();) { - BeanProperty property = (BeanProperty) iterator.next(); + @Override + public void visitSerializableProperties(final Object object, final JavaBeanProvider.Visitor visitor) { + final PropertyDescriptor[] propertyDescriptors = getSerializableProperties(object); + for (final PropertyDescriptor property : propertyDescriptors) { try { - Object value = property.get(object); - visitor.visit(property.getName(), property.getType(), value); - } catch (IllegalArgumentException e) { - throw new ObjectAccessException("Could not get property " + property.getClass() - + "." + property.getName(), e); - } catch (IllegalAccessException e) { - throw new ObjectAccessException("Could not get property " + property.getClass() - + "." + property.getName(), e); + final Method readMethod = property.getReadMethod(); + final String name = property.getName(); + final Class definedIn = readMethod.getDeclaringClass(); + if (visitor.shouldVisit(name, definedIn)) { + final Object value = readMethod.invoke(object); + visitor.visit(name, property.getPropertyType(), definedIn, value); + } + } catch (final IllegalArgumentException e) { + throw new ObjectAccessException("Could not get property " + + object.getClass() + + "." + + property.getName(), e); + } catch (final IllegalAccessException e) { + throw new ObjectAccessException("Could not get property " + + object.getClass() + + "." + + property.getName(), e); + } catch (final InvocationTargetException e) { + throw new ObjectAccessException("Could not get property " + + object.getClass() + + "." + + property.getName(), e); } } } - public void writeProperty(Object object, String propertyName, Object value) { - BeanProperty property = propertyDictionary.property(object.getClass(), propertyName); + @Override + public void writeProperty(final Object object, final String propertyName, final Object value) { + final PropertyDescriptor property = getProperty(propertyName, object.getClass()); try { - property.set(object, value); - } catch (IllegalArgumentException e) { - throw new ObjectAccessException("Could not set property " + object.getClass() + "." - + property.getName(), e); - } catch (IllegalAccessException e) { - throw new ObjectAccessException("Could not set property " + object.getClass() + "." - + property.getName(), e); + property.getWriteMethod().invoke(object, new Object[]{value}); + } catch (final IllegalArgumentException e) { + throw new ObjectAccessException("Could not set property " + object.getClass() + "." + property.getName(), e); + } catch (final IllegalAccessException e) { + throw new ObjectAccessException("Could not set property " + object.getClass() + "." + property.getName(), e); + } catch (final InvocationTargetException e) { + throw new ObjectAccessException("Could not set property " + object.getClass() + "." + property.getName(), e); } } - public Class getPropertyType(Object object, String name) { - return propertyDictionary.property(object.getClass(), name).getType(); + @Override + public Class getPropertyType(final Object object, final String name) { + return getProperty(name, object.getClass()).getPropertyType(); } - public boolean propertyDefinedInClass(String name, Class type) { - return propertyDictionary.property(type, name) != null; + @Override + public boolean propertyDefinedInClass(final String name, final Class type) { + return getProperty(name, type) != null; } /** * Returns true if the Bean provider can instantiate the specified class */ - public boolean canInstantiate(Class type) { - return getDefaultConstrutor(type) != null; + @Override + public boolean canInstantiate(final Class type) { + try { + return newInstance(type) != null; + } catch (final ObjectAccessException e) { + return false; + } } - + /** * Returns the default constructor, or null if none is found + * * @param type - * @return + * @deprecated As of 1.4.6 use {@link #newInstance(Class)} or {@link #canInstantiate(Class)} directly. */ - protected Constructor getDefaultConstrutor(Class type) { - Constructor[] constructors = type.getConstructors(); - for (int i = 0; i < constructors.length; i++) { - Constructor c = constructors[i]; - if (c.getParameterTypes().length == 0 && Modifier.isPublic(c.getModifiers())) + @Deprecated + protected Constructor getDefaultConstrutor(final Class type) { + + final Constructor[] constructors = type.getConstructors(); + for (final Constructor c : constructors) { + if (c.getParameterTypes().length == 0 && Modifier.isPublic(c.getModifiers())) { return c; + } } return null; } - - interface Visitor { - void visit(String name, Class type, Object value); + + protected PropertyDescriptor[] getSerializableProperties(final Object object) { + final List result = new ArrayList(); + for (final Iterator iter = propertyDictionary.propertiesFor(object.getClass()); iter + .hasNext();) { + final PropertyDescriptor descriptor = iter.next(); + if (canStreamProperty(descriptor)) { + result.add(descriptor); + } + } + return result.toArray(new PropertyDescriptor[result.size()]); } -} \ No newline at end of file + protected boolean canStreamProperty(final PropertyDescriptor descriptor) { + return descriptor.getReadMethod() != null && descriptor.getWriteMethod() != null; + } + + public boolean propertyWriteable(final String name, final Class type) { + final PropertyDescriptor property = getProperty(name, type); + return property.getWriteMethod() != null; + } + + protected PropertyDescriptor getProperty(final String name, final Class type) { + return propertyDictionary.propertyDescriptor(type, name); + } + + /** + * @deprecated As of 1.4 use {@link JavaBeanProvider.Visitor} + */ + @Deprecated + public interface Visitor extends JavaBeanProvider.Visitor {} +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/ComparingPropertySorter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/ComparingPropertySorter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/ComparingPropertySorter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011, 2014 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 16. July 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.javabean; + +import java.beans.PropertyDescriptor; +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; + + +/** + * A sorter that uses a comparator to determine the order of the bean properties. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class ComparingPropertySorter implements PropertySorter { + + private final Comparator comparator; + + public ComparingPropertySorter(final Comparator propertyNameComparator) { + comparator = propertyNameComparator; + } + + @Override + public Map sort(final Class type, final Map nameMap) { + final TreeMap map = new TreeMap(comparator); + map.putAll(nameMap); + return map; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/JavaBeanConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/JavaBeanConverter.java (.../JavaBeanConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/JavaBeanConverter.java (.../JavaBeanConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,116 +1,167 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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 12. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.converters.javabean; -import com.thoughtworks.xstream.alias.ClassMapper; +import java.util.HashSet; +import java.util.Set; + import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.reflection.MissingFieldException; +import com.thoughtworks.xstream.core.util.FastField; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + /** - * Can convert any bean with a public default constructor. BeanInfo are not - * taken into consideration, this class looks for bean patterns for simple - * properties + * Can convert any bean with a public default constructor. The {@link BeanProvider} used as default is based on + * {@link java.beans.BeanInfo}. Indexed properties are currently not supported. */ public class JavaBeanConverter implements Converter { - /** - * TODO: - * - use bean introspection instead of reflection. - * - support indexed properties - * - ignore default values - * - use BeanInfo - */ - private ClassMapper classMapper; + /* TODO: - support indexed properties - support attributes (XSTR-620) - support local converters (XSTR-601) Problem: + * Mappers take definitions based on reflection, they don't know about bean info */ + protected final Mapper mapper; + protected final JavaBeanProvider beanProvider; + private final Class type; - private String classAttributeIdentifier; + public JavaBeanConverter(final Mapper mapper) { + this(mapper, (Class)null); + } - private BeanProvider beanProvider; + public JavaBeanConverter(final Mapper mapper, final Class type) { + this(mapper, new BeanProvider(), type); + } - public JavaBeanConverter(ClassMapper classMapper, String classAttributeIdentifier) { - this.classMapper = classMapper; - this.classAttributeIdentifier = classAttributeIdentifier; - this.beanProvider = new BeanProvider(); + public JavaBeanConverter(final Mapper mapper, final JavaBeanProvider beanProvider) { + this(mapper, beanProvider, null); } + public JavaBeanConverter(final Mapper mapper, final JavaBeanProvider beanProvider, final Class type) { + this.mapper = mapper; + this.beanProvider = beanProvider; + this.type = type; + } + /** - * Only checks for the availability of a public default constructor. - * If you need stricter checks, subclass JavaBeanConverter + * Checks if the bean provider can instantiate this type. If you need less strict checks, subclass JavaBeanConverter */ - public boolean canConvert(Class type) { - return beanProvider.canInstantiate(type); + @Override + public boolean canConvert(final Class type) { + return (this.type == null || this.type == type) && beanProvider.canInstantiate(type); } + @Override public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final String classAttributeName = mapper.aliasForSystemAttribute("class"); + beanProvider.visitSerializableProperties(source, new JavaBeanProvider.Visitor() { + @Override + public boolean shouldVisit(final String name, final Class definedIn) { + return mapper.shouldSerializeMember(definedIn, name); + } - beanProvider.visitSerializableProperties(source, new BeanProvider.Visitor() { - public void visit(String propertyName, Class fieldType, Object newObj) { + @Override + public void visit(final String propertyName, final Class fieldType, final Class definedIn, + final Object newObj) { if (newObj != null) { - writeField(propertyName, fieldType, newObj); + writeField(propertyName, fieldType, newObj, definedIn); } } - private void writeField(String propertyName, Class fieldType, Object newObj) { - writer.startNode(classMapper.serializedMember(source.getClass(), propertyName)); - - Class actualType = newObj.getClass(); - - Class defaultType = classMapper.defaultImplementationOf(fieldType); - if (!actualType.equals(defaultType)) { - writer.addAttribute(classAttributeIdentifier, classMapper.serializedClass(actualType)); + private void writeField(final String propertyName, final Class fieldType, final Object newObj, + final Class definedIn) { + final Class actualType = newObj.getClass(); + final Class defaultType = mapper.defaultImplementationOf(fieldType); + final String serializedMember = mapper.serializedMember(source.getClass(), propertyName); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, serializedMember, actualType); + if (!actualType.equals(defaultType) && classAttributeName != null) { + writer.addAttribute(classAttributeName, mapper.serializedClass(actualType)); } context.convertAnother(newObj); writer.endNode(); } - }); } + @Override public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { final Object result = instantiateNewInstance(context); + final Set seenProperties = new HashSet() { + @Override + public boolean add(final FastField e) { + if (!super.add(e)) { + throw new DuplicatePropertyException(e.getName()); + } + return true; + } + }; + final Class resultType = result.getClass(); while (reader.hasMoreChildren()) { reader.moveDown(); - String propertyName = classMapper.realMember(result.getClass(), reader.getNodeName()); + final String propertyName = mapper.realMember(resultType, reader.getNodeName()); - boolean propertyExistsInClass = beanProvider.propertyDefinedInClass(propertyName, result.getClass()); + if (mapper.shouldSerializeMember(resultType, propertyName)) { + final boolean propertyExistsInClass = beanProvider.propertyDefinedInClass(propertyName, resultType); - Class type = determineType(reader, result, propertyName); - Object value = context.convertAnother(result, type); - - if (propertyExistsInClass) { - beanProvider.writeProperty(result, propertyName, value); + if (propertyExistsInClass) { + final Class type = determineType(reader, result, propertyName); + final Object value = context.convertAnother(result, type); + beanProvider.writeProperty(result, propertyName, value); + seenProperties.add(new FastField(resultType, propertyName)); + } else { + throw new MissingFieldException(resultType.getName(), propertyName); + } } - reader.moveUp(); } return result; } - private Object instantiateNewInstance(UnmarshallingContext context) { + private Object instantiateNewInstance(final UnmarshallingContext context) { Object result = context.currentObject(); if (result == null) { result = beanProvider.newInstance(context.getRequiredType()); } return result; } - private Class determineType(HierarchicalStreamReader reader, Object result, String fieldName) { - String classAttribute = reader.getAttribute(classAttributeIdentifier); + private Class determineType(final HierarchicalStreamReader reader, final Object result, final String fieldName) { + final String classAttributeName = mapper.aliasForSystemAttribute("class"); + final String classAttribute = classAttributeName == null ? null : reader.getAttribute(classAttributeName); if (classAttribute != null) { - return classMapper.realClass(classAttribute); + return mapper.realClass(classAttribute); } else { - return classMapper.defaultImplementationOf(beanProvider.getPropertyType(result, fieldName)); + return mapper.defaultImplementationOf(beanProvider.getPropertyType(result, fieldName)); } } - public static class DuplicateFieldException extends ConversionException { - public DuplicateFieldException(String msg) { - super(msg); + /** + * Exception to indicate double processing of a property to avoid silent clobbering. + * + * @author Jörg Schaible + * @since 1.4.2 + */ + public static class DuplicatePropertyException extends ConversionException { + public DuplicatePropertyException(final String msg) { + super("Duplicate property " + msg); + add("property", msg); } } -} \ No newline at end of file +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/JavaBeanProvider.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/JavaBeanProvider.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/JavaBeanProvider.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011, 2014 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 07. July 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.javabean; + +/** + * @author Jörg Schaible + * @since 1.4 + */ +public interface JavaBeanProvider { + + Object newInstance(Class type); + + void visitSerializableProperties(Object object, Visitor visitor); + + void writeProperty(Object object, String propertyName, Object value); + + Class getPropertyType(Object object, String name); + + boolean propertyDefinedInClass(String name, Class type); + + /** + * Returns true if the Bean provider can instantiate the specified class + */ + boolean canInstantiate(Class type); + + public interface Visitor { + boolean shouldVisit(String name, Class definedIn); + + void visit(String name, Class type, Class definedIn, Object value); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/NativePropertySorter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/NativePropertySorter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/NativePropertySorter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011, 2014 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 16. July 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.javabean; + +import java.beans.PropertyDescriptor; +import java.util.Map; + + +/** + * A sorter that keeps the natural order of the bean properties as they are returned by the JavaBean introspection. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class NativePropertySorter implements PropertySorter { + + @Override + public Map sort(final Class type, final Map nameMap) { + return nameMap; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/PropertyDictionary.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/PropertyDictionary.java (.../PropertyDictionary.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/PropertyDictionary.java (.../PropertyDictionary.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,199 +1,127 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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 12. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.converters.javabean; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; import java.beans.Introspector; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; +import java.beans.PropertyDescriptor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; -import java.util.List; +import java.util.LinkedHashMap; import java.util.Map; +import com.thoughtworks.xstream.converters.reflection.MissingFieldException; import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; +import com.thoughtworks.xstream.core.Caching; + /** - * Builds the serializable properties maps for each bean and caches them. + * Builds the properties maps for each bean and caches them. + * + * @author Joe Walnes + * @author Jörg Schaible */ -public class PropertyDictionary { +public class PropertyDictionary implements Caching { + private transient Map, Map> propertyNameCache = Collections + .synchronizedMap(new HashMap, Map>()); + private final PropertySorter sorter; - private final Map keyedByPropertyNameCache = Collections.synchronizedMap(new HashMap()); + public PropertyDictionary() { + this(new NativePropertySorter()); + } - public Iterator serializablePropertiesFor(Class cls) { - return buildMap(cls).values().iterator(); + public PropertyDictionary(final PropertySorter sorter) { + this.sorter = sorter; } /** - * Locates a serializable property - * - * @param cls - * @param name - * @param definedIn - * @return + * @deprecated As of 1.3.1, use {@link #propertiesFor(Class)} instead */ - public BeanProperty property(Class cls, String name) { - Map properties = buildMap(cls); - BeanProperty property = (BeanProperty) properties.get(name); - if (property == null) { - throw new ObjectAccessException("No such property " + cls.getName() + "." + name); - } else { - return property; + @Deprecated + public Iterator serializablePropertiesFor(final Class type) { + final Collection beanProperties = new ArrayList(); + final Collection descriptors = buildMap(type).values(); + for (final PropertyDescriptor descriptor : descriptors) { + if (descriptor.getReadMethod() != null && descriptor.getWriteMethod() != null) { + beanProperties.add(new BeanProperty(type, descriptor.getName(), descriptor.getPropertyType())); + } } + return beanProperties.iterator(); } /** - * Builds the map of all serializable properties for the the provided bean + * Locates a serializable property. * * @param cls - * @param tupleKeyed - * @return + * @param name + * @deprecated As of 1.3.1, use {@link #propertyDescriptor(Class, String)} instead */ - private Map buildMap(Class cls) { - final String clsName = cls.getName(); - if (!keyedByPropertyNameCache.containsKey(clsName)) { - synchronized (keyedByPropertyNameCache) { - if (!keyedByPropertyNameCache.containsKey(clsName)) { // double check - // Gather all the properties, using only the keyed map. It - // is possible that a class have two writable only - // properties that have the same name - // but different types - final Map propertyMap = new HashMap(); - Method[] methods = cls.getMethods(); - - for (int i = 0; i < methods.length; i++) { - if (!Modifier.isPublic(methods[i].getModifiers()) - || Modifier.isStatic(methods[i].getModifiers())) - continue; - - String methodName = methods[i].getName(); - Class[] parameters = methods[i].getParameterTypes(); - Class returnType = methods[i].getReturnType(); - String propertyName; - if ((methodName.startsWith("get") || methodName.startsWith("is")) - && parameters.length == 0 && returnType != void.class) { - if (methodName.startsWith("get")) { - propertyName = Introspector.decapitalize(methodName.substring(3)); - } else { - propertyName = Introspector.decapitalize(methodName.substring(2)); - } - BeanProperty property = getBeanProperty(propertyMap, cls, propertyName, - returnType); - property.setGetterMethod(methods[i]); - } else if (methodName.startsWith("set") && parameters.length == 1 - && returnType == void.class) { - propertyName = Introspector.decapitalize(methodName.substring(3)); - BeanProperty property = getBeanProperty(propertyMap, cls, propertyName, - parameters[0]); - property.setSetterMethod(methods[i]); - } - } - - // retain only those that can be both read and written and - // sort them by name - List serializableProperties = new ArrayList(); - for (Iterator it = propertyMap.values().iterator(); it.hasNext();) { - BeanProperty property = (BeanProperty) it.next(); - if (property.isReadable() && property.isWritable()) { - serializableProperties.add(property); - } - } - Collections.sort(serializableProperties, new BeanPropertyComparator()); - - // build the maps and return - final Map keyedByFieldName = new OrderRetainingMap(); - for (Iterator it = serializableProperties.iterator(); it.hasNext();) { - BeanProperty property = (BeanProperty) it.next(); - keyedByFieldName.put(property.getName(), property); - } - - keyedByPropertyNameCache.put(clsName, keyedByFieldName); - } - } + @Deprecated + public BeanProperty property(final Class cls, final String name) { + BeanProperty beanProperty = null; + final PropertyDescriptor descriptor = buildMap(cls).get(name); + if (descriptor == null) { + throw new MissingFieldException(cls.getName(), name); } - return (Map) keyedByPropertyNameCache.get(clsName); - } - - private BeanProperty getBeanProperty(Map propertyMap, Class cls, String propertyName, Class type) { - PropertyKey key = new PropertyKey(propertyName, type); - BeanProperty property = (BeanProperty) propertyMap.get(key); - if (property == null) { - property = new BeanProperty(cls, propertyName, type); - propertyMap.put(key, property); + if (descriptor.getReadMethod() != null && descriptor.getWriteMethod() != null) { + beanProperty = new BeanProperty(cls, descriptor.getName(), descriptor.getPropertyType()); } - return property; + return beanProperty; } - /** - * Needed to avoid problems with multiple setters with the same name, but - * referred to different types - */ - private static class PropertyKey { - private String propertyName; - - private Class propertyType; - - public PropertyKey(String propertyName, Class propertyType) { - this.propertyName = propertyName; - this.propertyType = propertyType; - } - - public boolean equals(Object o) { - if (this == o) - return true; - if (!(o instanceof PropertyKey)) - return false; - - final PropertyKey propertyKey = (PropertyKey) o; - - if (propertyName != null ? !propertyName.equals(propertyKey.propertyName) - : propertyKey.propertyName != null) - return false; - if (propertyType != null ? !propertyType.equals(propertyKey.propertyType) - : propertyKey.propertyType != null) - return false; - - return true; - } - - public int hashCode() { - int result; - result = (propertyName != null ? propertyName.hashCode() : 0); - result = 29 * result + (propertyType != null ? propertyType.hashCode() : 0); - return result; - } - - public String toString() { - return "PropertyKey{propertyName='" + propertyName + "'" + ", propertyType=" - + propertyType + "}"; - } - + public Iterator propertiesFor(final Class type) { + return buildMap(type).values().iterator(); } /** - * Compares properties by name + * Locates a property descriptor. + * + * @param type + * @param name */ - private static class BeanPropertyComparator implements Comparator { - - public int compare(Object o1, Object o2) { - return ((BeanProperty) o1).getName().compareTo(((BeanProperty) o2).getName()); + public PropertyDescriptor propertyDescriptor(final Class type, final String name) { + final PropertyDescriptor descriptor = buildMap(type).get(name); + if (descriptor == null) { + throw new MissingFieldException(type.getName(), name); } - + return descriptor; } - private static class OrderRetainingMap extends HashMap { - - private List valueOrder = new ArrayList(); - - public Object put(Object key, Object value) { - valueOrder.add(value); - return super.put(key, value); + private Map buildMap(final Class type) { + Map nameMap = propertyNameCache.get(type); + if (nameMap == null) { + BeanInfo beanInfo; + try { + beanInfo = Introspector.getBeanInfo(type, Object.class); + } catch (final IntrospectionException e) { + throw new ObjectAccessException("Cannot get BeanInfo of type " + type.getName(), e); + } + nameMap = new LinkedHashMap(); + final PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + for (final PropertyDescriptor descriptor : propertyDescriptors) { + nameMap.put(descriptor.getName(), descriptor); + } + nameMap = sorter.sort(type, nameMap); + propertyNameCache.put(type, nameMap); } - - public Collection values() { - return Collections.unmodifiableList(valueOrder); - } + return nameMap; } -} \ No newline at end of file + @Override + public void flushCache() { + propertyNameCache.clear(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/PropertySorter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/PropertySorter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/javabean/PropertySorter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011, 2014 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 16. July 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.javabean; + +import java.beans.PropertyDescriptor; +import java.util.Map; + + +/** + * An interface capable of sorting Java bean properties. + *

+ * Implement this interface if you want to customize the order in which XStream serializes the properties of a bean. + *

+ * + * @author Jörg Schaible + * @since 1.4 + */ +public interface PropertySorter { + + /** + * Sort the properties of a bean type. + *

+ * The method will be called with the class type that contains all the properties and a Map that retains the order + * in which the elements have been added. The sequence in which elements are returned by an iterator defines the + * processing order of the properties. An implementation may create a different Map with similar semantic, add all + * elements of the original map and return the new one. + *

+ * + * @param type the bean class that contains all the properties + * @param nameMap the map to sort, key is the property name, value the {@link PropertyDescriptor} + * @return the sorted nameMap + * @since 1.4 + */ + Map sort(Class type, Map nameMap); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/AbstractAttributedCharacterIteratorAttributeConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/AbstractAttributedCharacterIteratorAttributeConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/AbstractAttributedCharacterIteratorAttributeConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2007, 2013, 2014 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 01. February 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.text.AttributedCharacterIterator; +import java.util.HashMap; +import java.util.Map; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; +import com.thoughtworks.xstream.core.util.Fields; + + +/** + * An abstract converter implementation for constants of {@link java.text.AttributedCharacterIterator.Attribute} and + * derived types. + * + * @author Jörg Schaible + * @since 1.2.2 + */ +public class AbstractAttributedCharacterIteratorAttributeConverter + extends AbstractSingleValueConverter { + + private static final Map> instanceMaps = new HashMap>(); + private static final Method getName; + static { + Method method = null; + try { + method = AttributedCharacterIterator.Attribute.class.getDeclaredMethod("getName", (Class[])null); + if (!method.isAccessible()) { + method.setAccessible(true); + } + } catch (final SecurityException e) { + // ignore for now + } catch (final NoSuchMethodException e) { + // ignore for now + } + getName = method; + } + + private final Class type; + private transient Map attributeMap; + + public AbstractAttributedCharacterIteratorAttributeConverter(final Class type) { + super(); + if (!AttributedCharacterIterator.Attribute.class.isAssignableFrom(type)) { + throw new IllegalArgumentException(type.getName() + + " is not a " + + AttributedCharacterIterator.Attribute.class.getName()); + } + this.type = type; + readResolve(); + } + + @Override + public boolean canConvert(final Class type) { + return type == this.type && !attributeMap.isEmpty(); + } + + @Override + public String toString(final Object source) { + @SuppressWarnings("unchecked") + final T t = (T)source; + return getName(t); + } + + private String getName(final AttributedCharacterIterator.Attribute attribute) { + Exception ex = null; + if (getName != null) { + try { + return (String)getName.invoke(attribute); + } catch (final IllegalAccessException e) { + ex = e; + } catch (final InvocationTargetException e) { + ex = e; + } + } + final String s = attribute.toString(); + final String className = attribute.getClass().getName(); + if (s.startsWith(className)) { + return s.substring(className.length() + 1, s.length() - 1); + } + throw new ConversionException("Cannot find name of attribute of type " + className, ex); + } + + @Override + public Object fromString(final String str) { + if (attributeMap.containsKey(str)) { + return attributeMap.get(str); + } + throw new ConversionException("Cannot find attribute of type " + type.getName() + " with name " + str); + } + + private Object readResolve() { + @SuppressWarnings("unchecked") + final Map typedMap = (Map)instanceMaps.get(type.getName()); + attributeMap = typedMap; + if (attributeMap == null) { + attributeMap = new HashMap(); + final Field instanceMap = Fields.locate(type, Map.class, true); + if (instanceMap != null) { + try { + @SuppressWarnings("unchecked") + final Map map = (Map)Fields.read(instanceMap, null); + if (map != null) { + boolean valid = true; + for (final Map.Entry entry : map.entrySet()) { + valid = entry.getKey().getClass() == String.class && entry.getValue().getClass() == type; + } + if (valid) { + attributeMap.putAll(map); + } + } + } catch (final ObjectAccessException e) { + } + } + if (attributeMap.isEmpty()) { + try { + final Field[] fields = type.getDeclaredFields(); + for (final Field field : fields) { + if (field.getType() == type == Modifier.isStatic(field.getModifiers())) { + @SuppressWarnings("unchecked") + final T attribute = (T)Fields.read(field, null); + attributeMap.put(toString(attribute), attribute); + } + } + } catch (final SecurityException e) { + attributeMap.clear(); + } catch (final ObjectAccessException e) { + attributeMap.clear(); + } catch (final NoClassDefFoundError e) { + attributeMap.clear(); + } + } + instanceMaps.put(type.getName(), attributeMap); + } + return this; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,652 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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 02. March 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.Caching; +import com.thoughtworks.xstream.core.ReferencingMarshallingContext; +import com.thoughtworks.xstream.core.util.ArrayIterator; +import com.thoughtworks.xstream.core.util.FastField; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.core.util.Primitives; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.CannotResolveClassException; +import com.thoughtworks.xstream.mapper.Mapper; + + +public abstract class AbstractReflectionConverter implements Converter, Caching { + + protected final ReflectionProvider reflectionProvider; + protected final Mapper mapper; + protected transient SerializationMethodInvoker serializationMethodInvoker; + private transient ReflectionProvider pureJavaReflectionProvider; + + public AbstractReflectionConverter(final Mapper mapper, final ReflectionProvider reflectionProvider) { + this.mapper = mapper; + this.reflectionProvider = reflectionProvider; + serializationMethodInvoker = new SerializationMethodInvoker(); + } + + protected boolean canAccess(final Class type) { + try { + reflectionProvider.getFieldOrNull(type, "%"); + return true; + } catch (final NoClassDefFoundError e) { + // restricted type in GAE + } + return false; + } + + @Override + public void marshal(final Object original, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Object source = serializationMethodInvoker.callWriteReplace(original); + + if (source != original && context instanceof ReferencingMarshallingContext) { + ((ReferencingMarshallingContext)context).replace(original, source); + } + if (source.getClass() != original.getClass()) { + final String attributeName = mapper.aliasForSystemAttribute("resolves-to"); + if (attributeName != null) { + writer.addAttribute(attributeName, mapper.serializedClass(source.getClass())); + } + context.convertAnother(source); + } else { + doMarshal(source, writer, context); + } + } + + protected void doMarshal(final Object source, final HierarchicalStreamWriter writer, + final MarshallingContext context) { + final List fields = new ArrayList(); + final Map defaultFieldDefinition = new HashMap(); + + // Attributes might be preferred to child elements ... + reflectionProvider.visitSerializableFields(source, new ReflectionProvider.Visitor() { + final Set writtenAttributes = new HashSet(); + + @Override + public void visit(final String fieldName, final Class type, final Class definedIn, final Object value) { + if (!mapper.shouldSerializeMember(definedIn, fieldName)) { + return; + } + if (!defaultFieldDefinition.containsKey(fieldName)) { + Class lookupType = source.getClass(); + // See XSTR-457 and OmitFieldsTest + if (definedIn != source.getClass() && !mapper.shouldSerializeMember(lookupType, fieldName)) { + lookupType = definedIn; + } + defaultFieldDefinition.put(fieldName, reflectionProvider.getField(lookupType, fieldName)); + } + + final SingleValueConverter converter = mapper.getConverterFromItemType(fieldName, type, definedIn); + if (converter != null) { + final String attribute = mapper.aliasForAttribute(mapper.serializedMember(definedIn, fieldName)); + if (value != null) { + if (writtenAttributes.contains(fieldName)) { // TODO: use attribute + throw new ConversionException("Cannot write field with name '" + + fieldName + + "' twice as attribute for object of type " + + source.getClass().getName()); + } + final String str = converter.toString(value); + if (str != null) { + writer.addAttribute(attribute, str); + } + } + writtenAttributes.add(fieldName); // TODO: use attribute + } else { + fields.add(new FieldInfo(fieldName, type, definedIn, value)); + } + } + }); + + new Object() { + { + for (final FieldInfo fieldInfo : fields) { + final FieldInfo info = fieldInfo; + if (info.value != null) { + final Mapper.ImplicitCollectionMapping mapping = mapper.getImplicitCollectionDefForFieldName( + source.getClass(), info.fieldName); + if (mapping != null) { + if (context instanceof ReferencingMarshallingContext) { + if (info.value != Collections.EMPTY_LIST + && info.value != Collections.EMPTY_SET + && info.value != Collections.EMPTY_MAP) { + final ReferencingMarshallingContext refContext = (ReferencingMarshallingContext)context; + refContext.registerImplicit(info.value); + } + } + final boolean isCollection = info.value instanceof Collection; + final boolean isMap = info.value instanceof Map; + final boolean isEntry = isMap && mapping.getKeyFieldName() == null; + final boolean isArray = info.value.getClass().isArray(); + for (final Iterator iter = isArray ? new ArrayIterator(info.value) : isCollection + ? ((Collection)info.value).iterator() + : isEntry ? ((Map)info.value).entrySet().iterator() : ((Map)info.value) + .values() + .iterator(); iter.hasNext();) { + final Object obj = iter.next(); + final String itemName; + final Class itemType; + if (obj == null) { + itemType = Object.class; + itemName = mapper.serializedClass(null); + } else if (isEntry) { + final String entryName = mapping.getItemFieldName() != null ? mapping + .getItemFieldName() : mapper.serializedClass(Map.Entry.class); + final Map.Entry entry = (Map.Entry)obj; + ExtendedHierarchicalStreamWriterHelper.startNode(writer, entryName, entry + .getClass()); + writeItem(entry.getKey(), context, writer); + writeItem(entry.getValue(), context, writer); + writer.endNode(); + continue; + } else if (mapping.getItemFieldName() != null) { + itemType = mapping.getItemType(); + itemName = mapping.getItemFieldName(); + } else { + itemType = obj.getClass(); + itemName = mapper.serializedClass(itemType); + } + writeField(info.fieldName, itemName, itemType, info.definedIn, obj); + } + } else { + writeField(info.fieldName, null, info.type, info.definedIn, info.value); + } + } + } + + } + + void writeField(final String fieldName, final String aliasName, final Class fieldType, + final Class definedIn, final Object newObj) { + final Class actualType = newObj != null ? newObj.getClass() : fieldType; + ExtendedHierarchicalStreamWriterHelper.startNode(writer, aliasName != null ? aliasName : mapper + .serializedMember(source.getClass(), fieldName), actualType); + + if (newObj != null) { + final Class defaultType = mapper.defaultImplementationOf(fieldType); + if (!actualType.equals(defaultType)) { + final String serializedClassName = mapper.serializedClass(actualType); + if (!serializedClassName.equals(mapper.serializedClass(defaultType))) { + final String attributeName = mapper.aliasForSystemAttribute("class"); + if (attributeName != null) { + writer.addAttribute(attributeName, serializedClassName); + } + } + } + + final Field defaultField = defaultFieldDefinition.get(fieldName); + if (defaultField.getDeclaringClass() != definedIn) { + final String attributeName = mapper.aliasForSystemAttribute("defined-in"); + if (attributeName != null) { + writer.addAttribute(attributeName, mapper.serializedClass(definedIn)); + } + } + + final Field field = reflectionProvider.getField(definedIn, fieldName); + marshallField(context, newObj, field); + } + writer.endNode(); + } + + void writeItem(final Object item, final MarshallingContext context, final HierarchicalStreamWriter writer) { + if (item == null) { + final String name = mapper.serializedClass(null); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, Mapper.Null.class); + writer.endNode(); + } else { + final String name = mapper.serializedClass(item.getClass()); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, item.getClass()); + context.convertAnother(item); + writer.endNode(); + } + } + }; + } + + protected void marshallField(final MarshallingContext context, final Object newObj, final Field field) { + context.convertAnother(newObj, mapper.getLocalConverter(field.getDeclaringClass(), field.getName())); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + Object result = instantiateNewInstance(reader, context); + result = doUnmarshal(result, reader, context); + return serializationMethodInvoker.callReadResolve(result); + } + + public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader, + final UnmarshallingContext context) { + final Class resultType = result.getClass(); + final Set seenFields = new HashSet() { + @Override + public boolean add(final FastField e) { + if (!super.add(e)) { + throw new DuplicateFieldException(e.getName()); + } + return true; + } + }; + + // process attributes before recursing into child elements. + final Iterator it = reader.getAttributeNames(); + while (it.hasNext()) { + final String attrAlias = it.next(); + // TODO: realMember should return FastField + final String attrName = mapper.realMember(resultType, mapper.attributeForAlias(attrAlias)); + final Field field = reflectionProvider.getFieldOrNull(resultType, attrName); + if (field != null && shouldUnmarshalField(field)) { + final Class classDefiningField = field.getDeclaringClass(); + if (!mapper.shouldSerializeMember(classDefiningField, attrName)) { + continue; + } + + // we need a converter that produces a string representation only + final SingleValueConverter converter = mapper.getConverterFromAttribute(classDefiningField, attrName, + field.getType()); + Class type = field.getType(); + if (converter != null) { + final Object value = converter.fromString(reader.getAttribute(attrAlias)); + if (type.isPrimitive()) { + type = Primitives.box(type); + } + if (value != null && !type.isAssignableFrom(value.getClass())) { + throw new ConversionException("Cannot convert type " + + value.getClass().getName() + + " to type " + + type.getName()); + } + seenFields.add(new FastField(classDefiningField, attrName)); + reflectionProvider.writeField(result, attrName, value, classDefiningField); + } + } + } + + Map> implicitCollectionsForCurrentObject = null; + while (reader.hasMoreChildren()) { + reader.moveDown(); + + final String originalNodeName = reader.getNodeName(); + final Class explicitDeclaringClass = readDeclaringClass(reader); + final Class fieldDeclaringClass = explicitDeclaringClass == null ? resultType : explicitDeclaringClass; + final String fieldName = mapper.realMember(fieldDeclaringClass, originalNodeName); + final Mapper.ImplicitCollectionMapping implicitCollectionMapping = mapper + .getImplicitCollectionDefForFieldName(fieldDeclaringClass, fieldName); + final Object value; + String implicitFieldName = null; + Field field = null; + Class type = null; + if (implicitCollectionMapping == null) { + // no item of an implicit collection for this name ... do we have a field? + field = reflectionProvider.getFieldOrNull(fieldDeclaringClass, fieldName); + if (field == null) { + // it is not a field ... do we have a field alias? + final Class itemType = mapper.getItemTypeForItemFieldName(resultType, fieldName); + if (itemType != null) { + final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper); + if (classAttribute != null) { + type = mapper.realClass(classAttribute); + } else { + type = itemType; + } + } else { + // it is not an alias ... do we have an element of an implicit + // collection based on type only? + try { + type = mapper.realClass(originalNodeName); + implicitFieldName = mapper.getFieldNameForItemTypeAndName(context.getRequiredType(), type, + originalNodeName); + } catch (final CannotResolveClassException e) { + // type stays null ... + } + if (type == null || type != null && implicitFieldName == null) { + // either not a type or element is a type alias, but does not + // belong to an implicit field + handleUnknownField(explicitDeclaringClass, fieldName, resultType, originalNodeName); + + // element is unknown in declaring class, ignore it now + type = null; + } + } + if (type == null) { + // no type, no value + value = null; + } else { + if (Map.Entry.class.equals(type)) { + // it is an element of an implicit map with two elements now for + // key and value + reader.moveDown(); + final Object key = context.convertAnother(result, HierarchicalStreams.readClassType(reader, + mapper)); + reader.moveUp(); + reader.moveDown(); + final Object v = context.convertAnother(result, HierarchicalStreams.readClassType(reader, + mapper)); + reader.moveUp(); + value = Collections.singletonMap(key, v).entrySet().iterator().next(); + } else { + // recurse info hierarchy + value = context.convertAnother(result, type); + } + } + } else { + boolean fieldAlreadyChecked = false; + + // we have a field, but do we have to address a hidden one? + if (explicitDeclaringClass == null) { + while (field != null + && !(fieldAlreadyChecked = shouldUnmarshalField(field) + && mapper.shouldSerializeMember(field.getDeclaringClass(), fieldName))) { + field = reflectionProvider.getFieldOrNull(field.getDeclaringClass().getSuperclass(), + fieldName); + } + } + if (field != null + && (fieldAlreadyChecked || shouldUnmarshalField(field) + && mapper.shouldSerializeMember(field.getDeclaringClass(), fieldName))) { + + final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper); + if (classAttribute != null) { + type = mapper.realClass(classAttribute); + } else { + type = mapper.defaultImplementationOf(field.getType()); + } + // TODO the reflection provider should already return the proper field + value = unmarshallField(context, result, type, field); + final Class definedType = field.getType(); + if (!definedType.isPrimitive()) { + type = definedType; + } + } else { + value = null; + } + } + } else { + // we have an implicit collection with defined names + implicitFieldName = implicitCollectionMapping.getFieldName(); + type = implicitCollectionMapping.getItemType(); + if (type == null) { + final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper); + type = mapper.realClass(classAttribute != null ? classAttribute : originalNodeName); + } + value = context.convertAnother(result, type); + } + + if (value != null && !type.isAssignableFrom(value.getClass())) { + throw new ConversionException("Cannot convert type " + + value.getClass().getName() + + " to type " + + type.getName()); + } + + if (field != null) { + reflectionProvider.writeField(result, fieldName, value, field.getDeclaringClass()); + seenFields.add(new FastField(field.getDeclaringClass(), fieldName)); + } else if (type != null) { + if (implicitFieldName == null) { + // look for implicit field + implicitFieldName = mapper.getFieldNameForItemTypeAndName(context.getRequiredType(), value != null + ? value.getClass() + : Mapper.Null.class, originalNodeName); + } + if (implicitCollectionsForCurrentObject == null) { + implicitCollectionsForCurrentObject = new HashMap>(); + } + writeValueToImplicitCollection(value, implicitCollectionsForCurrentObject, result, implicitFieldName); + } + + reader.moveUp(); + } + + if (implicitCollectionsForCurrentObject != null) { + for (final Map.Entry> entry : implicitCollectionsForCurrentObject + .entrySet()) { + final Object value = entry.getValue(); + if (value instanceof ArraysList) { + final Object array = ((ArraysList)value).toPhysicalArray(); + reflectionProvider.writeField(result, entry.getKey(), array, null); + } + } + } + + return result; + } + + protected Object unmarshallField(final UnmarshallingContext context, final Object result, final Class type, + final Field field) { + return context.convertAnother(result, type, mapper + .getLocalConverter(field.getDeclaringClass(), field.getName())); + } + + protected boolean shouldUnmarshalTransientFields() { + return false; + } + + protected boolean shouldUnmarshalField(final Field field) { + return !(Modifier.isTransient(field.getModifiers()) && !shouldUnmarshalTransientFields()); + } + + private void handleUnknownField(final Class classDefiningField, final String fieldName, + final Class resultType, final String originalNodeName) { + if (classDefiningField == null) { + for (Class cls = resultType; cls != null; cls = cls.getSuperclass()) { + if (!mapper.shouldSerializeMember(cls, originalNodeName)) { + return; + } + } + } + throw new UnknownFieldException(resultType.getName(), fieldName); + } + + private void writeValueToImplicitCollection(final Object value, + final Map> implicitCollections, final Object result, + final String implicitFieldName) { + Collection collection = implicitCollections.get(implicitFieldName); + if (collection == null) { + final Class physicalFieldType = reflectionProvider.getFieldType(result, implicitFieldName, null); + if (physicalFieldType.isArray()) { + collection = new ArraysList(physicalFieldType); + } else { + final Class fieldType = mapper.defaultImplementationOf(physicalFieldType); + if (!(Collection.class.isAssignableFrom(fieldType) || Map.class.isAssignableFrom(fieldType))) { + throw new ObjectAccessException("Field " + + implicitFieldName + + " of " + + result.getClass().getName() + + " is configured for an implicit Collection or Map, but field is of type " + + fieldType.getName()); + } + if (pureJavaReflectionProvider == null) { + pureJavaReflectionProvider = new PureJavaReflectionProvider(); + } + final Object instance = pureJavaReflectionProvider.newInstance(fieldType); + if (instance instanceof Collection) { + @SuppressWarnings("unchecked") + final Collection uncheckedCollection = (Collection)instance; + collection = uncheckedCollection; + } else { + final Mapper.ImplicitCollectionMapping implicitCollectionMapping = mapper + .getImplicitCollectionDefForFieldName(result.getClass(), implicitFieldName); + @SuppressWarnings("unchecked") + final Map map = (Map)instance; + collection = new MappingList(map, implicitCollectionMapping.getKeyFieldName()); + } + reflectionProvider.writeField(result, implicitFieldName, instance, null); + } + implicitCollections.put(implicitFieldName, collection); + } + collection.add(value); + } + + private Class readDeclaringClass(final HierarchicalStreamReader reader) { + final String attributeName = mapper.aliasForSystemAttribute("defined-in"); + final String definedIn = attributeName == null ? null : reader.getAttribute(attributeName); + return definedIn == null ? null : mapper.realClass(definedIn); + } + + protected Object instantiateNewInstance(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String attributeName = mapper.aliasForSystemAttribute("resolves-to"); + final String readResolveValue = attributeName == null ? null : reader.getAttribute(attributeName); + final Object currentObject = context.currentObject(); + if (currentObject != null) { + return currentObject; + } else if (readResolveValue != null) { + return reflectionProvider.newInstance(mapper.realClass(readResolveValue)); + } else { + return reflectionProvider.newInstance(context.getRequiredType()); + } + } + + @Override + public void flushCache() { + serializationMethodInvoker.flushCache(); + } + + private Object readResolve() { + serializationMethodInvoker = new SerializationMethodInvoker(); + return this; + } + + public static class DuplicateFieldException extends ConversionException { + public DuplicateFieldException(final String msg) { + super("Duplicate field " + msg); + add("field", msg); + } + } + + public static class UnknownFieldException extends ConversionException { + public UnknownFieldException(final String type, final String field) { + super("No such field " + type + "." + field); + add("field", field); + } + } + + private static class FieldInfo { + final String fieldName; + final Class type; + final Class definedIn; + final Object value; + + FieldInfo(final String fieldName, final Class type, final Class definedIn, final Object value) { + this.fieldName = fieldName; + this.type = type; + this.definedIn = definedIn; + this.value = value; + } + } + + private static class ArraysList extends ArrayList { + final Class physicalFieldType; + + ArraysList(final Class physicalFieldType) { + this.physicalFieldType = physicalFieldType; + } + + Object toPhysicalArray() { + final Object[] objects = toArray(); + final Object array = Array.newInstance(physicalFieldType.getComponentType(), objects.length); + if (physicalFieldType.getComponentType().isPrimitive()) { + for (int i = 0; i < objects.length; ++i) { + Array.set(array, i, Array.get(objects, i)); + } + } else { + System.arraycopy(objects, 0, array, 0, objects.length); + } + return array; + } + } + + private class MappingList extends AbstractList { + + private final Map map; + private final String keyFieldName; + private final Map, Field> fieldCache = new HashMap, Field>(); + + public MappingList(final Map map, final String keyFieldName) { + this.map = map; + this.keyFieldName = keyFieldName; + } + + @Override + public boolean add(final Object object) { + if (object == null) { + final boolean containsNull = !map.containsKey(null); + map.put(null, null); + return containsNull; + } + final Class itemType = object.getClass(); + if (keyFieldName != null) { + Field field = fieldCache.get(itemType); + if (field == null) { + field = reflectionProvider.getField(itemType, keyFieldName); + fieldCache.put(itemType, field); + } + if (field != null) { + try { + final Object key = field.get(object); + return map.put(key, object) == null; + } catch (final IllegalArgumentException e) { + throw new ObjectAccessException("Could not get field " + + field.getClass() + + "." + + field.getName(), e); + } catch (final IllegalAccessException e) { + throw new ObjectAccessException("Could not get field " + + field.getClass() + + "." + + field.getName(), e); + } + } + } else if (object instanceof Map.Entry) { + @SuppressWarnings("unchecked") + final Map.Entry entry = (Map.Entry)object; + return map.put(entry.getKey(), entry.getValue()) == null; + } + + throw new ConversionException("Element of type " + + object.getClass().getName() + + " is not defined as entry for map of type " + + map.getClass().getName()); + } + + @Override + public Object get(final int index) { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + return map.size(); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014 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 13. April 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.ClassLoaderReference; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.CGLIBMapper; +import com.thoughtworks.xstream.mapper.Mapper; + +import net.sf.cglib.proxy.Callback; +import net.sf.cglib.proxy.CallbackFilter; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.Factory; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.NoOp; + + +/** + * Converts a proxy created by the CGLIB {@link Enhancer}. Such a proxy is recreated while deserializing the proxy. The + * converter does only work, if
+ *
    + *
  • the DefaultNamingPolicy is used for the proxy's name
  • + *
  • the proxy uses a factory or only one Callback is registered
  • + *
  • a possible super class has at least a protected default constructor
  • + *
+ * Note, that the this converter relies on the CGLIBMapper. + * + * @author Jörg Schaible + * @since 1.2 + */ +public class CGLIBEnhancedConverter extends SerializableConverter { + private static String DEFAULT_NAMING_MARKER = "$$EnhancerByCGLIB$$"; + private static String CALLBACK_MARKER = "CGLIB$CALLBACK_"; + private transient Map> fieldCache; + + /** + * Construct a CGLIBEnhancedConverter. + * + * @param mapper the mapper chain instance + * @param reflectionProvider the reflection provider + * @param classLoaderReference the reference to the {@link ClassLoader} of the XStream instance + * @since 1.4.5 + */ + public CGLIBEnhancedConverter( + final Mapper mapper, final ReflectionProvider reflectionProvider, + final ClassLoaderReference classLoaderReference) { + super(mapper, new CGLIBFilteringReflectionProvider(reflectionProvider), classLoaderReference); + fieldCache = new HashMap>(); + } + + /** + * @deprecated As of 1.4.5 use {@link #CGLIBEnhancedConverter(Mapper, ReflectionProvider, ClassLoaderReference)} + */ + @Deprecated + public CGLIBEnhancedConverter( + final Mapper mapper, final ReflectionProvider reflectionProvider, final ClassLoader classLoader) { + super(mapper, new CGLIBFilteringReflectionProvider(reflectionProvider), classLoader); + fieldCache = new HashMap>(); + } + + /** + * @deprecated As of 1.4 use {@link #CGLIBEnhancedConverter(Mapper, ReflectionProvider, ClassLoaderReference)} + */ + @Deprecated + public CGLIBEnhancedConverter(final Mapper mapper, final ReflectionProvider reflectionProvider) { + this(mapper, new CGLIBFilteringReflectionProvider(reflectionProvider), CGLIBEnhancedConverter.class + .getClassLoader()); + } + + @Override + public boolean canConvert(final Class type) { + return Enhancer.isEnhanced(type) + && type.getName().indexOf(DEFAULT_NAMING_MARKER) > 0 + || type == CGLIBMapper.Marker.class; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Class type = source.getClass(); + final boolean hasFactory = Factory.class.isAssignableFrom(type); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, "type", type); + context.convertAnother(type.getSuperclass()); + writer.endNode(); + writer.startNode("interfaces"); + final Class[] interfaces = type.getInterfaces(); + for (final Class interface1 : interfaces) { + if (interface1 == Factory.class) { + continue; + } + ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(interface1.getClass()), + interface1.getClass()); + context.convertAnother(interface1); + writer.endNode(); + } + writer.endNode(); + writer.startNode("hasFactory"); + writer.setValue(String.valueOf(hasFactory)); + writer.endNode(); + Map callbackIndexMap = null; + final Callback[] callbacks = hasFactory ? ((Factory)source).getCallbacks() : getCallbacks(source); + if (callbacks.length > 1) { + if (hasFactory) { + callbackIndexMap = createCallbackIndexMap((Factory)source); + } else { + final ConversionException exception = new ConversionException( + "Cannot handle CGLIB enhanced proxies without factory that have multiple callbacks"); + exception.add("proxy superclass", type.getSuperclass().getName()); + exception.add("number of callbacks", String.valueOf(callbacks.length)); + throw exception; + } + writer.startNode("callbacks"); + writer.startNode("mapping"); + context.convertAnother(callbackIndexMap); + writer.endNode(); + } + boolean hasInterceptor = false; + for (final Callback callback : callbacks) { + if (callback == null) { + final String name = mapper.serializedClass(null); + writer.startNode(name); + writer.endNode(); + } else { + hasInterceptor = hasInterceptor || MethodInterceptor.class.isAssignableFrom(callback.getClass()); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(callback.getClass()), + callback.getClass()); + context.convertAnother(callback); + writer.endNode(); + } + } + if (callbacks.length > 1) { + writer.endNode(); + } + try { + final Field field = type.getDeclaredField("serialVersionUID"); + if (!field.isAccessible()) { + field.setAccessible(true); + } + final long serialVersionUID = field.getLong(null); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, "serialVersionUID", String.class); + writer.setValue(String.valueOf(serialVersionUID)); + writer.endNode(); + } catch (final NoSuchFieldException e) { + // OK, ignore + } catch (final IllegalAccessException e) { + throw new ObjectAccessException("Access to serialVersionUID of " + type.getName() + " not allowed", e); + } + if (hasInterceptor) { + writer.startNode("instance"); + super.doMarshalConditionally(source, writer, context); + writer.endNode(); + } + } + + private Callback[] getCallbacks(final Object source) { + final Class type = source.getClass(); + List fields = fieldCache.get(type.getName()); + if (fields == null) { + fields = new ArrayList(); + fieldCache.put(type.getName(), fields); + for (int i = 0; true; ++i) { + try { + final Field field = type.getDeclaredField(CALLBACK_MARKER + i); + if (!field.isAccessible()) { + field.setAccessible(true); + } + fields.add(field); + } catch (final NoSuchFieldException e) { + break; + } + } + } + final List list = new ArrayList(); + for (int i = 0; i < fields.size(); ++i) { + try { + final Field field = fields.get(i); + final Callback callback = (Callback)field.get(source); + list.add(callback); + } catch (final IllegalAccessException e) { + throw new ObjectAccessException("Access to " + + type.getName() + + "." + + CALLBACK_MARKER + + i + + " not allowed", e); + } + } + return list.toArray(new Callback[list.size()]); + } + + private Map createCallbackIndexMap(final Factory source) { + final Callback[] originalCallbacks = source.getCallbacks(); + final Callback[] reverseEngineeringCallbacks = new Callback[originalCallbacks.length]; + final Map callbackIndexMap = new HashMap(); + int idxNoOp = -1; + for (int i = 0; i < originalCallbacks.length; i++) { + final Callback callback = originalCallbacks[i]; + if (callback == null) { + reverseEngineeringCallbacks[i] = null; + } else if (NoOp.class.isAssignableFrom(callback.getClass())) { + reverseEngineeringCallbacks[i] = NoOp.INSTANCE; + idxNoOp = i; + } else { + reverseEngineeringCallbacks[i] = createReverseEngineeredCallbackOfProperType(callback, i, + callbackIndexMap); + } + } + + try { + source.setCallbacks(reverseEngineeringCallbacks); + final Set> interfaces = new HashSet>(); + final Set methods = new HashSet(); + Class type = source.getClass(); + do { + methods.addAll(Arrays.asList(type.getDeclaredMethods())); + methods.addAll(Arrays.asList(type.getMethods())); + final Class[] implementedInterfaces = type.getInterfaces(); + interfaces.addAll(Arrays.asList(implementedInterfaces)); + type = type.getSuperclass(); + } while (type != null); + for (final Iterator> iterator = interfaces.iterator(); iterator.hasNext();) { + type = iterator.next(); + methods.addAll(Arrays.asList(type.getDeclaredMethods())); + } + for (final Iterator iter = methods.iterator(); iter.hasNext();) { + final Method method = iter.next(); + if (!method.isAccessible()) { + method.setAccessible(true); + } + if (Factory.class.isAssignableFrom(method.getDeclaringClass()) + || (method.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) { + iter.remove(); + continue; + } + final Class[] parameterTypes = method.getParameterTypes(); + Method calledMethod = method; + try { + if ((method.getModifiers() & Modifier.ABSTRACT) > 0) { + calledMethod = source.getClass().getMethod(method.getName(), method.getParameterTypes()); + } + callbackIndexMap.put(null, method); + calledMethod.invoke(source, parameterTypes == null + ? (Object[])null + : createNullArguments(parameterTypes)); + } catch (final IllegalAccessException e) { + throw new ObjectAccessException("Access to " + calledMethod + " not allowed", e); + } catch (final InvocationTargetException e) { + // OK, ignore + } catch (final NoSuchMethodException e) { + final ConversionException exception = new ConversionException( + "CGLIB enhanced proxies wit abstract nethod that has not been implemented"); + exception.add("proxy superclass", type.getSuperclass().getName()); + exception.add("method", method.toString()); + throw exception; + } + if (callbackIndexMap.containsKey(method)) { + iter.remove(); + } + } + if (idxNoOp >= 0) { + final Integer idx = Integer.valueOf(idxNoOp); + for (final Method method : methods) { + callbackIndexMap.put(method, idx); + } + } + } finally { + source.setCallbacks(originalCallbacks); + } + + callbackIndexMap.remove(null); + return callbackIndexMap; + } + + private Object[] createNullArguments(final Class[] parameterTypes) { + final Object[] arguments = new Object[parameterTypes.length]; + for (int i = 0; i < arguments.length; i++) { + final Class type = parameterTypes[i]; + if (type.isPrimitive()) { + if (type == byte.class) { + arguments[i] = new Byte((byte)0); + } else if (type == short.class) { + arguments[i] = new Short((short)0); + } else if (type == int.class) { + arguments[i] = new Integer(0); + } else if (type == long.class) { + arguments[i] = new Long(0); + } else if (type == float.class) { + arguments[i] = new Float(0); + } else if (type == double.class) { + arguments[i] = new Double(0); + } else if (type == char.class) { + arguments[i] = new Character('\0'); + } else { + arguments[i] = Boolean.FALSE; + } + } + } + return arguments; + } + + private Callback createReverseEngineeredCallbackOfProperType(final Callback callback, final int index, + final Map callbackIndexMap) { + Class iface = null; + Class[] interfaces = callback.getClass().getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + if (Callback.class.isAssignableFrom(interfaces[i])) { + iface = interfaces[i]; + if (iface == Callback.class) { + final ConversionException exception = new ConversionException("Cannot handle CGLIB callback"); + exception.add("CGLIB callback type", callback.getClass().getName()); + throw exception; + } + interfaces = iface.getInterfaces(); + if (Arrays.asList(interfaces).contains(Callback.class)) { + break; + } + i = -1; + } + } + return (Callback)Proxy.newProxyInstance(iface.getClassLoader(), new Class[]{iface}, + new ReverseEngineeringInvocationHandler(index, callbackIndexMap)); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Enhancer enhancer = new Enhancer(); + reader.moveDown(); + enhancer.setSuperclass((Class)context.convertAnother(null, Class.class)); + reader.moveUp(); + reader.moveDown(); + final List> interfaces = new ArrayList>(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + interfaces.add((Class)context.convertAnother(null, mapper.realClass(reader.getNodeName()))); + reader.moveUp(); + } + enhancer.setInterfaces(interfaces.toArray(new Class[interfaces.size()])); + reader.moveUp(); + reader.moveDown(); + final boolean useFactory = Boolean.valueOf(reader.getValue()).booleanValue(); + enhancer.setUseFactory(useFactory); + reader.moveUp(); + + final List callbacksToEnhance = new ArrayList(); + final List callbacks = new ArrayList(); + Map callbackIndexMap = null; + reader.moveDown(); + if ("callbacks".equals(reader.getNodeName())) { + reader.moveDown(); + @SuppressWarnings("unchecked") + final Map typedMap = (Map)context.convertAnother(null, HashMap.class); + callbackIndexMap = typedMap; + reader.moveUp(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + readCallback(reader, context, callbacksToEnhance, callbacks); + reader.moveUp(); + } + } else { + readCallback(reader, context, callbacksToEnhance, callbacks); + } + enhancer.setCallbacks(callbacksToEnhance.toArray(new Callback[callbacksToEnhance.size()])); + if (callbackIndexMap != null) { + enhancer.setCallbackFilter(new ReverseEngineeredCallbackFilter(callbackIndexMap)); + } + reader.moveUp(); + Object result = null; + while (reader.hasMoreChildren()) { + reader.moveDown(); + if (reader.getNodeName().equals("serialVersionUID")) { + enhancer.setSerialVersionUID(Long.valueOf(reader.getValue())); + } else if (reader.getNodeName().equals("instance")) { + result = create(enhancer, callbacks, useFactory); + super.doUnmarshalConditionally(result, reader, context); + } + reader.moveUp(); + } + if (result == null) { + result = create(enhancer, callbacks, useFactory); + } + return serializationMethodInvoker.callReadResolve(result); + } + + private void readCallback(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final List callbacksToEnhance, final List callbacks) { + final Callback callback = (Callback)context.convertAnother(null, mapper.realClass(reader.getNodeName())); + callbacks.add(callback); + if (callback == null) { + callbacksToEnhance.add(NoOp.INSTANCE); + } else { + callbacksToEnhance.add(callback); + } + } + + private Object create(final Enhancer enhancer, final List callbacks, final boolean useFactory) { + final Object result = enhancer.create(); + if (useFactory) { + ((Factory)result).setCallbacks(callbacks.toArray(new Callback[callbacks.size()])); + } + return result; + } + + @Override + protected List> hierarchyFor(final Class type) { + final List> typeHierarchy = super.hierarchyFor(type); + // drop the CGLIB proxy + typeHierarchy.remove(typeHierarchy.size() - 1); + return typeHierarchy; + } + + private Object readResolve() { + fieldCache = new HashMap>(); + return this; + } + + private static class CGLIBFilteringReflectionProvider extends ReflectionProviderWrapper { + + public CGLIBFilteringReflectionProvider(final ReflectionProvider reflectionProvider) { + super(reflectionProvider); + } + + @Override + public void visitSerializableFields(final Object object, final Visitor visitor) { + wrapped.visitSerializableFields(object, new Visitor() { + @Override + public void visit(final String name, final Class type, final Class definedIn, final Object value) { + if (!name.startsWith("CGLIB$")) { + visitor.visit(name, type, definedIn, value); + } + } + }); + } + } + + private static final class ReverseEngineeringInvocationHandler implements InvocationHandler { + private final Integer index; + private final Map indexMap; + + public ReverseEngineeringInvocationHandler(final int index, final Map indexMap) { + this.indexMap = indexMap; + this.index = Integer.valueOf(index); + } + + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { + indexMap.put(indexMap.get(null), index); + return null; + } + } + + private static class ReverseEngineeredCallbackFilter implements CallbackFilter { + + private final Map callbackIndexMap; + + public ReverseEngineeredCallbackFilter(final Map callbackIndexMap) { + this.callbackIndexMap = callbackIndexMap; + } + + @Override + public int accept(final Method method) { + if (!callbackIndexMap.containsKey(method)) { + final ConversionException exception = new ConversionException( + "CGLIB callback not detected in reverse engineering"); + exception.add("CGLIB callback", method.toString()); + throw exception; + } + return callbackIndexMap.get(method).intValue(); + } + + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java (.../ExternalizableConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java (.../ExternalizableConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,117 +1,193 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014 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 24. August 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.reflection; +import java.io.Externalizable; +import java.io.IOException; +import java.io.NotActiveException; +import java.io.ObjectInputValidation; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; + import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.ClassLoaderReference; +import com.thoughtworks.xstream.core.JVM; import com.thoughtworks.xstream.core.util.CustomObjectInputStream; import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; -import java.io.Externalizable; -import java.io.IOException; -import java.io.NotActiveException; -import java.io.ObjectInput; -import java.io.ObjectInputValidation; -import java.io.ObjectOutput; -import java.util.Map; /** - * Converts any object that implements the java.io.Externalizable interface, allowing compatability with native Java + * Converts any object that implements the {@link Externalizable} interface, allowing compatibility with native Java * serialization. - * + * * @author Joe Walnes */ public class ExternalizableConverter implements Converter { - private Mapper mapper; + private final Mapper mapper; + private final ClassLoaderReference classLoaderReference; - public ExternalizableConverter(Mapper mapper) { + /** + * Construct an ExternalizableConverter. + * + * @param mapper the Mapper chain + * @param classLoaderReference the reference to XStream's {@link ClassLoader} instance + * @since 1.4.5 + */ + public ExternalizableConverter(final Mapper mapper, final ClassLoaderReference classLoaderReference) { this.mapper = mapper; + this.classLoaderReference = classLoaderReference; } - public boolean canConvert(Class type) { - return Externalizable.class.isAssignableFrom(type); + /** + * @deprecated As of 1.4.5 use {@link #ExternalizableConverter(Mapper, ClassLoaderReference)} + */ + @Deprecated + public ExternalizableConverter(final Mapper mapper, final ClassLoader classLoader) { + this(mapper, new ClassLoaderReference(classLoader)); } - public void marshal(Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + /** + * @deprecated As of 1.4 use {@link #ExternalizableConverter(Mapper, ClassLoader)} + */ + @Deprecated + public ExternalizableConverter(final Mapper mapper) { + this(mapper, ExternalizableConverter.class.getClassLoader()); + } + + @Override + public boolean canConvert(final Class type) { + return JVM.canCreateDerivedObjectOutputStream() && Externalizable.class.isAssignableFrom(type); + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { try { - Externalizable externalizable = (Externalizable) source; - CustomObjectOutputStream.StreamCallback callback = new CustomObjectOutputStream.StreamCallback() { - public void writeToStream(Object object) { + final Externalizable externalizable = (Externalizable)source; + final CustomObjectOutputStream.StreamCallback callback = new CustomObjectOutputStream.StreamCallback() { + @Override + public void writeToStream(final Object object) { if (object == null) { writer.startNode("null"); writer.endNode(); } else { - writer.startNode(mapper.serializedClass(object.getClass())); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(object + .getClass()), object.getClass()); context.convertAnother(object); writer.endNode(); } } - public void writeFieldsToStream(Map fields) { + @Override + public void writeFieldsToStream(final Map fields) { throw new UnsupportedOperationException(); } + @Override public void defaultWriteObject() { throw new UnsupportedOperationException(); } + @Override public void flush() { writer.flush(); } + @Override public void close() { - throw new UnsupportedOperationException("Objects are not allowed to call ObjecOutput.close() from writeExternal()"); + throw new UnsupportedOperationException( + "Objects are not allowed to call ObjectOutput.close() from writeExternal()"); } }; - ObjectOutput objectOutput = CustomObjectOutputStream.getInstance(context, callback); + @SuppressWarnings("resource") + final CustomObjectOutputStream objectOutput = CustomObjectOutputStream.getInstance(context, callback); externalizable.writeExternal(objectOutput); - } catch (IOException e) { - throw new ConversionException("Cannot serialize " + source.getClass().getName() + " using Externalization", e); + objectOutput.popCallback(); + } catch (final IOException e) { + throw new ConversionException("Cannot serialize " + source.getClass().getName() + " using Externalization", + e); } } + @Override public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { - final Class type = context.getRequiredType(); + final Class type = context.getRequiredType(); + final Constructor defaultConstructor; try { - final Externalizable externalizable = (Externalizable) type.newInstance(); - CustomObjectInputStream.StreamCallback callback = new CustomObjectInputStream.StreamCallback() { + defaultConstructor = type.getDeclaredConstructor(); + if (!defaultConstructor.isAccessible()) { + defaultConstructor.setAccessible(true); + } + final Externalizable externalizable = (Externalizable)defaultConstructor.newInstance(); + final CustomObjectInputStream.StreamCallback callback = new CustomObjectInputStream.StreamCallback() { + @Override public Object readFromStream() { reader.moveDown(); - Object streamItem = context.convertAnother(externalizable, mapper.realClass(reader.getNodeName())); + final Class type = HierarchicalStreams.readClassType(reader, mapper); + final Object streamItem = context.convertAnother(externalizable, type); reader.moveUp(); return streamItem; } - public Map readFieldsFromStream() { + @Override + public Map readFieldsFromStream() { throw new UnsupportedOperationException(); } + @Override public void defaultReadObject() { throw new UnsupportedOperationException(); } - public void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException { + @Override + public void registerValidation(final ObjectInputValidation validation, final int priority) + throws NotActiveException { throw new NotActiveException("stream inactive"); } + @Override public void close() { - throw new UnsupportedOperationException("Objects are not allowed to call ObjectInput.close() from readExternal()"); + throw new UnsupportedOperationException( + "Objects are not allowed to call ObjectInput.close() from readExternal()"); } }; - ObjectInput objectInput = CustomObjectInputStream.getInstance(context, callback); - externalizable.readExternal(objectInput); + { + @SuppressWarnings("resource") + final CustomObjectInputStream objectInput = CustomObjectInputStream.getInstance(context, callback, + classLoaderReference); + externalizable.readExternal(objectInput); + objectInput.popCallback(); + } return externalizable; - } catch (InstantiationException e) { + } catch (final NoSuchMethodException e) { + throw new ConversionException("Cannot construct " + type.getClass() + ", missing default constructor", e); + } catch (final InvocationTargetException e) { throw new ConversionException("Cannot construct " + type.getClass(), e); - } catch (IllegalAccessException e) { + } catch (final InstantiationException e) { throw new ConversionException("Cannot construct " + type.getClass(), e); - } catch (IOException e) { + } catch (final IllegalAccessException e) { + throw new ConversionException("Cannot construct " + type.getClass(), e); + } catch (final IOException e) { throw new ConversionException("Cannot externalize " + type.getClass(), e); - } catch (ClassNotFoundException e) { + } catch (final ClassNotFoundException e) { throw new ConversionException("Cannot externalize " + type.getClass(), e); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java (.../FieldDictionary.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java (.../FieldDictionary.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,110 +1,178 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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 14. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.reflection; -import com.thoughtworks.xstream.core.util.OrderRetainingMap; - import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; -public class FieldDictionary { +import com.thoughtworks.xstream.core.Caching; +import com.thoughtworks.xstream.core.JVM; - private final Map keyedByFieldNameCache = Collections.synchronizedMap(new HashMap()); - private final Map keyedByFieldKeyCache = Collections.synchronizedMap(new HashMap()); - public Iterator serializableFieldsFor(Class cls) { +/** + * A field dictionary instance caches information about classes fields. + * + * @author Joe Walnes + * @author Jörg Schaible + * @author Guilherme Silveira + */ +public class FieldDictionary implements Caching { + + private transient Map, Map> keyedByFieldNameCache; + private transient Map, Map> keyedByFieldKeyCache; + private final FieldKeySorter sorter; + + public FieldDictionary() { + this(new ImmutableFieldKeySorter()); + } + + public FieldDictionary(final FieldKeySorter sorter) { + this.sorter = sorter; + init(); + } + + private void init() { + keyedByFieldNameCache = new HashMap, Map>(); + keyedByFieldKeyCache = new HashMap, Map>(); + keyedByFieldNameCache.put(Object.class, Collections.emptyMap()); + keyedByFieldKeyCache.put(Object.class, Collections.emptyMap()); + } + + /** + * Returns an iterator for all fields for some class + * + * @param cls the class you are interested on + * @return an iterator for its fields + */ + public Iterator fieldsFor(final Class cls) { return buildMap(cls, true).values().iterator(); } - public Field field(Class cls, String name, Class definedIn) { - Map fields = buildMap(cls, definedIn != null); - Field field = (Field) fields.get(definedIn != null ? (Object) new FieldKey(name, definedIn, 0) : (Object) name); + /** + * Returns an specific field of some class. If definedIn is null, it searches for the field named 'name' inside the + * class cls. If definedIn is different than null, tries to find the specified field name in the specified class cls + * which should be defined in class definedIn (either equals cls or a one of it's superclasses) + * + * @param cls the class where the field is to be searched + * @param name the field name + * @param definedIn the superclass (or the class itself) of cls where the field was defined + * @return the field itself + * @throws ObjectAccessException if no field can be found + */ + public Field field(final Class cls, final String name, final Class definedIn) { + final Field field = fieldOrNull(cls, name, definedIn); if (field == null) { - throw new ObjectAccessException("No such field " + cls.getName() + "." + name); + throw new MissingFieldException(cls.getName(), name); } else { return field; } } - private Map buildMap(Class cls, boolean tupleKeyed) { - final String clsName = cls.getName(); - if (!keyedByFieldNameCache.containsKey(clsName)) { - synchronized (keyedByFieldKeyCache) { - if (!keyedByFieldNameCache.containsKey(clsName)) { // double check - final Map keyedByFieldName = new HashMap(); - final Map keyedByFieldKey = new OrderRetainingMap(); - while (!Object.class.equals(cls)) { - Field[] fields = cls.getDeclaredFields(); + /** + * Returns an specific field of some class. If definedIn is null, it searches for the field named 'name' inside the + * class cls. If definedIn is different than null, tries to find the specified field name in the specified class cls + * which should be defined in class definedIn (either equals cls or a one of it's superclasses) + * + * @param cls the class where the field is to be searched + * @param name the field name + * @param definedIn the superclass (or the class itself) of cls where the field was defined + * @return the field itself or null + * @since 1.4 + */ + public Field fieldOrNull(final Class cls, final String name, final Class definedIn) { + final Map fields = buildMap(cls, definedIn != null); + final Field field = fields.get(definedIn != null ? (Object)new FieldKey(name, definedIn, -1) : (Object)name); + return field; + } + + private Map buildMap(final Class type, final boolean tupleKeyed) { + Class cls = type; + synchronized (this) { + if (!keyedByFieldNameCache.containsKey(type)) { + final List> superClasses = new ArrayList>(); + while (!Object.class.equals(cls) && cls != null) { + superClasses.add(0, cls); + cls = cls.getSuperclass(); + } + Map lastKeyedByFieldName = Collections.emptyMap(); + Map lastKeyedByFieldKey = Collections.emptyMap(); + for (final Class element : superClasses) { + cls = element; + if (!keyedByFieldNameCache.containsKey(cls)) { + final Map keyedByFieldName = new HashMap(lastKeyedByFieldName); + final Map keyedByFieldKey = new LinkedHashMap( + lastKeyedByFieldKey); + final Field[] fields = cls.getDeclaredFields(); + if (JVM.reverseFieldDefinition()) { + for (int i = fields.length >> 1; i-- > 0;) { + final int idx = fields.length - i - 1; + final Field field = fields[i]; + fields[i] = fields[idx]; + fields[idx] = field; + } + } for (int i = 0; i < fields.length; i++) { - Field field = fields[i]; - field.setAccessible(true); - if (!keyedByFieldName.containsKey(field.getName())) { + final Field field = fields[i]; + if (!field.isAccessible()) { + field.setAccessible(true); + } + final FieldKey fieldKey = new FieldKey(field.getName(), field.getDeclaringClass(), i); + final Field existent = keyedByFieldName.get(field.getName()); + if (existent == null + // do overwrite statics + || (existent.getModifiers() & Modifier.STATIC) != 0 + // overwrite non-statics with non-statics only + || existent != null + && (field.getModifiers() & Modifier.STATIC) == 0) { keyedByFieldName.put(field.getName(), field); } - keyedByFieldKey.put(new FieldKey(field.getName(), field.getDeclaringClass(), i), field); + keyedByFieldKey.put(fieldKey, field); } - cls = cls.getSuperclass(); + final Map sortedFieldKeys = sorter.sort(cls, keyedByFieldKey); + keyedByFieldNameCache.put(cls, keyedByFieldName); + keyedByFieldKeyCache.put(cls, sortedFieldKeys); + lastKeyedByFieldName = keyedByFieldName; + lastKeyedByFieldKey = sortedFieldKeys; + } else { + lastKeyedByFieldName = keyedByFieldNameCache.get(cls); + lastKeyedByFieldKey = keyedByFieldKeyCache.get(cls); } - keyedByFieldNameCache.put(clsName, keyedByFieldName); - keyedByFieldKeyCache.put(clsName, keyedByFieldKey); } + return tupleKeyed ? lastKeyedByFieldKey : lastKeyedByFieldName; } } - return (Map) (tupleKeyed ? keyedByFieldKeyCache.get(clsName) : keyedByFieldNameCache.get(clsName)); + return tupleKeyed ? keyedByFieldKeyCache.get(type) : keyedByFieldNameCache.get(type); } - private static class FieldKey { - private String fieldName; - private Class declaringClass; - private Integer depth; - private int order; - - public FieldKey(String fieldName, Class declaringClass, int order) { - this.fieldName = fieldName; - this.declaringClass = declaringClass; - this.order = order; - Class c = declaringClass; - int i = 0; - while (c.getSuperclass() != null) { - i++; - c = c.getSuperclass(); - } - depth = new Integer(i); + @Override + public synchronized void flushCache() { + final Set> objectTypeSet = Collections.>singleton(Object.class); + keyedByFieldNameCache.keySet().retainAll(objectTypeSet); + keyedByFieldKeyCache.keySet().retainAll(objectTypeSet); + if (sorter instanceof Caching) { + ((Caching)sorter).flushCache(); } - - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof FieldKey)) return false; - - final FieldKey fieldKey = (FieldKey) o; - - if (declaringClass != null ? !declaringClass.equals(fieldKey.declaringClass) : fieldKey.declaringClass != null) return false; - if (fieldName != null ? !fieldName.equals(fieldKey.fieldName) : fieldKey.fieldName != null) return false; - - return true; - } - - public int hashCode() { - int result; - result = (fieldName != null ? fieldName.hashCode() : 0); - result = 29 * result + (declaringClass != null ? declaringClass.hashCode() : 0); - return result; - } - - public String toString() { - return "FieldKey{" + - "order=" + order + - ", writer=" + depth + - ", declaringClass=" + declaringClass + - ", fieldName='" + fieldName + "'" + - "}"; - } - - } + protected Object readResolve() { + init(); + return this; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldKey.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldKey.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldKey.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2007, 2014 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 10. April 2007 by Guilherme Silveira + */ +package com.thoughtworks.xstream.converters.reflection; + +/** + * A field key. + * + * @author Guilherme Silveira + * @author Jörg Schaible + */ +public class FieldKey { + final private String fieldName; + final private Class declaringClass; + final private int depth; + final private int order; + + public FieldKey(final String fieldName, final Class declaringClass, final int order) { + if (fieldName == null || declaringClass == null) { + throw new IllegalArgumentException("fieldName or declaringClass is null"); + } + this.fieldName = fieldName; + this.declaringClass = declaringClass; + this.order = order; + Class c = declaringClass; + int i = 0; + while (c.getSuperclass() != null) { + i++; + c = c.getSuperclass(); + } + depth = i; + } + + public String getFieldName() { + return fieldName; + } + + public Class getDeclaringClass() { + return declaringClass; + } + + public int getDepth() { + return depth; + } + + public int getOrder() { + return order; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof FieldKey)) { + return false; + } + + final FieldKey fieldKey = (FieldKey)o; + + if (!declaringClass.equals(fieldKey.declaringClass)) { + return false; + } + if (!fieldName.equals(fieldKey.fieldName)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result; + result = fieldName.hashCode(); + result = 29 * result + declaringClass.hashCode(); + return result; + } + + @Override + public String toString() { + return "FieldKey{" + + "order=" + + order + + ", writer=" + + depth + + ", declaringClass=" + + declaringClass + + ", fieldName='" + + fieldName + + "'" + + "}"; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldKeySorter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldKeySorter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/FieldKeySorter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2007, 2014 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 10. April 2007 by Guilherme Silveira + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; +import java.util.Map; + + +/** + * An interface capable of sorting fields. + *

+ * Implement this interface if you want to customize the field order in which XStream serializes objects. + *

+ * + * @author Guilherme Silveira + * @since 1.2.2 + */ +public interface FieldKeySorter { + + /** + * Sort the fields of a type. + *

+ * The method will be called with the class type that contains all the fields and a Map that retains the order in + * which the elements have been added. The sequence in which elements are returned by an iterator defines the + * processing order of the fields. An implementation may create a different Map with similar semantic, add all + * elements of the original map and return the new one. + *

+ * + * @param type the class that contains all the fields + * @param keyedByFieldKey a Map containing a {@link FieldKey} as key element and a {@link java.lang.reflect.Field} + * as value. + * @return a Map with all the entries of the original Map + * @since 1.2.2 + */ + Map sort(Class type, Map keyedByFieldKey); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ImmutableFieldKeySorter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ImmutableFieldKeySorter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ImmutableFieldKeySorter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2007, 2014 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 10. April 2007 by Guilherme Silveira + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; +import java.util.Map; + + +/** + * Does not change the order of the fields. + * + * @author Guilherme Silveira + * @since 1.2.2 + */ +public class ImmutableFieldKeySorter implements FieldKeySorter { + + @Override + public Map sort(final Class type, final Map keyedByFieldKey) { + return keyedByFieldKey; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/MissingFieldException.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/MissingFieldException.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/MissingFieldException.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 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 01. October 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.reflection; + +/** + * Indicates a missing field or property creating an object. + * + * @author Nikita Levyankov + * @author Joerg Schaible + * @since 1.4.2 + */ +public class MissingFieldException extends ObjectAccessException { + + private final String fieldName; + private final String className; + + /** + * Construct a MissingFieldException. + * @param className the name of the class missing the field + * @param fieldName the name of the missed field + * @since 1.4.2 + */ + public MissingFieldException(final String className, final String fieldName) { + super("No field '" + fieldName + "' found in class '" + className + "'"); + this.className = className; + this.fieldName = fieldName; + } + + /** + * Retrieve the name of the missing field. + * @return the field name + * @since 1.4.2 + */ + public String getFieldName() { + return fieldName; + } + + /** + * Retrieve the name of the class with the missing field. + * @return the class name + * @since 1.4.2 + */ + protected String getClassName() { + return className; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2007, 2014 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 17.05.2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; + + +/** + * Sort the fields in their natural order. Fields are returned in their declaration order, fields of base classes first. + * + * @author Jörg Schaible + * @since 1.2.2 + */ +public class NativeFieldKeySorter implements FieldKeySorter { + + @Override + public Map sort(final Class type, final Map keyedByFieldKey) { + final Map map = new TreeMap(new Comparator() { + + @Override + public int compare(final FieldKey fieldKey1, final FieldKey fieldKey2) { + int i = fieldKey1.getDepth() - fieldKey2.getDepth(); + if (i == 0) { + i = fieldKey1.getOrder() - fieldKey2.getOrder(); + } + return i; + } + }); + map.putAll(keyedByFieldKey); + return map; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ObjectAccessException.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ObjectAccessException.java (.../ObjectAccessException.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ObjectAccessException.java (.../ObjectAccessException.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,8 +1,19 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.reflection; -import com.thoughtworks.xstream.core.BaseException; +import com.thoughtworks.xstream.XStreamException; -public class ObjectAccessException extends BaseException { +public class ObjectAccessException extends XStreamException { public ObjectAccessException(String message) { super(message); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java (.../PureJavaReflectionProvider.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java (.../PureJavaReflectionProvider.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,154 +1,212 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.reflection; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Iterator; -import java.util.Map; -import java.util.HashMap; -import java.util.Collections; -import java.io.Serializable; -import java.io.ObjectStreamConstants; -import java.io.DataOutputStream; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.IOException; -import java.io.ByteArrayInputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; +import java.io.ObjectStreamConstants; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + /** - * Pure Java ObjectFactory that instantiates objects using standard Java reflection, however the types of objects - * that can be constructed are limited. - *

- * Can newInstance: classes with public visibility, outer classes, static inner classes, classes with default constructors - * and any class that implements java.io.Serializable. - * Cannot newInstance: classes without public visibility, non-static inner classes, classes without default constructors. - * Note that any code in the constructor of a class will be executed when the ObjectFactory instantiates the object. + * Pure Java ObjectFactory that instantiates objects using standard Java reflection, however the types of objects that + * can be constructed are limited. + *

+ * Can newInstance: classes with public visibility, outer classes, static inner classes, classes with default + * constructors and any class that implements java.io.Serializable. *

+ *

+ * Cannot newInstance: classes without public visibility, non-static inner classes, classes without default + * constructors. Note that any code in the constructor of a class will be executed when the ObjectFactory instantiates + * the object. + *

+ * + * @author Joe Walnes */ public class PureJavaReflectionProvider implements ReflectionProvider { - private final Map serializedDataCache = Collections.synchronizedMap(new HashMap()); + private transient Map, byte[]> serializedDataCache; + protected FieldDictionary fieldDictionary; - protected FieldDictionary fieldDictionary = new FieldDictionary(); + public PureJavaReflectionProvider() { + this(new FieldDictionary(new ImmutableFieldKeySorter())); + } - public Object newInstance(Class type) { + public PureJavaReflectionProvider(final FieldDictionary fieldDictionary) { + this.fieldDictionary = fieldDictionary; + init(); + } + + @Override + public Object newInstance(final Class type) { try { - Constructor[] constructors = type.getDeclaredConstructors(); - for (int i = 0; i < constructors.length; i++) { - if (constructors[i].getParameterTypes().length == 0) { - if (!Modifier.isPublic(constructors[i].getModifiers())) { - constructors[i].setAccessible(true); + for (final Constructor constructor : type.getDeclaredConstructors()) { + if (constructor.getParameterTypes().length == 0) { + if (!constructor.isAccessible()) { + constructor.setAccessible(true); } - return constructors[i].newInstance(new Object[0]); + return constructor.newInstance(new Object[0]); } } if (Serializable.class.isAssignableFrom(type)) { return instantiateUsingSerialization(type); } else { - throw new ObjectAccessException("Cannot construct " + type.getName() - + " as it does not have a no-args constructor"); + throw new ObjectAccessException("Cannot construct " + + type.getName() + + " as it does not have a no-args constructor"); } - } catch (InstantiationException e) { + } catch (final InstantiationException e) { throw new ObjectAccessException("Cannot construct " + type.getName(), e); - } catch (IllegalAccessException e) { + } catch (final IllegalAccessException e) { throw new ObjectAccessException("Cannot construct " + type.getName(), e); - } catch (InvocationTargetException e) { + } catch (final InvocationTargetException e) { if (e.getTargetException() instanceof RuntimeException) { throw (RuntimeException)e.getTargetException(); } else if (e.getTargetException() instanceof Error) { throw (Error)e.getTargetException(); } else { - throw new ObjectAccessException("Constructor for " + type.getName() + " threw an exception", e); + throw new ObjectAccessException("Constructor for " + type.getName() + " threw an exception", e + .getTargetException()); } } } - private Object instantiateUsingSerialization(Class type) { + private Object instantiateUsingSerialization(final Class type) { try { - byte[] data; - if (serializedDataCache.containsKey(type)) { - data = (byte[]) serializedDataCache.get(type); - } else { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - DataOutputStream stream = new DataOutputStream(bytes); - stream.writeShort(ObjectStreamConstants.STREAM_MAGIC); - stream.writeShort(ObjectStreamConstants.STREAM_VERSION); - stream.writeByte(ObjectStreamConstants.TC_OBJECT); - stream.writeByte(ObjectStreamConstants.TC_CLASSDESC); - stream.writeUTF(type.getName()); - stream.writeLong(ObjectStreamClass.lookup(type).getSerialVersionUID()); - stream.writeByte(2); // classDescFlags (2 = Serializable) - stream.writeShort(0); // field count - stream.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); - stream.writeByte(ObjectStreamConstants.TC_NULL); - data = bytes.toByteArray(); - serializedDataCache.put(type, data); - } + synchronized (serializedDataCache) { + byte[] data = serializedDataCache.get(type); + if (data == null) { + final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + final DataOutputStream stream = new DataOutputStream(bytes); + stream.writeShort(ObjectStreamConstants.STREAM_MAGIC); + stream.writeShort(ObjectStreamConstants.STREAM_VERSION); + stream.writeByte(ObjectStreamConstants.TC_OBJECT); + stream.writeByte(ObjectStreamConstants.TC_CLASSDESC); + stream.writeUTF(type.getName()); + stream.writeLong(ObjectStreamClass.lookup(type).getSerialVersionUID()); + stream.writeByte(2); // classDescFlags (2 = Serializable) + stream.writeShort(0); // field count + stream.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); + stream.writeByte(ObjectStreamConstants.TC_NULL); + data = bytes.toByteArray(); + serializedDataCache.put(type, data); + } - ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data)); - return in.readObject(); - } catch (IOException e) { - throw new ObjectAccessException("", e); - } catch (ClassNotFoundException e) { - throw new ObjectAccessException("", e); + final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data)) { + @Override + protected Class resolveClass(final ObjectStreamClass desc) throws ClassNotFoundException { + return Class.forName(desc.getName(), false, type.getClassLoader()); + } + }; + return in.readObject(); + } + } catch (final IOException e) { + throw new ObjectAccessException("Cannot create " + type.getName() + " by JDK serialization", e); + } catch (final ClassNotFoundException e) { + throw new ObjectAccessException("Cannot find class " + e.getMessage(), e); } } - public void visitSerializableFields(Object object, ReflectionProvider.Visitor visitor) { - for (Iterator iterator = fieldDictionary.serializableFieldsFor(object.getClass()); iterator.hasNext();) { - Field field = (Field) iterator.next(); + @Override + public void visitSerializableFields(final Object object, final ReflectionProvider.Visitor visitor) { + for (final Iterator iterator = fieldDictionary.fieldsFor(object.getClass()); iterator.hasNext();) { + final Field field = iterator.next(); if (!fieldModifiersSupported(field)) { continue; } validateFieldAccess(field); try { - Object value = field.get(object); + final Object value = field.get(object); visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(), value); - } catch (IllegalArgumentException e) { + } catch (final IllegalArgumentException e) { throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); - } catch (IllegalAccessException e) { + } catch (final IllegalAccessException e) { throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); } } } - public void writeField(Object object, String fieldName, Object value, Class definedIn) { - Field field = fieldDictionary.field(object.getClass(), fieldName, definedIn); + @Override + public void writeField(final Object object, final String fieldName, final Object value, final Class definedIn) { + final Field field = fieldDictionary.field(object.getClass(), fieldName, definedIn); validateFieldAccess(field); try { field.set(object, value); - } catch (IllegalArgumentException e) { + } catch (final IllegalArgumentException e) { throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); - } catch (IllegalAccessException e) { + } catch (final IllegalAccessException e) { throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); } } - public Class getFieldType(Object object, String fieldName, Class definedIn) { + @Override + public Class getFieldType(final Object object, final String fieldName, final Class definedIn) { return fieldDictionary.field(object.getClass(), fieldName, definedIn).getType(); } - public boolean fieldDefinedInClass(String fieldName, Class type) { - try { - fieldDictionary.field(type, fieldName, null); - return true; - } catch (ObjectAccessException e) { - return false; - } + /** + * @deprecated As of 1.4.5, use {@link #getFieldOrNull(Class, String)} instead + */ + @Deprecated + @Override + public boolean fieldDefinedInClass(final String fieldName, final Class type) { + final Field field = fieldDictionary.fieldOrNull(type, fieldName, null); + return field != null && fieldModifiersSupported(field); } - protected boolean fieldModifiersSupported(Field field) { - return !(Modifier.isStatic(field.getModifiers()) - || Modifier.isTransient(field.getModifiers())); + protected boolean fieldModifiersSupported(final Field field) { + final int modifiers = field.getModifiers(); + return !(Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)); } - protected void validateFieldAccess(Field field) { + protected void validateFieldAccess(final Field field) { if (Modifier.isFinal(field.getModifiers())) { - throw new ObjectAccessException("Invalid final field " - + field.getDeclaringClass().getName() + "." + field.getName()); + if (!field.isAccessible()) { + field.setAccessible(true); + } } } + @Override + public Field getField(final Class definedIn, final String fieldName) { + return fieldDictionary.field(definedIn, fieldName, null); + } + + @Override + public Field getFieldOrNull(final Class definedIn, final String fieldName) { + return fieldDictionary.fieldOrNull(definedIn, fieldName, null); + } + + public void setFieldDictionary(final FieldDictionary dictionary) { + fieldDictionary = dictionary; + } + + private Object readResolve() { + init(); + return this; + } + + protected void init() { + serializedDataCache = new HashMap, byte[]>(); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionConverter.java (.../ReflectionConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionConverter.java (.../ReflectionConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,191 +1,46 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.reflection; -import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.converters.Converter; -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.core.JVM; import com.thoughtworks.xstream.mapper.Mapper; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -public class ReflectionConverter implements Converter { +public class ReflectionConverter extends AbstractReflectionConverter { - private final Mapper mapper; - private final ReflectionProvider reflectionProvider; - private final SerializationMethodInvoker serializationMethodInvoker; + // Might be missing in Android + private final static Class eventHandlerType = JVM.loadClassForName("java.beans.EventHandler"); + private Class type; - public ReflectionConverter(Mapper mapper, ReflectionProvider reflectionProvider) { - this.mapper = mapper; - this.reflectionProvider = reflectionProvider; - serializationMethodInvoker = new SerializationMethodInvoker(); + public ReflectionConverter(final Mapper mapper, final ReflectionProvider reflectionProvider) { + super(mapper, reflectionProvider); } - public boolean canConvert(Class type) { - return true; + /** + * Construct a ReflectionConverter for an explicit type. + * + * @param mapper the mapper in use + * @param reflectionProvider the reflection provider in use + * @param type the explicit type to handle + * @since 1.4.7 + */ + public ReflectionConverter(final Mapper mapper, final ReflectionProvider reflectionProvider, final Class type) { + this(mapper, reflectionProvider); + this.type = type; } - public void marshal(Object original, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final Object source = serializationMethodInvoker.callWriteReplace(original); - - if (source.getClass() != original.getClass()) { - writer.addAttribute(mapper.attributeForReadResolveField(), mapper.serializedClass(source.getClass())); - } - - final Set seenFields = new HashSet(); - - reflectionProvider.visitSerializableFields(source, new ReflectionProvider.Visitor() { - public void visit(String fieldName, Class fieldType, Class definedIn, Object newObj) { - if (newObj != null) { - Mapper.ImplicitCollectionMapping mapping = mapper.getImplicitCollectionDefForFieldName(source.getClass(), fieldName); - if (mapping != null) { - if (mapping.getItemFieldName() != null) { - ArrayList list = (ArrayList) newObj; - for (Iterator iter = list.iterator(); iter.hasNext();) { - Object obj = iter.next(); - writeField(mapping.getItemFieldName(), mapping.getItemType(), definedIn, obj); - } - } else { - context.convertAnother(newObj); - } - } else { - writeField(fieldName, fieldType, definedIn, newObj); - seenFields.add(fieldName); - } - } - } - - private void writeField(String fieldName, Class fieldType, Class definedIn, Object newObj) { - if (!mapper.shouldSerializeMember(definedIn, fieldName)) { - return; - } - writer.startNode(mapper.serializedMember(definedIn, fieldName)); - - Class actualType = newObj.getClass(); - - Class defaultType = mapper.defaultImplementationOf(fieldType); - if (!actualType.equals(defaultType)) { - writer.addAttribute(mapper.attributeForImplementationClass(), mapper.serializedClass(actualType)); - } - - if (seenFields.contains(fieldName)) { - writer.addAttribute(mapper.attributeForClassDefiningField(), mapper.serializedClass(definedIn)); - } - context.convertAnother(newObj); - - writer.endNode(); - } - - }); + @Override + public boolean canConvert(final Class type) { + return (this.type != null && this.type == type || this.type == null && type != null && type != eventHandlerType) + && canAccess(type); } - - public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { - final Object result = instantiateNewInstance(context, reader.getAttribute(mapper.attributeForReadResolveField())); - final SeenFields seenFields = new SeenFields(); - - Map implicitCollectionsForCurrentObject = null; - while (reader.hasMoreChildren()) { - reader.moveDown(); - - String fieldName = mapper.realMember(result.getClass(), reader.getNodeName()); - - Class classDefiningField = determineWhichClassDefinesField(reader); - boolean fieldExistsInClass = reflectionProvider.fieldDefinedInClass(fieldName, result.getClass()); - - Class type = determineType(reader, fieldExistsInClass, result, fieldName, classDefiningField); - Object value = context.convertAnother(result, type); - - if (fieldExistsInClass) { - reflectionProvider.writeField(result, fieldName, value, classDefiningField); - seenFields.add(classDefiningField, fieldName); - } else { - implicitCollectionsForCurrentObject = writeValueToImplicitCollection(context, value, implicitCollectionsForCurrentObject, result, fieldName); - } - - reader.moveUp(); - } - - return serializationMethodInvoker.callReadResolve(result); - } - - - private Map writeValueToImplicitCollection(UnmarshallingContext context, Object value, Map implicitCollections, Object result, String itemFieldName) { - String fieldName = mapper.getFieldNameForItemTypeAndName(context.getRequiredType(), value.getClass(), itemFieldName); - if (fieldName != null) { - if (implicitCollections == null) { - implicitCollections = new HashMap(); // lazy instantiation - } - Collection collection = (Collection) implicitCollections.get(fieldName); - if (collection == null) { - collection = new ArrayList(); - reflectionProvider.writeField(result, fieldName, collection, null); - implicitCollections.put(fieldName, collection); - } - collection.add(value); - } - return implicitCollections; - } - - private Class determineWhichClassDefinesField(HierarchicalStreamReader reader) { - String definedIn = reader.getAttribute(mapper.attributeForClassDefiningField()); - return definedIn == null ? null : mapper.realClass(definedIn); - } - - private Object instantiateNewInstance(UnmarshallingContext context, String readResolveValue) { - Object currentObject = context.currentObject(); - if (currentObject != null) { - return currentObject; - } else if (readResolveValue != null) { - return reflectionProvider.newInstance(mapper.realClass(readResolveValue)); - } else { - return reflectionProvider.newInstance(context.getRequiredType()); - } - } - - private static class SeenFields { - - private Set seen = new HashSet(); - - public void add(Class definedInCls, String fieldName) { - String uniqueKey = fieldName; - if (definedInCls != null) { - uniqueKey += " [" + definedInCls.getName() + "]"; - } - if (seen.contains(uniqueKey)) { - throw new DuplicateFieldException(uniqueKey); - } else { - seen.add(uniqueKey); - } - } - - } - - private Class determineType(HierarchicalStreamReader reader, boolean validField, Object result, String fieldName, Class definedInCls) { - String classAttribute = reader.getAttribute(mapper.attributeForImplementationClass()); - if (classAttribute != null) { - return mapper.realClass(classAttribute); - } else if (!validField) { - Class itemType = mapper.getItemTypeForItemFieldName(result.getClass(), fieldName); - if (itemType != null) { - return itemType; - } else { - return mapper.realClass(reader.getNodeName()); - } - } else { - return mapper.defaultImplementationOf(reflectionProvider.getFieldType(result, fieldName, definedInCls)); - } - } - - public static class DuplicateFieldException extends ConversionException { - public DuplicateFieldException(String msg) { - super(msg); - } - } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionProvider.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionProvider.java (.../ReflectionProvider.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionProvider.java (.../ReflectionProvider.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,21 +1,80 @@ +/* + * Copyright (C) 2004, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.reflection; +import java.lang.reflect.Field; + + /** * Provides core reflection services. + * + * @author Joe Walnes */ public interface ReflectionProvider { - Object newInstance(Class type); + /** + * Creates a new instance of the specified type. It is in the responsibility of the implementation how such an + * instance is created. + * + * @param type the type to instantiate + * @return a new instance of this type + */ + Object newInstance(Class type); void visitSerializableFields(Object object, Visitor visitor); - void writeField(Object object, String fieldName, Object value, Class definedIn); + void writeField(Object object, String fieldName, Object value, Class definedIn); - Class getFieldType(Object object, String fieldName, Class definedIn); + Class getFieldType(Object object, String fieldName, Class definedIn); - boolean fieldDefinedInClass(String fieldName, Class type); + /** + * @deprecated As of 1.4.5, use {@link #getFieldOrNull(Class, String)} instead + */ + @Deprecated + boolean fieldDefinedInClass(String fieldName, Class type); + /** + * A visitor interface for serializable fields defined in a class. + */ interface Visitor { - void visit(String name, Class type, Class definedIn, Object value); + + /** + * Callback for each visit + * + * @param name field name + * @param type field type + * @param definedIn where the field was defined + * @param value field value + */ + void visit(String name, Class type, Class definedIn, Object value); } + + /** + * Returns a field defined in some class. + * + * @param definedIn class where the field was defined + * @param fieldName field name + * @return the field itself + * @throws ObjectAccessException if field does not exist + */ + Field getField(Class definedIn, String fieldName); + + /** + * Returns a field defined in some class. + * + * @param definedIn class where the field was defined + * @param fieldName field name + * @return the field itself or null + * @since 1.4.5 + */ + Field getFieldOrNull(Class definedIn, String fieldName); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionProviderWrapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionProviderWrapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/ReflectionProviderWrapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2006, 2007, 2013, 2014 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 13. April 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; + + +/** + * A wrapper implementation for the ReflectionProvider. + * + * @author Jörg Schaible + * @since 1.2 + */ +public class ReflectionProviderWrapper implements ReflectionProvider { + + final protected ReflectionProvider wrapped; + + public ReflectionProviderWrapper(final ReflectionProvider wrapper) { + wrapped = wrapper; + } + + /** + * @deprecated As of 1.4.5, use {@link #getFieldOrNull(Class, String)} instead + */ + @Deprecated + @Override + public boolean fieldDefinedInClass(final String fieldName, final Class type) { + return wrapped.fieldDefinedInClass(fieldName, type); + } + + @Override + public Field getField(final Class definedIn, final String fieldName) { + return wrapped.getField(definedIn, fieldName); + } + + @Override + public Field getFieldOrNull(final Class definedIn, final String fieldName) { + return wrapped.getFieldOrNull(definedIn, fieldName); + } + + @Override + public Class getFieldType(final Object object, final String fieldName, final Class definedIn) { + return wrapped.getFieldType(object, fieldName, definedIn); + } + + @Override + public Object newInstance(final Class type) { + return wrapped.newInstance(type); + } + + @Override + public void visitSerializableFields(final Object object, final Visitor visitor) { + wrapped.visitSerializableFields(object, visitor); + } + + @Override + public void writeField(final Object object, final String fieldName, final Object value, final Class definedIn) { + wrapped.writeField(object, fieldName, value, definedIn); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SelfStreamingInstanceChecker.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SelfStreamingInstanceChecker.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SelfStreamingInstanceChecker.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2006, 2007, 2013 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 03. April 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.reflection; + +import com.thoughtworks.xstream.converters.Converter; + + +/** + * A special converter that prevents self-serialization. The serializing XStream instance adds a converter of this type + * to prevent self-serialization and will throw an exception instead. + * + * @author Jörg Schaible + * @since 1.2 + * @deprecated As of 1.4.5 use {@link com.thoughtworks.xstream.core.util.SelfStreamingInstanceChecker} + */ +@Deprecated +public class SelfStreamingInstanceChecker extends com.thoughtworks.xstream.core.util.SelfStreamingInstanceChecker { + + public SelfStreamingInstanceChecker(final Converter defaultConverter, final Object xstream) { + super(defaultConverter, xstream); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java (.../SerializableConverter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java (.../SerializableConverter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,119 +1,181 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014 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 21. December 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.reflection; -import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.converters.Converter; -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.core.util.CustomObjectInputStream; -import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.mapper.Mapper; - import java.io.IOException; import java.io.InvalidObjectException; -import java.io.ObjectInputStream; import java.io.ObjectInputValidation; -import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.io.ObjectStreamField; import java.io.Serializable; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.ClassLoaderReference; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.core.util.CustomObjectInputStream; +import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + + /** * Emulates the mechanism used by standard Java Serialization for classes that implement java.io.Serializable AND - * implement a custom readObject()/writeObject() method. - * - *

Supported features of serialization

+ * implement or inherit a custom readObject()/writeObject() method.

Supported features of serialization

*
    - *
  • readObject(), writeObject()
  • - *
  • class inheritance
  • - *
  • readResolve(), writeReplace()
  • + *
  • readObject(), writeObject()
  • + *
  • class inheritance
  • + *
  • readResolve(), writeReplace()
  • *
- * *

Currently unsupported features

*
    - *
  • putFields(), writeFields(), readFields()
  • - *
  • ObjectStreamField[] serialPersistentFields
  • - *
  • ObjectInputValidation
  • + *
  • putFields(), writeFields(), readFields()
  • + *
  • ObjectStreamField[] serialPersistentFields
  • + *
  • ObjectInputValidation
  • *
- * + * * @author Joe Walnes + * @author Jörg Schaible */ -public class SerializableConverter implements Converter { +public class SerializableConverter extends AbstractReflectionConverter { - private final SerializationMethodInvoker serializationMethodInvoker = new SerializationMethodInvoker(); - private final Mapper mapper; - private final ReflectionProvider reflectionProvider; - private static final String ELEMENT_NULL = "null"; private static final String ELEMENT_DEFAULT = "default"; + private static final String ELEMENT_UNSERIALIZABLE_PARENTS = "unserializable-parents"; private static final String ATTRIBUTE_CLASS = "class"; private static final String ATTRIBUTE_SERIALIZATION = "serialization"; private static final String ATTRIBUTE_VALUE_CUSTOM = "custom"; private static final String ELEMENT_FIELDS = "fields"; private static final String ELEMENT_FIELD = "field"; private static final String ATTRIBUTE_NAME = "name"; - public SerializableConverter(Mapper mapper, ReflectionProvider reflectionProvider) { - this.mapper = mapper; - this.reflectionProvider = reflectionProvider; + private final ClassLoaderReference classLoaderReference; + + /** + * Construct a SerializableConverter. + * + * @param mapper the mapper chain instance + * @param reflectionProvider the reflection provider + * @param classLoaderReference the reference to the {@link ClassLoader} of the XStream instance + * @since 1.4.5 + */ + public SerializableConverter( + final Mapper mapper, final ReflectionProvider reflectionProvider, + final ClassLoaderReference classLoaderReference) { + super(mapper, new UnserializableParentsReflectionProvider(reflectionProvider)); + this.classLoaderReference = classLoaderReference; } - public boolean canConvert(Class type) { - return Serializable.class.isAssignableFrom(type) - && ( serializationMethodInvoker.supportsReadObject(type, true) - || serializationMethodInvoker.supportsWriteObject(type, true) ); + /** + * @deprecated As of 1.4.5 use {@link #SerializableConverter(Mapper, ReflectionProvider, ClassLoaderReference)} + */ + @Deprecated + public SerializableConverter( + final Mapper mapper, final ReflectionProvider reflectionProvider, final ClassLoader classLoader) { + this(mapper, reflectionProvider, new ClassLoaderReference(classLoader)); } - public void marshal(Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final Object replacedSource = serializationMethodInvoker.callWriteReplace(source); + /** + * @deprecated As of 1.4 use {@link #SerializableConverter(Mapper, ReflectionProvider, ClassLoaderReference)} + */ + @Deprecated + public SerializableConverter(final Mapper mapper, final ReflectionProvider reflectionProvider) { + this(mapper, new UnserializableParentsReflectionProvider(reflectionProvider), new ClassLoaderReference(null)); + } - if (replacedSource.getClass() != source.getClass()) { - writer.addAttribute(mapper.attributeForReadResolveField(), mapper.serializedClass(replacedSource.getClass())); + @Override + public boolean canConvert(final Class type) { + return JVM.canCreateDerivedObjectOutputStream() && isSerializable(type); + } + + private boolean isSerializable(final Class type) { + if (type != null + && Serializable.class.isAssignableFrom(type) + && !type.isInterface() + && (serializationMethodInvoker.supportsReadObject(type, true) || serializationMethodInvoker + .supportsWriteObject(type, true))) { + for (final Class clazz : hierarchyFor(type)) { + if (!Serializable.class.isAssignableFrom(clazz)) { + return canAccess(type); + } + } + return true; } + return false; + } - writer.addAttribute(ATTRIBUTE_SERIALIZATION, ATTRIBUTE_VALUE_CUSTOM); + @Override + public void doMarshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final String attributeName = mapper.aliasForSystemAttribute(ATTRIBUTE_SERIALIZATION); + if (attributeName != null) { + writer.addAttribute(attributeName, ATTRIBUTE_VALUE_CUSTOM); + } // this is an array as it's a non final value that's accessed from an anonymous inner class. - final Class[] currentType = new Class[1]; + final Class[] currentTypeRef = new Class[1]; final boolean[] writtenClassWrapper = {false}; - CustomObjectOutputStream.StreamCallback callback = new CustomObjectOutputStream.StreamCallback() { + final CustomObjectOutputStream.StreamCallback callback = new CustomObjectOutputStream.StreamCallback() { - public void writeToStream(Object object) { + @Override + public void writeToStream(final Object object) { if (object == null) { writer.startNode(ELEMENT_NULL); writer.endNode(); } else { - writer.startNode(mapper.serializedClass(object.getClass())); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(object.getClass()), + object.getClass()); context.convertAnother(object); writer.endNode(); } } - public void writeFieldsToStream(Map fields) { - ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]); + @Override + public void writeFieldsToStream(final Map fields) { + final Class currentType = currentTypeRef[0]; + final ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType); writer.startNode(ELEMENT_DEFAULT); - for (Iterator iterator = fields.keySet().iterator(); iterator.hasNext();) { - String name = (String) iterator.next(); - ObjectStreamField field = objectStreamClass.getField(name); - Object value = fields.get(name); + for (final String name : fields.keySet()) { + if (!mapper.shouldSerializeMember(currentType, name)) { + continue; + } + final ObjectStreamField field = objectStreamClass.getField(name); + final Object value = fields.get(name); if (field == null) { - throw new ObjectAccessException("Class " + value.getClass().getName() - + " may not write a field named '" + name + "'"); + throw new ObjectAccessException("Class " + + value.getClass().getName() + + " may not write a field named '" + + name + + "'"); } if (value != null) { - writer.startNode(mapper.serializedMember(currentType[0], name)); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedMember(source + .getClass(), name), value.getClass()); if (field.getType() != value.getClass() && !field.getType().isPrimitive()) { - writer.addAttribute(ATTRIBUTE_CLASS, mapper.serializedClass(value.getClass())); + final String attributeName = mapper.aliasForSystemAttribute(ATTRIBUTE_CLASS); + if (attributeName != null) { + writer.addAttribute(attributeName, mapper.serializedClass(value.getClass())); + } } context.convertAnother(value); writer.endNode(); @@ -122,35 +184,40 @@ writer.endNode(); } + @Override public void defaultWriteObject() { boolean writtenDefaultFields = false; - ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]); - + final Class currentType = currentTypeRef[0]; + final ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType); if (objectStreamClass == null) { return; } - ObjectStreamField[] fields = objectStreamClass.getFields(); - for (int i = 0; i < fields.length; i++) { - ObjectStreamField field = fields[i]; - Object value = readField(field, currentType[0], replacedSource); + for (final ObjectStreamField field : objectStreamClass.getFields()) { + final Object value = readField(field, currentType, source); if (value != null) { if (!writtenClassWrapper[0]) { - writer.startNode(mapper.serializedClass(currentType[0])); + writer.startNode(mapper.serializedClass(currentType)); writtenClassWrapper[0] = true; } if (!writtenDefaultFields) { writer.startNode(ELEMENT_DEFAULT); writtenDefaultFields = true; } + if (!mapper.shouldSerializeMember(currentType, field.getName())) { + continue; + } - writer.startNode(mapper.serializedMember(currentType[0], field.getName())); - - Class actualType = value.getClass(); - Class defaultType = mapper.defaultImplementationOf(field.getType()); + final Class actualType = value.getClass(); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedMember(source + .getClass(), field.getName()), actualType); + final Class defaultType = mapper.defaultImplementationOf(field.getType()); if (!actualType.equals(defaultType)) { - writer.addAttribute(ATTRIBUTE_CLASS, mapper.serializedClass(actualType)); + final String attributeName = mapper.aliasForSystemAttribute(ATTRIBUTE_CLASS); + if (attributeName != null) { + writer.addAttribute(attributeName, mapper.serializedClass(actualType)); + } } context.convertAnother(value); @@ -166,147 +233,188 @@ } } + @Override public void flush() { writer.flush(); } + @Override public void close() { - throw new UnsupportedOperationException("Objects are not allowed to call ObjectOutputStream.close() from writeObject()"); + throw new UnsupportedOperationException( + "Objects are not allowed to call ObjectOutputStream.close() from writeObject()"); } }; try { - Iterator classHieararchy = hierarchyFor(replacedSource.getClass()); - while (classHieararchy.hasNext()) { - currentType[0] = (Class) classHieararchy.next(); - if (serializationMethodInvoker.supportsWriteObject(currentType[0], false)) { - writtenClassWrapper[0] = true; - writer.startNode(mapper.serializedClass(currentType[0])); - ObjectOutputStream objectOutputStream = CustomObjectOutputStream.getInstance(context, callback); - serializationMethodInvoker.callWriteObject(currentType[0], replacedSource, objectOutputStream); - writer.endNode(); - } else if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) { - // Special case for objects that have readObject(), but not writeObject(). - // The class wrapper is always written, whether or not this class in the hierarchy has - // serializable fields. This guarantees that readObject() will be called upon deserialization. - writtenClassWrapper[0] = true; - writer.startNode(mapper.serializedClass(currentType[0])); - callback.defaultWriteObject(); - writer.endNode(); + boolean mustHandleUnserializableParent = false; + for (final Class currentType : hierarchyFor(source.getClass())) { + currentTypeRef[0] = currentType; + if (!Serializable.class.isAssignableFrom(currentType)) { + mustHandleUnserializableParent = true; + continue; } else { - writtenClassWrapper[0] = false; - callback.defaultWriteObject(); - if (writtenClassWrapper[0]) { + if (mustHandleUnserializableParent) { + marshalUnserializableParent(writer, context, source); + mustHandleUnserializableParent = false; + } + if (serializationMethodInvoker.supportsWriteObject(currentType, false)) { + writtenClassWrapper[0] = true; + writer.startNode(mapper.serializedClass(currentType)); + if (currentType != mapper.defaultImplementationOf(currentType)) { + final String classAttributeName = mapper.aliasForSystemAttribute(ATTRIBUTE_CLASS); + if (classAttributeName != null) { + writer.addAttribute(classAttributeName, currentType.getName()); + } + } + @SuppressWarnings("resource") + final CustomObjectOutputStream objectOutputStream = CustomObjectOutputStream.getInstance( + context, callback); + serializationMethodInvoker.callWriteObject(currentType, source, objectOutputStream); + objectOutputStream.popCallback(); writer.endNode(); + } else if (serializationMethodInvoker.supportsReadObject(currentType, false)) { + // Special case for objects that have readObject(), but not writeObject(). + // The class wrapper is always written, whether or not this class in the hierarchy has + // serializable fields. This guarantees that readObject() will be called upon deserialization. + writtenClassWrapper[0] = true; + writer.startNode(mapper.serializedClass(currentType)); + if (currentType != mapper.defaultImplementationOf(currentType)) { + final String classAttributeName = mapper.aliasForSystemAttribute(ATTRIBUTE_CLASS); + if (classAttributeName != null) { + writer.addAttribute(classAttributeName, currentType.getName()); + } + } + callback.defaultWriteObject(); + writer.endNode(); + } else { + writtenClassWrapper[0] = false; + callback.defaultWriteObject(); + if (writtenClassWrapper[0]) { + writer.endNode(); + } } } } - } catch (IOException e) { + } catch (final IOException e) { throw new ObjectAccessException("Could not call defaultWriteObject()", e); } } - private Object readField(ObjectStreamField field, Class type, Object instance) { + protected void marshalUnserializableParent(final HierarchicalStreamWriter writer, final MarshallingContext context, + final Object replacedSource) { + writer.startNode(ELEMENT_UNSERIALIZABLE_PARENTS); + super.doMarshal(replacedSource, writer, context); + writer.endNode(); + } + + private Object readField(final ObjectStreamField field, final Class type, final Object instance) { try { - Field javaField = type.getDeclaredField(field.getName()); - javaField.setAccessible(true); + final Field javaField = type.getDeclaredField(field.getName()); + if (!javaField.isAccessible()) { + javaField.setAccessible(true); + } return javaField.get(instance); - } catch (IllegalArgumentException e) { + } catch (final IllegalArgumentException e) { throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); - } catch (IllegalAccessException e) { + } catch (final IllegalAccessException e) { throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); - } catch (NoSuchFieldException e) { + } catch (final NoSuchFieldException e) { throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); - } catch (SecurityException e) { + } catch (final SecurityException e) { throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e); } } - private Iterator hierarchyFor(Class type) { - List result = new ArrayList(); - while(type != null) { + protected List> hierarchyFor(Class type) { + final List> result = new ArrayList>(); + while (type != Object.class && type != null) { result.add(type); type = type.getSuperclass(); } // In Java Object Serialization, the classes are deserialized starting from parent class and moving down. Collections.reverse(result); - return result.iterator(); + return result; } - public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { - String resolvesAttribute = reader.getAttribute(mapper.attributeForReadResolveField()); - Class requiredType; - if (resolvesAttribute != null) { - requiredType = mapper.realClass(resolvesAttribute); - } else { - requiredType = context.getRequiredType(); - } - final Object result = reflectionProvider.newInstance(requiredType); - + @Override + public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader, + final UnmarshallingContext context) { // this is an array as it's a non final value that's accessed from an anonymous inner class. - final Class[] currentType = new Class[1]; + final Class[] currentType = new Class[1]; - if (!ATTRIBUTE_VALUE_CUSTOM.equals(reader.getAttribute(ATTRIBUTE_SERIALIZATION))) { + final String attributeName = mapper.aliasForSystemAttribute(ATTRIBUTE_SERIALIZATION); + if (attributeName != null && !ATTRIBUTE_VALUE_CUSTOM.equals(reader.getAttribute(attributeName))) { throw new ConversionException("Cannot deserialize object with new readObject()/writeObject() methods"); } - CustomObjectInputStream.StreamCallback callback = new CustomObjectInputStream.StreamCallback() { + final CustomObjectInputStream.StreamCallback callback = new CustomObjectInputStream.StreamCallback() { + @Override public Object readFromStream() { reader.moveDown(); - Class type = mapper.realClass(reader.getNodeName()); - Object value = context.convertAnother(result, type); + final Class type = HierarchicalStreams.readClassType(reader, mapper); + final Object value = context.convertAnother(result, type); reader.moveUp(); return value; } - public Map readFieldsFromStream() { - Map result = new HashMap(); + @Override + public Map readFieldsFromStream() { + final Map fields = new HashMap(); reader.moveDown(); if (reader.getNodeName().equals(ELEMENT_FIELDS)) { - // Maintain compatability with XStream 1.1.0 + // Maintain compatibility with XStream 1.1.0 while (reader.hasMoreChildren()) { reader.moveDown(); if (!reader.getNodeName().equals(ELEMENT_FIELD)) { - throw new ConversionException("Expected <" + ELEMENT_FIELD + "/> element inside <" + ELEMENT_FIELD + "/>"); + throw new ConversionException("Expected <" + + ELEMENT_FIELD + + "/> element inside <" + + ELEMENT_FIELD + + "/>"); } - String name = reader.getAttribute(ATTRIBUTE_NAME); - Class type = mapper.realClass(reader.getAttribute(ATTRIBUTE_CLASS)); - Object value = context.convertAnother(result, type); - result.put(name, value); + final String name = reader.getAttribute(ATTRIBUTE_NAME); + final Class type = mapper.realClass(reader.getAttribute(ATTRIBUTE_CLASS)); + final Object value = context.convertAnother(result, type); + fields.put(name, value); reader.moveUp(); } } else if (reader.getNodeName().equals(ELEMENT_DEFAULT)) { // New format introduced in XStream 1.1.1 - ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]); + final ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]); while (reader.hasMoreChildren()) { reader.moveDown(); - String name = reader.getNodeName(); - String typeName = reader.getAttribute(ATTRIBUTE_CLASS); - Class type; - if (typeName != null) { - type = mapper.realClass(typeName); - } else { - ObjectStreamField field = objectStreamClass.getField(name); - if (field == null) { - throw new ObjectAccessException("Class " + currentType[0] - + " does not contain a field named '" + name + "'"); + final String name = mapper.realMember(currentType[0], reader.getNodeName()); + if (mapper.shouldSerializeMember(currentType[0], name)) { + final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper); + Class type; + if (classAttribute != null) { + type = mapper.realClass(classAttribute); + } else { + final ObjectStreamField field = objectStreamClass.getField(name); + if (field == null) { + throw new MissingFieldException(currentType[0].getName(), name); + } + type = field.getType(); } - type = field.getType(); + final Object value = context.convertAnother(result, type); + fields.put(name, value); } - Object value = context.convertAnother(result, type); - result.put(name, value); reader.moveUp(); } } else { - throw new ConversionException("Expected <" + ELEMENT_FIELDS + "/> or <" + - ELEMENT_DEFAULT + "/> element when calling ObjectInputStream.readFields()"); + throw new ConversionException("Expected <" + + ELEMENT_FIELDS + + "/> or <" + + ELEMENT_DEFAULT + + "/> element when calling ObjectInputStream.readFields()"); } reader.moveUp(); - return result; + return fields; } + @Override public void defaultReadObject() { if (!reader.hasMoreChildren()) { return; @@ -318,57 +426,110 @@ while (reader.hasMoreChildren()) { reader.moveDown(); - Class type; - String fieldName = mapper.realMember(currentType[0], reader.getNodeName()); - String classAttribute = reader.getAttribute(ATTRIBUTE_CLASS); - if (classAttribute != null) { - type = mapper.realClass(classAttribute); - } else { - type = mapper.defaultImplementationOf(reflectionProvider.getFieldType(result, fieldName, currentType[0])); + final String fieldName = mapper.realMember(currentType[0], reader.getNodeName()); + if (mapper.shouldSerializeMember(currentType[0], fieldName)) { + final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper); + final Class type; + if (classAttribute != null) { + type = mapper.realClass(classAttribute); + } else { + type = mapper.defaultImplementationOf(reflectionProvider.getFieldType(result, fieldName, + currentType[0])); + } + + final Object value = context.convertAnother(result, type); + reflectionProvider.writeField(result, fieldName, value, currentType[0]); } - Object value = context.convertAnother(result, type); - reflectionProvider.writeField(result, fieldName, value, currentType[0]); - reader.moveUp(); } reader.moveUp(); } - public void registerValidation(final ObjectInputValidation validation, int priority) { + @Override + public void registerValidation(final ObjectInputValidation validation, final int priority) { context.addCompletionCallback(new Runnable() { + @Override public void run() { try { validation.validateObject(); - } catch (InvalidObjectException e) { + } catch (final InvalidObjectException e) { throw new ObjectAccessException("Cannot validate object : " + e.getMessage(), e); } } }, priority); } + @Override public void close() { - throw new UnsupportedOperationException("Objects are not allowed to call ObjectInputStream.close() from readObject()"); + throw new UnsupportedOperationException( + "Objects are not allowed to call ObjectInputStream.close() from readObject()"); } }; while (reader.hasMoreChildren()) { reader.moveDown(); - currentType[0] = mapper.defaultImplementationOf(mapper.realClass(reader.getNodeName())); - if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) { - ObjectInputStream objectInputStream = CustomObjectInputStream.getInstance(context, callback); - serializationMethodInvoker.callReadObject(currentType[0], result, objectInputStream); + final String nodeName = reader.getNodeName(); + if (nodeName.equals(ELEMENT_UNSERIALIZABLE_PARENTS)) { + super.doUnmarshal(result, reader, context); } else { - try { - callback.defaultReadObject(); - } catch (IOException e) { - throw new ObjectAccessException("Could not call defaultWriteObject()", e); + final String classAttribute = HierarchicalStreams.readClassAttribute(reader, mapper); + if (classAttribute == null) { + currentType[0] = mapper.defaultImplementationOf(mapper.realClass(nodeName)); + } else { + currentType[0] = mapper.realClass(classAttribute); } + if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) { + @SuppressWarnings("resource") + final CustomObjectInputStream objectInputStream = CustomObjectInputStream.getInstance(context, + callback, classLoaderReference); + serializationMethodInvoker.callReadObject(currentType[0], result, objectInputStream); + objectInputStream.popCallback(); + } else { + try { + callback.defaultReadObject(); + } catch (final IOException e) { + throw new ObjectAccessException("Could not call defaultWriteObject()", e); + } + } } reader.moveUp(); } - return serializationMethodInvoker.callReadResolve(result); + return result; } + protected void doMarshalConditionally(final Object source, final HierarchicalStreamWriter writer, + final MarshallingContext context) { + if (isSerializable(source.getClass())) { + doMarshal(source, writer, context); + } else { + super.doMarshal(source, writer, context); + } + } + + protected Object doUnmarshalConditionally(final Object result, final HierarchicalStreamReader reader, + final UnmarshallingContext context) { + return isSerializable(result.getClass()) ? doUnmarshal(result, reader, context) : super.doUnmarshal(result, + reader, context); + } + + private static class UnserializableParentsReflectionProvider extends ReflectionProviderWrapper { + + public UnserializableParentsReflectionProvider(final ReflectionProvider reflectionProvider) { + super(reflectionProvider); + } + + @Override + public void visitSerializableFields(final Object object, final Visitor visitor) { + wrapped.visitSerializableFields(object, new Visitor() { + @Override + public void visit(final String name, final Class type, final Class definedIn, final Object value) { + if (!Serializable.class.isAssignableFrom(definedIn)) { + visitor.visit(name, type, definedIn, value); + } + } + }); + } + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java (.../SerializationMethodInvoker.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java (.../SerializationMethodInvoker.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,128 +1,159 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2014 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 23. August 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.reflection; -import com.thoughtworks.xstream.converters.ConversionException; - +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Map; -import java.util.HashMap; +import java.util.Arrays; import java.util.Collections; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; +import java.util.HashMap; +import java.util.Map; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.core.Caching; +import com.thoughtworks.xstream.core.util.FastField; + + /** * Convenience wrapper to invoke special serialization methods on objects (and perform reflection caching). - * + * * @author Joe Walnes + * @author Jörg Schaible */ -public class SerializationMethodInvoker { +public class SerializationMethodInvoker implements Caching { - private Map cache = Collections.synchronizedMap(new HashMap()); - private static final Object NO_METHOD = new Object(); - private static final Object[] EMPTY_ARGS = new Object[0]; + private static final Method NO_METHOD = new Object() { + @SuppressWarnings("unused") + private void noMethod() { + } + }.getClass().getDeclaredMethods()[0]; + private static final FastField[] OBJECT_TYPE_FIELDS = new FastField[]{ + new FastField(Object.class, "readResolve"), new FastField(Object.class, "writeReplace"), + new FastField(Object.class, "readObject"), new FastField(Object.class, "writeObject")}; + private final Map cache = Collections.synchronizedMap(new HashMap()); + { + for (final FastField element : OBJECT_TYPE_FIELDS) { + cache.put(element, NO_METHOD); + } + } /** * Resolves an object as native serialization does by calling readResolve(), if available. */ - public Object callReadResolve(Object result) { + public Object callReadResolve(final Object result) { if (result == null) { return null; } else { - Method readResolveMethod = getMethod(result.getClass(), "readResolve", null, true); + final Method readResolveMethod = getMethod(result.getClass(), "readResolve", true); if (readResolveMethod != null) { try { - return readResolveMethod.invoke(result, EMPTY_ARGS); - } catch (IllegalAccessException e) { - throw new ObjectAccessException("Could not call " + result.getClass().getName() + ".readResolve()", e); - } catch (InvocationTargetException e) { - throw new ObjectAccessException("Could not call " + result.getClass().getName() + ".readResolve()", e); + return readResolveMethod.invoke(result); + } catch (final IllegalAccessException e) { + throw new ObjectAccessException("Could not call " + result.getClass().getName() + ".readResolve()", + e); + } catch (final InvocationTargetException e) { + throw new ObjectAccessException("Could not call " + result.getClass().getName() + ".readResolve()", + e.getTargetException()); } } else { return result; } } } - public Object callWriteReplace(Object object) { + public Object callWriteReplace(final Object object) { if (object == null) { return null; } else { - Method writeReplaceMethod = getMethod(object.getClass(), "writeReplace", null, true); + final Method writeReplaceMethod = getMethod(object.getClass(), "writeReplace", true); if (writeReplaceMethod != null) { try { - Object[] EMPTY_ARGS = new Object[0]; - return writeReplaceMethod.invoke(object, EMPTY_ARGS); - } catch (IllegalAccessException e) { - throw new ObjectAccessException("Could not call " + object.getClass().getName() + ".writeReplace()", e); - } catch (InvocationTargetException e) { - throw new ObjectAccessException("Could not call " + object.getClass().getName() + ".writeReplace()", e); + return writeReplaceMethod.invoke(object); + } catch (final IllegalAccessException e) { + throw new ObjectAccessException( + "Could not call " + object.getClass().getName() + ".writeReplace()", e); + } catch (final InvocationTargetException e) { + throw new ObjectAccessException( + "Could not call " + object.getClass().getName() + ".writeReplace()", e.getTargetException()); } } else { return object; } } } - public boolean supportsReadObject(Class type, boolean includeBaseClasses) { - return getMethod(type, "readObject", new Class[]{ObjectInputStream.class}, includeBaseClasses) != null; + public boolean supportsReadObject(final Class type, final boolean includeBaseClasses) { + return getMethod(type, "readObject", includeBaseClasses, ObjectInputStream.class) != null; } - public void callReadObject(Class type, Object object, ObjectInputStream stream) { + public void callReadObject(final Class type, final Object object, final ObjectInputStream stream) { try { - Method readObjectMethod = getMethod(type, "readObject", new Class[]{ObjectInputStream.class}, false); - readObjectMethod.invoke(object, new Object[]{stream}); - } catch (IllegalAccessException e) { + final Method readObjectMethod = getMethod(type, "readObject", false, ObjectInputStream.class); + readObjectMethod.invoke(object, stream); + } catch (final IllegalAccessException e) { throw new ConversionException("Could not call " + object.getClass().getName() + ".readObject()", e); - } catch (InvocationTargetException e) { - throw new ConversionException("Could not call " + object.getClass().getName() + ".readObject()", e); + } catch (final InvocationTargetException e) { + throw new ConversionException("Could not call " + object.getClass().getName() + ".readObject()", e + .getTargetException()); } } - public boolean supportsWriteObject(Class type, boolean includeBaseClasses) { - return getMethod(type, "writeObject", new Class[]{ObjectOutputStream.class}, includeBaseClasses) != null; + public boolean supportsWriteObject(final Class type, final boolean includeBaseClasses) { + return getMethod(type, "writeObject", includeBaseClasses, ObjectOutputStream.class) != null; } - public void callWriteObject(Class type, Object instance, ObjectOutputStream stream) { + public void callWriteObject(final Class type, final Object instance, final ObjectOutputStream stream) { try { - Method readObjectMethod = getMethod(type, "writeObject", new Class[]{ObjectOutputStream.class}, false); - readObjectMethod.invoke(instance, new Object[]{stream}); - } catch (IllegalAccessException e) { + final Method readObjectMethod = getMethod(type, "writeObject", false, ObjectOutputStream.class); + readObjectMethod.invoke(instance, stream); + } catch (final IllegalAccessException e) { throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e); - } catch (InvocationTargetException e) { - throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e); + } catch (final InvocationTargetException e) { + throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e + .getTargetException()); } } - private Method getMethod(Class type, String name, Class[] parameterTypes, boolean includeBaseclasses) { - Object key = type.getName() + "." + name + "." + includeBaseclasses; - if (cache.containsKey(key)) { - Object result = cache.get(key); - return (Method) (result == NO_METHOD ? null : result); + private Method getMethod(final Class type, final String name, final boolean includeBaseclasses, + final Class... parameterTypes) { + final Method method = getMethod(type, name, parameterTypes); + return method == NO_METHOD || !includeBaseclasses && !method.getDeclaringClass().equals(type) ? null : method; + } + + private Method getMethod(final Class type, final String name, final Class... parameterTypes) { + if (type == null) { + return null; } - if (includeBaseclasses) { - while (type != null) { - try { - Method result = type.getDeclaredMethod(name, parameterTypes); + final FastField method = new FastField(type, name); + Method result = cache.get(method); + + if (result == null) { + try { + result = type.getDeclaredMethod(name, parameterTypes); + if (!result.isAccessible()) { result.setAccessible(true); - cache.put(key, result); - return result; - } catch (NoSuchMethodException e) { - type = type.getSuperclass(); } + } catch (final NoSuchMethodException e) { + result = getMethod(type.getSuperclass(), name, parameterTypes); } - cache.put(key, NO_METHOD); - return null; - } else { - try { - Method result = type.getDeclaredMethod(name, parameterTypes); - result.setAccessible(true); - cache.put(key, result); - return result; - } catch (NoSuchMethodException e) { - cache.put(key, NO_METHOD); - return null; - } + cache.put(method, result); } + return result; } + @Override + public void flushCache() { + cache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS)); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SortableFieldKeySorter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SortableFieldKeySorter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SortableFieldKeySorter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2007, 2009, 2011, 2014 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 10. April 2007 by Guilherme Silveira + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.thoughtworks.xstream.core.Caching; +import com.thoughtworks.xstream.io.StreamException; + + +/** + * The default implementation for sorting fields. Invoke registerFieldOrder in order to set the field order for an + * specific type. + * + * @author Guilherme Silveira + * @since 1.2.2 + */ +public class SortableFieldKeySorter implements FieldKeySorter, Caching { + + private final Map, Comparator> map = new HashMap, Comparator>(); + + @Override + public Map sort(final Class type, final Map keyedByFieldKey) { + if (map.containsKey(type)) { + final Map result = new LinkedHashMap(); + final FieldKey[] fieldKeys = keyedByFieldKey.keySet().toArray(new FieldKey[keyedByFieldKey.size()]); + Arrays.sort(fieldKeys, map.get(type)); + for (final FieldKey fieldKey : fieldKeys) { + result.put(fieldKey, keyedByFieldKey.get(fieldKey)); + } + return result; + } else { + return keyedByFieldKey; + } + } + + /** + * Registers the field order to use for a specific type. This will not affect any of the type's super or sub + * classes. If you skip a field which will be serialized, XStream will thrown an StreamException during the + * serialization process. + * + * @param type the type + * @param fields the field order + */ + public void registerFieldOrder(final Class type, final String[] fields) { + map.put(type, new FieldComparator(fields)); + } + + private class FieldComparator implements Comparator { + + private final String[] fieldOrder; + + public FieldComparator(final String[] fields) { + fieldOrder = fields; + } + + private int compare(final String first, final String second) { + int firstPosition = -1, secondPosition = -1; + for (int i = 0; i < fieldOrder.length; i++) { + if (fieldOrder[i].equals(first)) { + firstPosition = i; + } + if (fieldOrder[i].equals(second)) { + secondPosition = i; + } + } + if (firstPosition == -1 || secondPosition == -1) { + // field not defined!!! + throw new StreamException("You have not given XStream a list of all fields to be serialized."); + } + return firstPosition - secondPosition; + } + + @Override + public int compare(final FieldKey first, final FieldKey second) { + return compare(first.getFieldName(), second.getFieldName()); + } + + } + + @Override + public void flushCache() { + map.clear(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/Sun14ReflectionProvider.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/Sun14ReflectionProvider.java (.../Sun14ReflectionProvider.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/Sun14ReflectionProvider.java (.../Sun14ReflectionProvider.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,115 +1,45 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2011, 2013, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.converters.reflection; -import sun.misc.Unsafe; -import sun.reflect.ReflectionFactory; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Map; -import java.util.Collections; - /** - * Instantiates a new object on the Sun JVM by bypassing the constructor (meaning code in the constructor - * will never be executed and parameters do not have to be known). This is the same method used by the internals of - * standard Java serialization, but relies on internal Sun code that may not be present on all JVMs. - * + * Instantiates a new object on the Sun JVM by bypassing the constructor (meaning code in the constructor will never be + * executed and parameters do not have to be known). This is the same method used by the internals of standard Java + * serialization, but relies on internal Sun code that may not be present on all JVMs. + * * @author Joe Walnes * @author Brian Slesinsky + * @deprecated As of upcoming use {@link SunUnsafeReflectionProvider} */ -public class Sun14ReflectionProvider extends PureJavaReflectionProvider { - - private final ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory(); - private Unsafe cachedUnsafe; - private final Map constructorCache = Collections.synchronizedMap(new HashMap()); - - private Unsafe getUnsafe() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { - if (cachedUnsafe != null) { - return cachedUnsafe; - } - Class objectStreamClass = Class.forName("java.io.ObjectStreamClass$FieldReflector"); - Field unsafeField = objectStreamClass.getDeclaredField("unsafe"); - unsafeField.setAccessible(true); - cachedUnsafe = (Unsafe) unsafeField.get(null); - return cachedUnsafe; +@Deprecated +public class Sun14ReflectionProvider extends SunUnsafeReflectionProvider { + /** + * @deprecated As of upcoming use {@link SunUnsafeReflectionProvider#SunUnsafeReflectionProvider()} + */ + @Deprecated + public Sun14ReflectionProvider() { + super(); } - public Object newInstance(Class type) { - try { - Constructor customConstructor = getMungedConstructor(type); - return customConstructor.newInstance(new Object[0]); - } catch (NoSuchMethodException e) { - throw new ObjectAccessException("Cannot construct " + type.getName(), e); - } catch (SecurityException e) { - throw new ObjectAccessException("Cannot construct " + type.getName(), e); - } catch (InstantiationException e) { - throw new ObjectAccessException("Cannot construct " + type.getName(), e); - } catch (IllegalAccessException e) { - throw new ObjectAccessException("Cannot construct " + type.getName(), e); - } catch (IllegalArgumentException e) { - throw new ObjectAccessException("Cannot construct " + type.getName(), e); - } catch (InvocationTargetException e) { - throw new ObjectAccessException("Cannot construct " + type.getName(), e); - } + /** + * @deprecated As of upcoming use {@link SunUnsafeReflectionProvider#SunUnsafeReflectionProvider(FieldDictionary)} + */ + @Deprecated + public Sun14ReflectionProvider(final FieldDictionary dic) { + super(dic); } - private Constructor getMungedConstructor(Class type) throws NoSuchMethodException { - if (!constructorCache.containsKey(type)) { - Constructor javaLangObjectConstructor = Object.class.getDeclaredConstructor(new Class[0]); - Constructor customConstructor = reflectionFactory.newConstructorForSerialization(type, javaLangObjectConstructor); - constructorCache.put(type, customConstructor); - } - return (Constructor) constructorCache.get(type); + private Object readResolve() { + init(); + return this; } - - public void writeField(Object object, String fieldName, Object value, Class definedIn) { - write(fieldDictionary.field(object.getClass(), fieldName, definedIn), object, value); - } - - private void write(Field field, Object object, Object value) { - try { - Unsafe unsafe = getUnsafe(); - long offset = unsafe.objectFieldOffset(field); - Class type = field.getType(); - if (type.isPrimitive()) { - if (type.equals(Integer.TYPE)) { - unsafe.putInt(object, offset, ((Integer) value).intValue()); - } else if (type.equals(Long.TYPE)) { - unsafe.putLong(object, offset, ((Long) value).longValue()); - } else if (type.equals(Short.TYPE)) { - unsafe.putShort(object, offset, ((Short) value).shortValue()); - } else if (type.equals(Character.TYPE)) { - unsafe.putChar(object, offset, ((Character) value).charValue()); - } else if (type.equals(Byte.TYPE)) { - unsafe.putByte(object, offset, ((Byte) value).byteValue()); - } else if (type.equals(Float.TYPE)) { - unsafe.putFloat(object, offset, ((Float) value).floatValue()); - } else if (type.equals(Double.TYPE)) { - unsafe.putDouble(object, offset, ((Double) value).doubleValue()); - } else if (type.equals(Boolean.TYPE)) { - unsafe.putBoolean(object, offset, ((Boolean) value).booleanValue()); - } else { - throw new ObjectAccessException("Could not set field " + - object.getClass() + "." + field.getName() + - ": Unknown type " + type); - } - } else { - unsafe.putObject(object, offset, value); - } - - } catch (IllegalArgumentException e) { - throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); - } catch (IllegalAccessException e) { - throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); - } catch (NoSuchFieldException e) { - throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); - } catch (ClassNotFoundException e) { - throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); - } - } - - protected void validateFieldAccess(Field field) { - // (overriden) don't mind final fields. - } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProvider.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProvider.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProvider.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2011, 2013, 2014 XStream Committers. + * All rights reserved. + * + * Created on 08. January 2014 by Joerg Schaible, factored out from SunUnsafeReflectionProvider + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + + +/** + * Instantiates a new object bypassing the constructor using undocumented internal JDK features. + *

+ * The code in the constructor will never be executed and parameters do not have to be known. This is the same method + * used by the internals of standard Java serialization, but relies on internal code (sun.misc.Unsafe) that may not be + * present on all JVMs. + *

+ *

+ * The implementation will use standard Java functionality to write any fields. This requires Java 5 as minimum runtime + * and is used as fallback on platforms that do not provide the complete implementation level for the internals (like + * Dalvik). + *

+ * + * @author Jörg Schaible + * @author Joe Walnes + * @author Brian Slesinsky + * @since 1.4.7 + */ +public class SunLimitedUnsafeReflectionProvider extends PureJavaReflectionProvider { + + protected static final Unsafe unsafe; + protected static final Exception exception; + static { + Unsafe u = null; + Exception ex = null; + try { + final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + u = (Unsafe)unsafeField.get(null); + } catch (final SecurityException e) { + ex = e; + } catch (final NoSuchFieldException e) { + ex = e; + } catch (final IllegalArgumentException e) { + ex = e; + } catch (final IllegalAccessException e) { + ex = e; + } + exception = ex; + unsafe = u; + } + + /** + * @since 1.4.7 + */ + public SunLimitedUnsafeReflectionProvider() { + super(); + } + + /** + * @since 1.4.7 + */ + public SunLimitedUnsafeReflectionProvider(final FieldDictionary fieldDictionary) { + super(fieldDictionary); + } + + @Override + public Object newInstance(final Class type) { + if (exception != null) { + throw new ObjectAccessException("Cannot construct " + type.getName(), exception); + } + try { + return unsafe.allocateInstance(type); + } catch (final SecurityException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (final InstantiationException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (final IllegalArgumentException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } + } + + @Override + protected void validateFieldAccess(final Field field) { + // (overriden) don't mind final fields. + } + + private Object readResolve() { + init(); + return this; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SunUnsafeReflectionProvider.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SunUnsafeReflectionProvider.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/SunUnsafeReflectionProvider.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2011, 2013, 2014 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 08. January 2014 by Joerg Schaible, renamed from Sun14ReflectionProvider + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + + +/** + * Instantiates a new object bypassing the constructor using undocumented internal JDK features. + *

+ * The code in the constructor will never be executed and parameters do not have to be known. This is the same method + * used by the internals of standard Java serialization, but relies on internal code (sun.misc.Unsafe) that may not be + * present on all JVMs. + *

+ *

+ * The implementation will use the same internals to write into fields. This is a lot faster and was additionally the + * only possibility to set final fields prior to Java 5. + *

+ * + * @author Joe Walnes + * @author Brian Slesinsky + * @author Jörg Schaible + * @since 1.4.7 + */ +public class SunUnsafeReflectionProvider extends SunLimitedUnsafeReflectionProvider { + + // references to the Field key are kept in the FieldDictionary + private transient Map fieldOffsetCache; + + /** + * @since 1.4.7 + */ + public SunUnsafeReflectionProvider() { + super(); + } + + /** + * @since 1.4.7 + */ + public SunUnsafeReflectionProvider(final FieldDictionary dic) { + super(dic); + } + + @Override + public void writeField(final Object object, final String fieldName, final Object value, final Class definedIn) { + write(fieldDictionary.field(object.getClass(), fieldName, definedIn), object, value); + } + + private void write(final Field field, final Object object, final Object value) { + if (exception != null) { + throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), + exception); + } + try { + final long offset = getFieldOffset(field); + final Class type = field.getType(); + if (type.isPrimitive()) { + if (type.equals(Integer.TYPE)) { + unsafe.putInt(object, offset, ((Integer)value).intValue()); + } else if (type.equals(Long.TYPE)) { + unsafe.putLong(object, offset, ((Long)value).longValue()); + } else if (type.equals(Short.TYPE)) { + unsafe.putShort(object, offset, ((Short)value).shortValue()); + } else if (type.equals(Character.TYPE)) { + unsafe.putChar(object, offset, ((Character)value).charValue()); + } else if (type.equals(Byte.TYPE)) { + unsafe.putByte(object, offset, ((Byte)value).byteValue()); + } else if (type.equals(Float.TYPE)) { + unsafe.putFloat(object, offset, ((Float)value).floatValue()); + } else if (type.equals(Double.TYPE)) { + unsafe.putDouble(object, offset, ((Double)value).doubleValue()); + } else if (type.equals(Boolean.TYPE)) { + unsafe.putBoolean(object, offset, ((Boolean)value).booleanValue()); + } else { + throw new ObjectAccessException("Could not set field " + + object.getClass() + + "." + + field.getName() + + ": Unknown type " + + type); + } + } else { + unsafe.putObject(object, offset, value); + } + + } catch (final IllegalArgumentException e) { + throw new ObjectAccessException("Could not set field " + object.getClass() + "." + field.getName(), e); + } + } + + private synchronized long getFieldOffset(final Field f) { + Long l = fieldOffsetCache.get(f); + if (l == null) { + l = Long.valueOf(unsafe.objectFieldOffset(f)); + fieldOffsetCache.put(f, l); + } + + return l.longValue(); + } + + private Object readResolve() { + init(); + return this; + } + + @Override + protected void init() { + super.init(); + fieldOffsetCache = new HashMap(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/XStream12FieldKeySorter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/XStream12FieldKeySorter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/converters/reflection/XStream12FieldKeySorter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007, 2008, 2013, 2014 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 19.09.2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.reflection; + +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; + + +/** + * Sort the fields in the order of XStream 1.2.x. Fields are returned in their declaration order, fields of base classes + * last. + * + * @author Jörg Schaible + * @since 1.3 + */ +public class XStream12FieldKeySorter implements FieldKeySorter { + + @Override + public Map sort(final Class type, final Map keyedByFieldKey) { + final Map map = new TreeMap(new Comparator() { + + @Override + public int compare(final FieldKey fieldKey1, final FieldKey fieldKey2) { + int i = fieldKey2.getDepth() - fieldKey1.getDepth(); + if (i == 0) { + i = fieldKey1.getOrder() - fieldKey2.getOrder(); + } + return i; + } + }); + map.putAll(keyedByFieldKey); + keyedByFieldKey.clear(); + keyedByFieldKey.putAll(map); + return keyedByFieldKey; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/AbstractReferenceMarshaller.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/AbstractReferenceMarshaller.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/AbstractReferenceMarshaller.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2014 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 15. March 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.core; + +import java.util.Iterator; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.core.util.ObjectIdDictionary; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.path.Path; +import com.thoughtworks.xstream.io.path.PathTracker; +import com.thoughtworks.xstream.io.path.PathTrackingWriter; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Abstract base class for a TreeMarshaller, that can build references. + * + * @author Joe Walnes + * @author Jörg Schaible + * @author Mauro Talevi + * @since 1.2 + */ +public abstract class AbstractReferenceMarshaller extends TreeMarshaller implements MarshallingContext { + + private final ObjectIdDictionary> references = new ObjectIdDictionary>(); + private final ObjectIdDictionary implicitElements = new ObjectIdDictionary(); + private final PathTracker pathTracker = new PathTracker(); + private Path lastPath; + + public AbstractReferenceMarshaller( + final HierarchicalStreamWriter writer, final ConverterLookup converterLookup, final Mapper mapper) { + super(writer, converterLookup, mapper); + this.writer = new PathTrackingWriter(writer, pathTracker); + } + + @Override + public void convert(final Object item, final Converter converter) { + if (getMapper().isImmutableValueType(item.getClass())) { + // strings, ints, dates, etc... don't bother using references. + converter.marshal(item, writer, this); + } else { + final Path currentPath = pathTracker.getPath(); + final Id existingReference = references.lookupId(item); + if (existingReference != null && existingReference.getPath() != currentPath) { + final String attributeName = getMapper().aliasForSystemAttribute("reference"); + if (attributeName != null) { + writer.addAttribute(attributeName, createReference(currentPath, existingReference.getItem())); + } + } else { + final R newReferenceKey = existingReference == null + ? createReferenceKey(currentPath, item) + : existingReference.getItem(); + if (lastPath == null || !currentPath.isAncestor(lastPath)) { + fireValidReference(newReferenceKey); + lastPath = currentPath; + references.associateId(item, new Id(newReferenceKey, currentPath)); + } + converter.marshal(item, writer, new ReferencingMarshallingContext() { + + @Override + public void put(final Object key, final Object value) { + AbstractReferenceMarshaller.this.put(key, value); + } + + @Override + public Iterator keys() { + return AbstractReferenceMarshaller.this.keys(); + } + + @Override + public Object get(final Object key) { + return AbstractReferenceMarshaller.this.get(key); + } + + @Override + public void convertAnother(final Object nextItem, final Converter converter) { + AbstractReferenceMarshaller.this.convertAnother(nextItem, converter); + } + + @Override + public void convertAnother(final Object nextItem) { + AbstractReferenceMarshaller.this.convertAnother(nextItem); + } + + @Override + public void replace(final Object original, final Object replacement) { + references.associateId(replacement, new Id(newReferenceKey, currentPath)); + } + + @Override + public R lookupReference(final Object item) { + final Id id = references.lookupId(item); + return id.getItem(); + } + + /** + * @deprecated As of 1.4.2 + */ + @Deprecated + @Override + public Path currentPath() { + return pathTracker.getPath(); + } + + @Override + public void registerImplicit(final Object item) { + if (implicitElements.containsId(item)) { + throw new ReferencedImplicitElementException(item, currentPath); + } + implicitElements.associateId(item, newReferenceKey); + } + }); + } + } + } + + protected abstract String createReference(Path currentPath, R existingReferenceKey); + + protected abstract R createReferenceKey(Path currentPath, Object item); + + protected abstract void fireValidReference(R referenceKey); + + private static class Id { + private final R item; + private final Path path; + + public Id(final R item, final Path path) { + this.item = item; + this.path = path; + } + + protected R getItem() { + return item; + } + + protected Path getPath() { + return path; + } + } + + public static class ReferencedImplicitElementException extends ConversionException { + public ReferencedImplicitElementException(final Object item, final Path path) { + super("Cannot reference implicit element"); + add("implicit-element", item.toString()); + add("referencing-element", path.toString()); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/AbstractReferenceUnmarshaller.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/AbstractReferenceUnmarshaller.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/AbstractReferenceUnmarshaller.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2011, 2014 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 15. March 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.core; + +import java.util.HashMap; +import java.util.Map; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Abstract base class for a TreeUnmarshaller, that resolves references. + * + * @author Joe Walnes + * @author Jörg Schaible + * @author Mauro Talevi + * @since 1.2 + */ +public abstract class AbstractReferenceUnmarshaller extends TreeUnmarshaller { + + private static final Object NULL = new Object(); + private final Map values = new HashMap(); + private final FastStack parentStack = new FastStack(16); + + public AbstractReferenceUnmarshaller( + final Object root, final HierarchicalStreamReader reader, final ConverterLookup converterLookup, + final Mapper mapper) { + super(root, reader, converterLookup, mapper); + } + + @Override + protected Object convert(final Object parent, final Class type, final Converter converter) { + if (parentStack.size() > 0) { // handles circular references + final R parentReferenceKey = parentStack.peek(); + if (parentReferenceKey != null) { + // see AbstractCircularReferenceTest.testWeirdCircularReference() + if (!values.containsKey(parentReferenceKey)) { + values.put(parentReferenceKey, parent); + } + } + } + final Object result; + final String attributeName = getMapper().aliasForSystemAttribute("reference"); + final String reference = attributeName == null ? null : reader.getAttribute(attributeName); + if (reference != null) { + final Object cache = values.get(getReferenceKey(reference)); + if (cache == null) { + final ConversionException ex = new ConversionException("Invalid reference"); + ex.add("reference", reference); + throw ex; + } + result = cache == NULL ? null : cache; + } else { + final R currentReferenceKey = getCurrentReferenceKey(); + parentStack.push(currentReferenceKey); + result = super.convert(parent, type, converter); + if (currentReferenceKey != null) { + values.put(currentReferenceKey, result == null ? NULL : result); + } + parentStack.popSilently(); + } + return result; + } + + protected abstract R getReferenceKey(String reference); + + protected abstract R getCurrentReferenceKey(); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/AbstractTreeMarshallingStrategy.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/AbstractTreeMarshallingStrategy.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/AbstractTreeMarshallingStrategy.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009, 2014 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.09.2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.MarshallingStrategy; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Basic functionality of a tree based marshalling strategy. + * + * @author Joe Walnes + * @author Jörg Schaible + * @since 1.3 + */ +public abstract class AbstractTreeMarshallingStrategy implements MarshallingStrategy { + + @Override + public Object unmarshal(final Object root, final HierarchicalStreamReader reader, final DataHolder dataHolder, + final ConverterLookup converterLookup, final Mapper mapper) { + final TreeUnmarshaller context = createUnmarshallingContext(root, reader, converterLookup, mapper); + return context.start(dataHolder); + } + + @Override + public void marshal(final HierarchicalStreamWriter writer, final Object obj, final ConverterLookup converterLookup, + final Mapper mapper, final DataHolder dataHolder) { + final TreeMarshaller context = createMarshallingContext(writer, converterLookup, mapper); + context.start(obj, dataHolder); + } + + protected abstract TreeUnmarshaller createUnmarshallingContext(Object root, HierarchicalStreamReader reader, + ConverterLookup converterLookup, Mapper mapper); + + protected abstract TreeMarshaller createMarshallingContext(HierarchicalStreamWriter writer, + ConverterLookup converterLookup, Mapper mapper); +} Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/core/BaseException.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/Caching.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/Caching.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/Caching.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2011 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 19. July 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.core; + +/** + * Marker interface for caching implementations. + * + * @author Jörg Schaible + * @since 1.4 + */ +public interface Caching { + void flushCache(); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ClassLoaderReference.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ClassLoaderReference.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ClassLoaderReference.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2013 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. June 2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.core.util.CompositeClassLoader; + +/** + * Reference to a ClassLoader, allowing a single instance to be passed around the codebase that + * can later have its destination changed. + * + * @author Jörg Schaible + * @since 1.4.5 + */ +public final class ClassLoaderReference { + + private transient ClassLoader reference; + + public ClassLoaderReference(ClassLoader reference) { + setReference(reference); + } + + public ClassLoader getReference() { + return reference; + } + + public void setReference(ClassLoader reference) { + this.reference = reference instanceof com.thoughtworks.xstream.core.util.ClassLoaderReference + ? ((com.thoughtworks.xstream.core.util.ClassLoaderReference)reference) + .getReference() : reference; + } + + private Object readResolve() { + this.reference = new CompositeClassLoader(); + return this; + } +} Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/core/DefaultClassMapper.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/DefaultConverterLookup.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/DefaultConverterLookup.java (.../DefaultConverterLookup.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/DefaultConverterLookup.java (.../DefaultConverterLookup.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,55 +1,82 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.alias.ClassMapper; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; + import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.ConverterLookup; -import com.thoughtworks.xstream.converters.basic.NullConverter; +import com.thoughtworks.xstream.converters.ConverterRegistry; import com.thoughtworks.xstream.core.util.PrioritizedList; -import com.thoughtworks.xstream.XStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -public class DefaultConverterLookup implements ConverterLookup { +/** + * The default implementation of converters lookup. + * + * @author Joe Walnes + * @author Jörg Schaible + * @author Guilherme Silveira + */ +public class DefaultConverterLookup implements ConverterLookup, ConverterRegistry, Caching { - private final PrioritizedList converters = new PrioritizedList(); - private final Converter nullConverter = new NullConverter(); - private final Map typeToConverterMap = Collections.synchronizedMap(new HashMap()); - private final ClassMapper classMapper; + private final PrioritizedList converters = new PrioritizedList(); + private transient Map, Converter> typeToConverterMap; - public DefaultConverterLookup(ClassMapper classMapper) { - this.classMapper = classMapper; + public DefaultConverterLookup() { + readResolve(); } - /** - * @deprecated As of 1.1.1 you can register Converters with priorities, making the need for a default converter redundant. - */ - public Converter defaultConverter() { - return (Converter) converters.firstOfLowestPriority(); - } - - public Converter lookupConverterForType(Class type) { - if (type == null) { - return nullConverter; + @Override + public Converter lookupConverterForType(final Class type) { + final Converter cachedConverter = typeToConverterMap.get(type); + if (cachedConverter != null) { + return cachedConverter; } - Converter cachedConverter = (Converter) typeToConverterMap.get(type); - if (cachedConverter != null) return cachedConverter; - Class mapType = classMapper.defaultImplementationOf(type); - Iterator iterator = converters.iterator(); - while (iterator.hasNext()) { - Converter converter = (Converter) iterator.next(); - if (converter.canConvert(mapType)) { - typeToConverterMap.put(type, converter); + for (final Converter converter : converters) { + if (converter.canConvert(type)) { return converter; } } throw new ConversionException("No converter specified for " + type); } - public void registerConverter(Converter converter, int priority) { + + @Override + public void registerConverter(final Converter converter, final int priority) { converters.add(converter, priority); + for (final Iterator> iter = typeToConverterMap.keySet().iterator(); iter.hasNext();) { + final Class type = iter.next(); + if (converter.canConvert(type)) { + iter.remove(); + } + } } + @Override + public void flushCache() { + typeToConverterMap.clear(); + for (final Converter converter : converters) { + if (converter instanceof Caching) { + ((Caching)converter).flushCache(); + } + } + } + + private Object readResolve() { + // TODO: Use ConcurrentMap + typeToConverterMap = Collections.synchronizedMap(new WeakHashMap, Converter>()); + return this; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/JVM.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/JVM.java (.../JVM.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/JVM.java (.../JVM.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,97 +1,555 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014 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 09. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.text.AttributedString; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Comparator; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; + +import com.thoughtworks.xstream.converters.reflection.FieldDictionary; +import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; +import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; +import com.thoughtworks.xstream.core.util.DependencyInjectionFactory; +import com.thoughtworks.xstream.core.util.PresortedMap; +import com.thoughtworks.xstream.core.util.PresortedSet; -import java.security.AccessControlException; -public class JVM { +public class JVM implements Caching { private ReflectionProvider reflectionProvider; - private static final float majorJavaVersion = getMajorJavaVersion(System.getProperty("java.version")); + private static final boolean isAWTAvailable; + private static final boolean isSwingAvailable; + private static final boolean isSQLAvailable; + private static final boolean canAllocateWithUnsafe; + private static final boolean canWriteWithUnsafe; + private static final boolean optimizedTreeSetAddAll; + private static final boolean optimizedTreeMapPutAll; + private static final boolean canParseUTCDateFormat; + private static final boolean canCreateDerivedObjectOutputStream; - static final float DEFAULT_JAVA_VERSION = 1.3f; - + private static final String vendor = System.getProperty("java.vm.vendor"); + private static final float majorJavaVersion = getMajorJavaVersion(); + private static final float DEFAULT_JAVA_VERSION = 1.4f; + private static final boolean reverseFieldOrder = false; + private static final Class reflectionProviderType; + + static class Test { + @SuppressWarnings("unused") + private Object o; + @SuppressWarnings("unused") + private char c; + @SuppressWarnings("unused") + private byte b; + @SuppressWarnings("unused") + private short s; + @SuppressWarnings("unused") + private int i; + @SuppressWarnings("unused") + private long l; + @SuppressWarnings("unused") + private float f; + @SuppressWarnings("unused") + private double d; + @SuppressWarnings("unused") + private boolean bool; + + Test() { + throw new UnsupportedOperationException(); + } + } + + static { + boolean test = true; + Object unsafe = null; + try { + final Class unsafeClass = Class.forName("sun.misc.Unsafe"); + final Field unsafeField = unsafeClass.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + unsafe = unsafeField.get(null); + final Method allocateInstance = unsafeClass.getDeclaredMethod("allocateInstance", new Class[]{Class.class}); + allocateInstance.setAccessible(true); + test = allocateInstance.invoke(unsafe, new Object[]{Test.class}) != null; + } catch (final Exception e) { + test = false; + } catch (final Error e) { + test = false; + } + canAllocateWithUnsafe = test; + test = false; + Class type = PureJavaReflectionProvider.class; + if (canUseSunUnsafeReflectionProvider()) { + Class cls = loadClassForName("com.thoughtworks.xstream.converters.reflection.SunUnsafeReflectionProvider"); + if (cls != null) { + try { + final ReflectionProvider provider = DependencyInjectionFactory.newInstance(cls); + final Test t = (Test)provider.newInstance(Test.class); + try { + provider.writeField(t, "o", "object", Test.class); + provider.writeField(t, "c", new Character('c'), Test.class); + provider.writeField(t, "b", new Byte((byte)1), Test.class); + provider.writeField(t, "s", new Short((short)1), Test.class); + provider.writeField(t, "i", new Integer(1), Test.class); + provider.writeField(t, "l", new Long(1), Test.class); + provider.writeField(t, "f", new Float(1), Test.class); + provider.writeField(t, "d", new Double(1), Test.class); + provider.writeField(t, "bool", Boolean.TRUE, Test.class); + test = true; + } catch (final IncompatibleClassChangeError e) { + cls = null; + } catch (final ObjectAccessException e) { + cls = null; + } + if (cls == null) { + cls = loadClassForName("com.thoughtworks.xstream.converters.reflection.SunLimitedUnsafeReflectionProvider"); + } + type = cls; + } catch (final ObjectAccessException e) { + } + } + } + reflectionProviderType = type; + canWriteWithUnsafe = test; + final Comparator comparator = new Comparator() { + @Override + public int compare(final Object o1, final Object o2) { + throw new RuntimeException(); + } + }; + final SortedMap map = new PresortedMap(comparator); + map.put("one", null); + map.put("two", null); + try { + new TreeMap(comparator).putAll(map); + test = true; + } catch (final RuntimeException e) { + test = false; + } + optimizedTreeMapPutAll = test; + final SortedSet set = new PresortedSet(comparator); + set.addAll(map.keySet()); + try { + new TreeSet(comparator).addAll(set); + test = true; + } catch (final RuntimeException e) { + test = false; + } + optimizedTreeSetAddAll = test; + try { + new SimpleDateFormat("z").parse("UTC"); + test = true; + } catch (final ParseException e) { + test = false; + } + canParseUTCDateFormat = test; + try { + test = new CustomObjectOutputStream(null) != null; + } catch (final RuntimeException e) { + test = false; + } catch (final IOException e) { + test = false; + } + canCreateDerivedObjectOutputStream = test; + + isAWTAvailable = loadClassForName("java.awt.Color", false) != null; + isSwingAvailable = loadClassForName("javax.swing.LookAndFeel", false) != null; + isSQLAvailable = loadClassForName("java.sql.Date") != null; + } + /** - * Parses the java version system property to determine the major java version, - * ie 1.x + * @deprecated As of 1.4.5 use the static methods of JVM. + */ + @Deprecated + public JVM() { + } + + /** + * Parses the java version system property to determine the major java version, i.e. 1.x * - * @param javaVersion the system property 'java.version' * @return A float of the form 1.x */ - static final float getMajorJavaVersion(String javaVersion) { - try { - return Float.parseFloat(javaVersion.substring(0, 3)); - } catch ( NumberFormatException e ){ + private static final float getMajorJavaVersion() { + try { + return isAndroid() ? 1.5f : Float.parseFloat(System.getProperty("java.specification.version")); + } catch (final NumberFormatException e) { // Some JVMs may not conform to the x.y.z java.version format return DEFAULT_JAVA_VERSION; } } + /** + * @deprecated As of 1.4.4, minimal JDK version is 1.4 already + */ + @Deprecated public static boolean is14() { return majorJavaVersion >= 1.4f; } + /** + * @deprecated As of 1.4.4, minimal JDK version will be 1.6 for next major release + */ + @Deprecated public static boolean is15() { return majorJavaVersion >= 1.5f; } - private static boolean isSun() { - return System.getProperty("java.vm.vendor").indexOf("Sun") != -1; + /** + * @deprecated As of 1.4.4, minimal JDK version will be 1.6 for next major release + */ + @Deprecated + public static boolean is16() { + return majorJavaVersion >= 1.6f; } - private static boolean isApple() { - return System.getProperty("java.vm.vendor").indexOf("Apple") != -1; + /** + * @since 1.4 + */ + public static boolean is17() { + return majorJavaVersion >= 1.7f; } - private static boolean isHPUX() { - return System.getProperty("java.vm.vendor").indexOf("Hewlett-Packard Company") != -1; + /** + * @since 1.4 + */ + public static boolean is18() { + return majorJavaVersion >= 1.8f; } private static boolean isIBM() { - return System.getProperty("java.vm.vendor").indexOf("IBM") != -1; + return vendor.indexOf("IBM") != -1; } - private static boolean isBlackdown() { - return System.getProperty("java.vm.vendor").indexOf("Blackdown") != -1; + /** + * @since 1.4 + */ + private static boolean isAndroid() { + return vendor.indexOf("Android") != -1; } - private static boolean isBEA() { - return System.getProperty("java.vm.vendor").indexOf("BEA") != -1; + /** + * Load a XStream class for the given name. + *

+ * This method is not meant to use loading arbitrary classes. It is used by XStream bootstrap until it is able to + * use the user provided or the default {@link ClassLoader}. + *

+ * + * @since 1.4.5 + */ + public static Class loadClassForName(final String name) { + return loadClassForName(name, true); } - public Class loadClass(String name) { + /** + * @deprecated As of 1.4.5 use {@link #loadClassForName(String)} + */ + @Deprecated + public Class loadClass(final String name) { + return loadClassForName(name, true); + } + + /** + * Load a XStream class for the given name. + *

+ * This method is not meant to use loading arbitrary classes. It is used by XStream bootstrap until it is able to + * use the user provided or the default {@link ClassLoader}. + *

+ * + * @since 1.4.5 + */ + public static Class loadClassForName(final String name, final boolean initialize) { try { - return Class.forName(name, false, getClass().getClassLoader()); - } catch (ClassNotFoundException e) { + @SuppressWarnings("unchecked") + final Class clazz = (Class)Class.forName(name, initialize, JVM.class + .getClassLoader()); + return clazz; + } catch (final LinkageError e) { return null; + } catch (final ClassNotFoundException e) { + return null; } } - + + /** + * @since 1.4.4 + * @deprecated As of 1.4.5 use {@link #loadClassForName(String, boolean)} + */ + @Deprecated + public Class loadClass(final String name, final boolean initialize) { + return loadClassForName(name, initialize); + } + + /** + * Create the best matching ReflectionProvider. + * + * @return a new instance + * @since 1.4.5 + */ + public static ReflectionProvider newReflectionProvider() { + return DependencyInjectionFactory.newInstance(reflectionProviderType); + } + + /** + * Create the best matching ReflectionProvider. + * + * @param dictionary the FieldDictionary to use by the ReflectionProvider + * @return a new instance + * @since 1.4.5 + */ + public static ReflectionProvider newReflectionProvider(final FieldDictionary dictionary) { + return DependencyInjectionFactory.newInstance(reflectionProviderType, dictionary); + } + + /** + * Get the XMLInputFactory implementation used normally by the current Java runtime as standard. + *

+ * In contrast to XMLInputFactory.newFactory() this method will ignore any implementations provided with the system + * property javax.xml.stream.XMLInputFactory, implementations configured in lib/stax.properties or + * registered with the Service API. + *

+ * + * @return the XMLInputFactory implementation or null + * @throws ClassNotFoundException if the standard class cannot be found + * @since 1.4.5 + */ + @SuppressWarnings("unchecked") + public static Class getStaxInputFactory() throws ClassNotFoundException { + if (is16()) { + if (isIBM()) { + return (Class)Class.forName("com.ibm.xml.xlxp.api.stax.XMLInputFactoryImpl"); + } else { + return (Class)Class + .forName("com.sun.xml.internal.stream.XMLInputFactoryImpl"); + } + } + return null; + } + + /** + * Get the XMLOutputFactory implementation used normally by the current Java runtime as standard. + *

+ * In contrast to XMLOutputFactory.newFactory() this method will ignore any implementations provided with the system + * property javax.xml.stream.XMLOutputFactory, implementations configured in lib/stax.properties + * or registered with the Service API. + *

+ * + * @return the XMLOutputFactory implementation or null + * @throws ClassNotFoundException if the standard class cannot be found + * @since 1.4.5 + */ + @SuppressWarnings("unchecked") + public static Class getStaxOutputFactory() throws ClassNotFoundException { + if (is16()) { + if (isIBM()) { + return (Class)Class + .forName("com.ibm.xml.xlxp.api.stax.XMLOutputFactoryImpl"); + } else { + return (Class)Class + .forName("com.sun.xml.internal.stream.XMLOutputFactoryImpl"); + } + } + return null; + } + + /** + * @deprecated As of 1.4.5 use {@link #newReflectionProvider()} + */ + @Deprecated public synchronized ReflectionProvider bestReflectionProvider() { if (reflectionProvider == null) { - try { - if ( canUseSun14ReflectionProvider() ) { - String cls = "com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider"; - reflectionProvider = (ReflectionProvider) loadClass(cls).newInstance(); - } else { - reflectionProvider = new PureJavaReflectionProvider(); - } - } catch (InstantiationException e) { - reflectionProvider = new PureJavaReflectionProvider(); - } catch (IllegalAccessException e) { - reflectionProvider = new PureJavaReflectionProvider(); - } catch (AccessControlException e) { - // thrown when trying to access sun.misc package in Applet context. - reflectionProvider = new PureJavaReflectionProvider(); - } + reflectionProvider = newReflectionProvider(); } return reflectionProvider; } - private boolean canUseSun14ReflectionProvider() { - return (isSun() || isApple() || isHPUX() || isIBM() || isBlackdown()) && is14() && loadClass("sun.misc.Unsafe") != null; - } + private static boolean canUseSunUnsafeReflectionProvider() { + return canAllocateWithUnsafe && is14(); + } + private static boolean canUseSunLimitedUnsafeReflectionProvider() { + return canWriteWithUnsafe; + } + + /** + * @deprecated As of 1.4.5 + */ + @Deprecated + public static boolean reverseFieldDefinition() { + return reverseFieldOrder; + } + + /** + * Checks if AWT is available. + * + * @since 1.4.5 + */ + public static boolean isAWTAvailable() { + return isAWTAvailable; + } + + /** + * Checks if the jvm supports awt. + * + * @deprecated As of 1.4.5 use {@link #isAWTAvailable()} + */ + @Deprecated + public boolean supportsAWT() { + return isAWTAvailable; + } + + /** + * Checks if Swing is available. + * + * @since 1.4.5 + */ + public static boolean isSwingAvailable() { + return isSwingAvailable; + } + + /** + * Checks if the jvm supports swing. + * + * @deprecated As of 1.4.5 use {@link #isSwingAvailable()} + */ + @Deprecated + public boolean supportsSwing() { + return isSwingAvailable; + } + + /** + * Checks if SQL is available. + * + * @since 1.4.5 + */ + public static boolean isSQLAvailable() { + return isSQLAvailable; + } + + /** + * Checks if the jvm supports sql. + * + * @deprecated As of 1.4.5 use {@link #isSQLAvailable()} + */ + @Deprecated + public boolean supportsSQL() { + return isSQLAvailable; + } + + /** + * Checks if TreeSet.addAll is optimized for SortedSet argument. + * + * @since 1.4 + */ + public static boolean hasOptimizedTreeSetAddAll() { + return optimizedTreeSetAddAll; + } + + /** + * Checks if TreeMap.putAll is optimized for SortedMap argument. + * + * @since 1.4 + */ + public static boolean hasOptimizedTreeMapPutAll() { + return optimizedTreeMapPutAll; + } + + public static boolean canParseUTCDateFormat() { + return canParseUTCDateFormat; + } + + /** + * @since 1.4.6 + */ + public static boolean canCreateDerivedObjectOutputStream() { + return canCreateDerivedObjectOutputStream; + } + + /** + * @deprecated As of 1.4.5 no functionality + */ + @Deprecated + @Override + public void flushCache() { + } + + public static void main(final String... args) { + boolean reverseJDK = false; + Field[] fields = AttributedString.class.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + if (fields[i].getName().equals("text")) { + reverseJDK = i > 3; + break; + } + } + + boolean reverseLocal = false; + fields = Test.class.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + if (fields[i].getName().equals("o")) { + reverseLocal = i > 3; + break; + } + } + + String staxInputFactory = null; + try { + staxInputFactory = getStaxInputFactory().getName(); + } catch (final ClassNotFoundException e) { + staxInputFactory = e.getMessage(); + } catch (final NullPointerException e) { + } + + String staxOutputFactory = null; + try { + staxOutputFactory = getStaxOutputFactory().getName(); + } catch (final ClassNotFoundException e) { + staxOutputFactory = e.getMessage(); + } catch (final NullPointerException e) { + } + + System.out.println("XStream JVM diagnostics"); + System.out.println("java.specification.version: " + System.getProperty("java.specification.version")); + System.out.println("java.specification.vendor: " + System.getProperty("java.specification.vendor")); + System.out.println("java.specification.name: " + System.getProperty("java.specification.name")); + System.out.println("java.vm.vendor: " + vendor); + System.out.println("java.vendor: " + System.getProperty("java.vendor")); + System.out.println("java.vm.name: " + System.getProperty("java.vm.name")); + System.out.println("Version: " + majorJavaVersion); + System.out.println("XStream support for enhanced Mode: " + canUseSunUnsafeReflectionProvider()); + System.out.println("XStream support for reduced Mode: " + canUseSunLimitedUnsafeReflectionProvider()); + System.out.println("Supports AWT: " + isAWTAvailable()); + System.out.println("Supports Swing: " + isSwingAvailable()); + System.out.println("Supports SQL: " + isSQLAvailable()); + System.out.println("Java Beans EventHandler present: " + (loadClassForName("java.beans.EventHandler") != null)); + System.out.println("Standard StAX XMLInputFactory: " + staxInputFactory); + System.out.println("Standard StAX XMLOutputFactory: " + staxOutputFactory); + System.out.println("Optimized TreeSet.addAll: " + hasOptimizedTreeSetAddAll()); + System.out.println("Optimized TreeMap.putAll: " + hasOptimizedTreeMapPutAll()); + System.out.println("Can parse UTC date format: " + canParseUTCDateFormat()); + System.out.println("Can create derive ObjectOutputStream: " + canCreateDerivedObjectOutputStream()); + System.out.println("Reverse field order detected for JDK: " + reverseJDK); + System.out + .println("Reverse field order detected (only if JVM class itself has been compiled): " + reverseLocal); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/MapBackedDataHolder.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/MapBackedDataHolder.java (.../MapBackedDataHolder.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/MapBackedDataHolder.java (.../MapBackedDataHolder.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,32 +1,47 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 04. October 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.converters.DataHolder; - import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import com.thoughtworks.xstream.converters.DataHolder; + + public class MapBackedDataHolder implements DataHolder { - private final Map map; + private final Map map; public MapBackedDataHolder() { - this(new HashMap()); + this(new HashMap()); } - public MapBackedDataHolder(Map map) { + public MapBackedDataHolder(final Map map) { this.map = map; } - public Object get(Object key) { + @Override + public Object get(final Object key) { return map.get(key); } - public void put(Object key, Object value) { + @Override + public void put(final Object key, final Object value) { map.put(key, value); } - public Iterator keys() { + @Override + public Iterator keys() { return Collections.unmodifiableCollection(map.keySet()).iterator(); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshaller.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshaller.java (.../ReferenceByIdMarshaller.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshaller.java (.../ReferenceByIdMarshaller.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,51 +1,57 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2014 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 15. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.alias.ClassMapper; -import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.ConverterLookup; -import com.thoughtworks.xstream.core.util.ObjectIdDictionary; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.path.Path; +import com.thoughtworks.xstream.mapper.Mapper; -public class ReferenceByIdMarshaller extends TreeMarshaller { - private ObjectIdDictionary references = new ObjectIdDictionary(); - private IDGenerator idGenerator; +public class ReferenceByIdMarshaller extends AbstractReferenceMarshaller { + private final IDGenerator idGenerator; + public static interface IDGenerator { - String next(); + String next(Object item); } - public ReferenceByIdMarshaller(HierarchicalStreamWriter writer, - ConverterLookup converterLookup, - ClassMapper classMapper, - IDGenerator idGenerator) { - super(writer, converterLookup, classMapper); + public ReferenceByIdMarshaller( + final HierarchicalStreamWriter writer, final ConverterLookup converterLookup, final Mapper mapper, + final IDGenerator idGenerator) { + super(writer, converterLookup, mapper); this.idGenerator = idGenerator; } - public ReferenceByIdMarshaller(HierarchicalStreamWriter writer, - ConverterLookup converterLookup, - ClassMapper classMapper) { - this(writer, converterLookup, classMapper, new SequenceGenerator(1)); + public ReferenceByIdMarshaller( + final HierarchicalStreamWriter writer, final ConverterLookup converterLookup, final Mapper mapper) { + this(writer, converterLookup, mapper, new SequenceGenerator(1)); } - public void convertAnother(Object item) { - Converter converter = converterLookup.lookupConverterForType(item.getClass()); + @Override + protected String createReference(final Path currentPath, final String existingReferenceKey) { + return existingReferenceKey.toString(); + } - if (classMapper.isImmutableValueType(item.getClass())) { - // strings, ints, dates, etc... don't bother using references. - converter.marshal(item, writer, this); - } else { - Object idOfExistingReference = references.lookupId(item); - if (idOfExistingReference != null) { - writer.addAttribute("reference", idOfExistingReference.toString()); - } else { - String newId = idGenerator.next(); - writer.addAttribute("id", newId); - references.associateId(item, newId); - converter.marshal(item, writer, this); - } - } + @Override + protected String createReferenceKey(final Path currentPath, final Object item) { + return idGenerator.next(item); } + @Override + protected void fireValidReference(final String referenceKey) { + final String attributeName = getMapper().aliasForSystemAttribute("id"); + if (attributeName != null) { + writer.addAttribute(attributeName, referenceKey.toString()); + } + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshallingStrategy.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshallingStrategy.java (.../ReferenceByIdMarshallingStrategy.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdMarshallingStrategy.java (.../ReferenceByIdMarshallingStrategy.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,22 +1,33 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 16. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.MarshallingStrategy; -import com.thoughtworks.xstream.alias.ClassMapper; -import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.converters.ConverterLookup; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; -public class ReferenceByIdMarshallingStrategy implements MarshallingStrategy { - public Object unmarshal(Object root, HierarchicalStreamReader reader, DataHolder dataHolder, DefaultConverterLookup converterLookup, ClassMapper classMapper) { - return new ReferenceByIdUnmarshaller( - root, reader, converterLookup, - classMapper).start(dataHolder); - } +public class ReferenceByIdMarshallingStrategy extends AbstractTreeMarshallingStrategy { - public void marshal(HierarchicalStreamWriter writer, Object obj, DefaultConverterLookup converterLookup, ClassMapper classMapper, DataHolder dataHolder) { - new ReferenceByIdMarshaller( - writer, converterLookup, classMapper).start(obj, dataHolder); + @Override + protected TreeUnmarshaller createUnmarshallingContext(final Object root, final HierarchicalStreamReader reader, + final ConverterLookup converterLookup, final Mapper mapper) { + return new ReferenceByIdUnmarshaller(root, reader, converterLookup, mapper); } + @Override + protected TreeMarshaller createMarshallingContext(final HierarchicalStreamWriter writer, + final ConverterLookup converterLookup, final Mapper mapper) { + return new ReferenceByIdMarshaller(writer, converterLookup, mapper); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdUnmarshaller.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdUnmarshaller.java (.../ReferenceByIdUnmarshaller.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByIdUnmarshaller.java (.../ReferenceByIdUnmarshaller.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,41 +1,37 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2014 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 15. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.alias.ClassMapper; import com.thoughtworks.xstream.converters.ConverterLookup; -import com.thoughtworks.xstream.core.util.FastStack; import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.mapper.Mapper; -import java.util.HashMap; -import java.util.Map; -public class ReferenceByIdUnmarshaller extends TreeUnmarshaller { +public class ReferenceByIdUnmarshaller extends AbstractReferenceUnmarshaller { - private Map values = new HashMap(); - private FastStack parentIdStack = new FastStack(16); - - public ReferenceByIdUnmarshaller(Object root, HierarchicalStreamReader reader, - ConverterLookup converterLookup, ClassMapper classMapper) { - super(root, reader, converterLookup, classMapper); + public ReferenceByIdUnmarshaller( + final Object root, final HierarchicalStreamReader reader, final ConverterLookup converterLookup, + final Mapper mapper) { + super(root, reader, converterLookup, mapper); } - public Object convertAnother(Object parent, Class type) { - if (parentIdStack.size() > 0) { // handles circular references - Object parentId = parentIdStack.peek(); - if (!values.containsKey(parentId)) { // see AbstractCircularReferenceTest.testWeirdCircularReference() - values.put(parentId, parent); - } - } - String reference = reader.getAttribute("reference"); - if (reference != null) { - return values.get(reference); - } else { - String currentId = reader.getAttribute("id"); - parentIdStack.push(currentId); - Object result = super.convertAnother(parent, type); - values.put(currentId, result); - parentIdStack.popSilently(); - return result; - } + @Override + protected String getReferenceKey(final String reference) { + return reference; } + @Override + protected String getCurrentReferenceKey() { + final String attributeName = getMapper().aliasForSystemAttribute("id"); + return attributeName == null ? null : reader.getAttribute(attributeName); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshaller.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshaller.java (.../ReferenceByXPathMarshaller.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshaller.java (.../ReferenceByXPathMarshaller.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,41 +1,50 @@ +/* + * Copyright (C) 2004, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2014 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 03. April 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.alias.ClassMapper; -import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.ConverterLookup; -import com.thoughtworks.xstream.core.util.ObjectIdDictionary; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.path.Path; -import com.thoughtworks.xstream.io.path.PathTracker; -import com.thoughtworks.xstream.io.path.PathTrackingWriter; +import com.thoughtworks.xstream.mapper.Mapper; -public class ReferenceByXPathMarshaller extends TreeMarshaller { - private PathTracker pathTracker = new PathTracker(); - private ObjectIdDictionary references = new ObjectIdDictionary(); +public class ReferenceByXPathMarshaller extends AbstractReferenceMarshaller { - public ReferenceByXPathMarshaller(HierarchicalStreamWriter writer, ConverterLookup converterLookup, ClassMapper classMapper) { - super(writer, converterLookup, classMapper); - this.writer = new PathTrackingWriter(writer, pathTracker); + private final int mode; + + public ReferenceByXPathMarshaller( + final HierarchicalStreamWriter writer, final ConverterLookup converterLookup, final Mapper mapper, + final int mode) { + super(writer, converterLookup, mapper); + this.mode = mode; } - public void convertAnother(Object item) { - Converter converter = converterLookup.lookupConverterForType(item.getClass()); + @Override + protected String createReference(final Path currentPath, final Path existingReferenceKey) { + final Path existingPath = existingReferenceKey; + final Path referencePath = (mode & ReferenceByXPathMarshallingStrategy.ABSOLUTE) > 0 + ? existingPath + : currentPath.relativeTo(existingPath); + return (mode & ReferenceByXPathMarshallingStrategy.SINGLE_NODE) > 0 ? referencePath.explicit() : referencePath + .toString(); + } - if (classMapper.isImmutableValueType(item.getClass())) { - // strings, ints, dates, etc... don't bother using references. - converter.marshal(item, writer, this); - } else { - Path currentPath = pathTracker.getPath(); - Path pathOfExistingReference = (Path) references.lookupId(item); - if (pathOfExistingReference != null) { - Path absolutePath = currentPath.relativeTo(pathOfExistingReference); - writer.addAttribute("reference", absolutePath.toString()); - } else { - references.associateId(item, currentPath); - converter.marshal(item, writer, this); - } - } + @Override + protected Path createReferenceKey(final Path currentPath, final Object item) { + return currentPath; } + @Override + protected void fireValidReference(final Path referenceKey) { + // nothing to do + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshallingStrategy.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshallingStrategy.java (.../ReferenceByXPathMarshallingStrategy.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathMarshallingStrategy.java (.../ReferenceByXPathMarshallingStrategy.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,19 +1,42 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2014 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 03. April 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.MarshallingStrategy; -import com.thoughtworks.xstream.alias.ClassMapper; -import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.converters.ConverterLookup; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; -public class ReferenceByXPathMarshallingStrategy implements MarshallingStrategy { - public Object unmarshal(Object root, HierarchicalStreamReader reader, DataHolder dataHolder, DefaultConverterLookup converterLookup, ClassMapper classMapper) { - return new ReferenceByXPathUnmarshaller(root, reader, converterLookup, - classMapper).start(dataHolder); +public class ReferenceByXPathMarshallingStrategy extends AbstractTreeMarshallingStrategy { + + public static int RELATIVE = 0; + public static int ABSOLUTE = 1; + public static int SINGLE_NODE = 2; + private final int mode; + + public ReferenceByXPathMarshallingStrategy(final int mode) { + this.mode = mode; } - public void marshal(HierarchicalStreamWriter writer, Object obj, DefaultConverterLookup converterLookup, ClassMapper classMapper, DataHolder dataHolder) { - new ReferenceByXPathMarshaller(writer, converterLookup, classMapper).start(obj, dataHolder); + @Override + protected TreeUnmarshaller createUnmarshallingContext(final Object root, final HierarchicalStreamReader reader, + final ConverterLookup converterLookup, final Mapper mapper) { + return new ReferenceByXPathUnmarshaller(root, reader, converterLookup, mapper); } + + @Override + protected TreeMarshaller createMarshallingContext(final HierarchicalStreamWriter writer, + final ConverterLookup converterLookup, final Mapper mapper) { + return new ReferenceByXPathMarshaller(writer, converterLookup, mapper, mode); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathUnmarshaller.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathUnmarshaller.java (.../ReferenceByXPathUnmarshaller.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferenceByXPathUnmarshaller.java (.../ReferenceByXPathUnmarshaller.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,46 +1,50 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 03. April 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.alias.ClassMapper; import com.thoughtworks.xstream.converters.ConverterLookup; -import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.io.AbstractReader; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.path.Path; import com.thoughtworks.xstream.io.path.PathTracker; import com.thoughtworks.xstream.io.path.PathTrackingReader; +import com.thoughtworks.xstream.mapper.Mapper; -import java.util.HashMap; -import java.util.Map; -public class ReferenceByXPathUnmarshaller extends TreeUnmarshaller { +public class ReferenceByXPathUnmarshaller extends AbstractReferenceUnmarshaller { - private Map values = new HashMap(); - private FastStack parentPathStack = new FastStack(16); - private PathTracker pathTracker = new PathTracker(); + private final PathTracker pathTracker = new PathTracker(); + protected boolean isNameEncoding; - public ReferenceByXPathUnmarshaller(Object root, HierarchicalStreamReader reader, - ConverterLookup converterLookup, ClassMapper classMapper) { - super(root, reader, converterLookup, classMapper); + public ReferenceByXPathUnmarshaller( + final Object root, final HierarchicalStreamReader reader, final ConverterLookup converterLookup, + final Mapper mapper) { + super(root, reader, converterLookup, mapper); this.reader = new PathTrackingReader(reader, pathTracker); + isNameEncoding = reader.underlyingReader() instanceof AbstractReader; } - public Object convertAnother(Object parent, Class type) { - if (parentPathStack.size() > 0) { // handles circular references - Object parentPath = parentPathStack.peek(); - if (!values.containsKey(parentPath)) { // see AbstractCircularReferenceTest.testWeirdCircularReference() - values.put(parentPath, parent); - } - } - String relativePathOfReference = reader.getAttribute("reference"); - Path currentPath = pathTracker.getPath(); - if (relativePathOfReference != null) { - return values.get(currentPath.apply(new Path(relativePathOfReference))); - } else { - parentPathStack.push(currentPath); - Object result = super.convertAnother(parent, type); - values.put(currentPath, result); - parentPathStack.popSilently(); - return result; - } + @Override + protected Path getReferenceKey(final String reference) { + final Path path = new Path(isNameEncoding + ? ((AbstractReader)reader.underlyingReader()).decodeNode(reference) + : reference); + // We have absolute references, if path starts with '/' + return reference.charAt(0) != '/' ? pathTracker.getPath().apply(path) : path; } + @Override + protected Path getCurrentReferenceKey() { + return pathTracker.getPath(); + } + } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferencingMarshallingContext.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferencingMarshallingContext.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/ReferencingMarshallingContext.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 06. May 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.io.path.Path; + + +/** + * A {@link MarshallingContext} that manages references. + * + * @author Jörg Schaible + * @since 1.4 + */ +public interface ReferencingMarshallingContext extends MarshallingContext { + + /** + * Retrieve the current path. + * + * @return the current path + * @since 1.4 + * @deprecated As of 1.4.2 + */ + @Deprecated + Path currentPath(); + + /** + * Request the reference key for the given item + * + * @param item the item to lookup + * @return the reference key or null + * @since 1.4 + */ + K lookupReference(Object item); + + /** + * Replace the currently marshalled item. + *

+ * Use this method only, if you know exactly what you do! It is a special solution for Serializable + * types that make usage of the writeReplace method where the replacing object itself is referenced. + *

+ * + * @param original the original item to convert + * @param replacement the replacement item that is converted instead + * @since 1.4 + */ + void replace(Object original, Object replacement); + + /** + * Register an implicit element. This is typically some kind of collection. Note, that this object may not be + * referenced anywhere else in the object stream. + * + * @param item the object that is implicit + * @since 1.4 + */ + void registerImplicit(Object item); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/SequenceGenerator.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/SequenceGenerator.java (.../SequenceGenerator.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/SequenceGenerator.java (.../SequenceGenerator.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,14 +1,26 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2014 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 16. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; public class SequenceGenerator implements ReferenceByIdMarshaller.IDGenerator { private int counter; - public SequenceGenerator(int startsAt) { - this.counter = startsAt; + public SequenceGenerator(final int startsAt) { + counter = startsAt; } - public String next() { + @Override + public String next(final Object item) { return String.valueOf(counter++); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshaller.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshaller.java (.../TreeMarshaller.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshaller.java (.../TreeMarshaller.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,64 +1,103 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 15. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.alias.ClassMapper; +import java.util.Iterator; + +import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.ConverterLookup; import com.thoughtworks.xstream.converters.DataHolder; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.core.util.ObjectIdDictionary; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; -import java.util.Iterator; public class TreeMarshaller implements MarshallingContext { protected HierarchicalStreamWriter writer; protected ConverterLookup converterLookup; - protected ClassMapper classMapper; - private ObjectIdDictionary parentObjects = new ObjectIdDictionary(); + private final Mapper mapper; + private final ObjectIdDictionary parentObjects = new ObjectIdDictionary(); private DataHolder dataHolder; - public TreeMarshaller(HierarchicalStreamWriter writer, - ConverterLookup converterLookup, - ClassMapper classMapper) { + public TreeMarshaller( + final HierarchicalStreamWriter writer, final ConverterLookup converterLookup, final Mapper mapper) { this.writer = writer; this.converterLookup = converterLookup; - this.classMapper = classMapper; + this.mapper = mapper; } - public void convertAnother(Object item) { + @Override + public void convertAnother(final Object item) { + convertAnother(item, null); + } + + @Override + public void convertAnother(final Object item, Converter converter) { + if (converter == null) { + converter = converterLookup.lookupConverterForType(item.getClass()); + } else { + if (!converter.canConvert(item.getClass())) { + final ConversionException e = new ConversionException("Explicit selected converter cannot handle item"); + e.add("item-type", item.getClass().getName()); + e.add("converter-type", converter.getClass().getName()); + throw e; + } + } + convert(item, converter); + } + + protected void convert(final Object item, final Converter converter) { if (parentObjects.containsId(item)) { - throw new CircularReferenceException(); + final ConversionException e = new CircularReferenceException("Recursive reference to parent object"); + e.add("item-type", item.getClass().getName()); + e.add("converter-type", converter.getClass().getName()); + throw e; } parentObjects.associateId(item, ""); - Converter converter = converterLookup.lookupConverterForType(item.getClass()); converter.marshal(item, writer, this); parentObjects.removeId(item); } - public void start(Object item, DataHolder dataHolder) { + public void start(final Object item, final DataHolder dataHolder) { this.dataHolder = dataHolder; if (item == null) { - writer.startNode(classMapper.serializedClass(ClassMapper.Null.class)); + writer.startNode(mapper.serializedClass(null)); writer.endNode(); } else { - writer.startNode(classMapper.serializedClass(item.getClass())); + ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(item.getClass()), item + .getClass()); convertAnother(item); writer.endNode(); } } - public Object get(Object key) { + @Override + public Object get(final Object key) { lazilyCreateDataHolder(); return dataHolder.get(key); } - public void put(Object key, Object value) { + @Override + public void put(final Object key, final Object value) { lazilyCreateDataHolder(); dataHolder.put(key, value); } - public Iterator keys() { + @Override + public Iterator keys() { lazilyCreateDataHolder(); return dataHolder.keys(); } @@ -69,7 +108,14 @@ } } - public static class CircularReferenceException extends RuntimeException { + protected Mapper getMapper() { + return mapper; } + public static class CircularReferenceException extends ConversionException { + + public CircularReferenceException(final String msg) { + super(msg); + } + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshallingStrategy.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshallingStrategy.java (.../TreeMarshallingStrategy.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeMarshallingStrategy.java (.../TreeMarshallingStrategy.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,21 +1,33 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 16. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.MarshallingStrategy; -import com.thoughtworks.xstream.alias.ClassMapper; -import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.converters.ConverterLookup; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; -public class TreeMarshallingStrategy implements MarshallingStrategy { - public Object unmarshal(Object root, HierarchicalStreamReader reader, DataHolder dataHolder, DefaultConverterLookup converterLookup, ClassMapper classMapper) { - return new TreeUnmarshaller( - root, reader, converterLookup, - classMapper).start(dataHolder); - } +public class TreeMarshallingStrategy extends AbstractTreeMarshallingStrategy { - public void marshal(HierarchicalStreamWriter writer, Object obj, DefaultConverterLookup converterLookup, ClassMapper classMapper, DataHolder dataHolder) { - new TreeMarshaller(writer, converterLookup, classMapper).start(obj, dataHolder); + @Override + protected TreeUnmarshaller createUnmarshallingContext(final Object root, final HierarchicalStreamReader reader, + final ConverterLookup converterLookup, final Mapper mapper) { + return new TreeUnmarshaller(root, reader, converterLookup, mapper); } + @Override + protected TreeMarshaller createMarshallingContext(final HierarchicalStreamWriter writer, + final ConverterLookup converterLookup, final Mapper mapper) { + return new TreeMarshaller(writer, converterLookup, mapper); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeUnmarshaller.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeUnmarshaller.java (.../TreeUnmarshaller.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/TreeUnmarshaller.java (.../TreeUnmarshaller.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,82 +1,131 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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 15. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core; -import com.thoughtworks.xstream.alias.ClassMapper; +import java.util.Iterator; + import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.ConverterLookup; import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.converters.ErrorReporter; import com.thoughtworks.xstream.converters.ErrorWriter; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.core.util.ClassStack; +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; import com.thoughtworks.xstream.core.util.PrioritizedList; import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.mapper.Mapper; -import java.util.Iterator; public class TreeUnmarshaller implements UnmarshallingContext { - private Object root; + private final Object root; protected HierarchicalStreamReader reader; - private ConverterLookup converterLookup; - private ClassMapper classMapper; - private ClassStack types = new ClassStack(16); + private final ConverterLookup converterLookup; + private final Mapper mapper; + private final FastStack> types = new FastStack>(16); private DataHolder dataHolder; - private final PrioritizedList validationList = new PrioritizedList(); + private final PrioritizedList validationList = new PrioritizedList(); - public TreeUnmarshaller(Object root, HierarchicalStreamReader reader, - ConverterLookup converterLookup, ClassMapper classMapper) { + public TreeUnmarshaller( + final Object root, final HierarchicalStreamReader reader, final ConverterLookup converterLookup, + final Mapper mapper) { this.root = root; this.reader = reader; this.converterLookup = converterLookup; - this.classMapper = classMapper; + this.mapper = mapper; } - public Object convertAnother(Object parent, Class type) { + @Override + public Object convertAnother(final Object parent, final Class type) { + return convertAnother(parent, type, null); + } + + @Override + public Object convertAnother(final Object parent, Class type, Converter converter) { + type = mapper.defaultImplementationOf(type); + if (converter == null) { + converter = converterLookup.lookupConverterForType(type); + } else { + if (!converter.canConvert(type)) { + final ConversionException e = new ConversionException("Explicit selected converter cannot handle type"); + e.add("item-type", type.getName()); + e.add("converter-type", converter.getClass().getName()); + throw e; + } + } + return convert(parent, type, converter); + } + + protected Object convert(final Object parent, final Class type, final Converter converter) { try { - Converter converter = converterLookup.lookupConverterForType(type); - types.push(classMapper.defaultImplementationOf(type)); - Object result = converter.unmarshal(reader, this); + types.push(type); + final Object result = converter.unmarshal(reader, this); types.popSilently(); return result; - } catch (ConversionException conversionException) { - addInformationTo(conversionException, type); + } catch (final ConversionException conversionException) { + addInformationTo(conversionException, type, converter, parent); throw conversionException; - } catch (RuntimeException e) { - ConversionException conversionException = new ConversionException(e); - addInformationTo(conversionException, type); + } catch (final RuntimeException e) { + final ConversionException conversionException = new ConversionException(e); + addInformationTo(conversionException, type, converter, parent); throw conversionException; } } - private void addInformationTo(ErrorWriter errorWriter, Class type) { + private void addInformationTo(final ErrorWriter errorWriter, final Class type, final Converter converter, + final Object parent) { errorWriter.add("class", type.getName()); errorWriter.add("required-type", getRequiredType().getName()); + errorWriter.add("converter-type", converter.getClass().getName()); + if (converter instanceof ErrorReporter) { + ((ErrorReporter)converter).appendErrors(errorWriter); + } + if (parent instanceof ErrorReporter) { + ((ErrorReporter)parent).appendErrors(errorWriter); + } reader.appendErrors(errorWriter); } - public void addCompletionCallback(Runnable work, int priority) { + @Override + public void addCompletionCallback(final Runnable work, final int priority) { validationList.add(work, priority); } + @Override public Object currentObject() { return types.size() == 1 ? root : null; } - public Class getRequiredType() { + @Override + public Class getRequiredType() { return types.peek(); } - public Object get(Object key) { + @Override + public Object get(final Object key) { lazilyCreateDataHolder(); return dataHolder.get(key); } - public void put(Object key, Object value) { + @Override + public void put(final Object key, final Object value) { lazilyCreateDataHolder(); dataHolder.put(key, value); } - public Iterator keys() { + @Override + public Iterator keys() { lazilyCreateDataHolder(); return dataHolder.keys(); } @@ -87,22 +136,18 @@ } } - public Object start(DataHolder dataHolder) { + public Object start(final DataHolder dataHolder) { this.dataHolder = dataHolder; - String classAttribute = reader.getAttribute(classMapper.attributeForImplementationClass()); - Class type; - if (classAttribute == null) { - type = classMapper.realClass(reader.getNodeName()); - } else { - type = classMapper.realClass(classAttribute); - } - Object result = convertAnother(root, type); - Iterator validations = validationList.iterator(); - while (validations.hasNext()) { - Runnable runnable = (Runnable) validations.next(); + final Class type = HierarchicalStreams.readClassType(reader, mapper); + final Object result = convertAnother(null, type); + for (final Runnable runnable : validationList) { runnable.run(); } return result; } + protected Mapper getMapper() { + return mapper; + } + } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ArrayIterator.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ArrayIterator.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ArrayIterator.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011, 2014 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 29.07.2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import java.lang.reflect.Array; +import java.util.Iterator; + + +/** + * Iterator for an array of arbitrary type. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class ArrayIterator implements Iterator { + private final Object array; + private int idx; + private final int length; + + public ArrayIterator(final Object array) { + this.array = array; + length = Array.getLength(array); + } + + @Override + public boolean hasNext() { + return idx < length; + } + + @Override + public Object next() { + return Array.get(array, idx++); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Remove from array"); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Base64Encoder.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Base64Encoder.java (.../Base64Encoder.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Base64Encoder.java (.../Base64Encoder.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,3 +1,14 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007 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 06. August 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; import java.io.ByteArrayOutputStream; Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ClassLoaderReference.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ClassLoaderReference.java (.../ClassLoaderReference.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ClassLoaderReference.java (.../ClassLoaderReference.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,29 +1,75 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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 07. March 2005 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; /** - * ClassLoader that refers to another ClassLoader, allowing a single instance to be passed around the codebase that - * can later have its destination changed. - * + * ClassLoader that refers to another ClassLoader, allowing a single instance to be passed around the codebase that can + * later have its destination changed. + * * @author Joe Walnes + * @author Jörg Schaible * @since 1.1.1 + * @deprecated As of 1.4.5 use {@link com.thoughtworks.xstream.core.ClassLoaderReference} instead */ +@Deprecated public class ClassLoaderReference extends ClassLoader { - private ClassLoader reference; + private transient ClassLoader reference; - public ClassLoaderReference(ClassLoader reference) { + /** + * @deprecated As of 1.4.5 use + * {@link com.thoughtworks.xstream.core.ClassLoaderReference#ClassLoaderReference(ClassLoader)} instead + */ + @Deprecated + public ClassLoaderReference(final ClassLoader reference) { this.reference = reference; } - public Class loadClass(String name) throws ClassNotFoundException { + /** + * @deprecated As of 1.4.5 use {@link com.thoughtworks.xstream.core.ClassLoaderReference#getReference()} + * .loadClass(String) instead + */ + @Deprecated + @Override + public Class loadClass(final String name) throws ClassNotFoundException { return reference.loadClass(name); } + /** + * @deprecated As of 1.4.5 use {@link com.thoughtworks.xstream.core.ClassLoaderReference#getReference()} instead + */ + @Deprecated public ClassLoader getReference() { return reference; } - public void setReference(ClassLoader reference) { + /** + * @deprecated As of 1.4.5 use {@link com.thoughtworks.xstream.core.ClassLoaderReference#setReference(ClassLoader)} + * instead + */ + @Deprecated + public void setReference(final ClassLoader reference) { this.reference = reference; } + + private Object writeReplace() { + return new Replacement(); + } + + static class Replacement { + + private Object readResolve() { + return new ClassLoaderReference(new CompositeClassLoader()); + } + + }; } Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ClassStack.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Cloneables.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Cloneables.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Cloneables.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2009, 2010, 2011, 2014 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 29. August 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; + +/** + * Utility functions for {@link Cloneable} objects. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class Cloneables { + + @SuppressWarnings("unchecked") + public static T clone(final T o) { + if (o instanceof Cloneable) { + if (o.getClass().isArray()) { + final Class componentType = o.getClass().getComponentType(); + if (!componentType.isPrimitive()) { + return (T)((Object[])o).clone(); + } else { + int length = Array.getLength(o); + final Object clone = Array.newInstance(componentType, length); + while (length-- > 0) { + Array.set(clone, length, Array.get(o, length)); + } + return (T)clone; + } + } else { + try { + final Method clone = o.getClass().getMethod("clone"); + return (T)clone.invoke(o); + } catch (final NoSuchMethodException e) { + throw new ObjectAccessException("Cloneable type has no clone method", e); + } catch (final IllegalAccessException e) { + throw new ObjectAccessException("Cannot clone Cloneable type", e); + } catch (final InvocationTargetException e) { + throw new ObjectAccessException("Exception cloning Cloneable type", e.getCause()); + } + } + } + return null; + } + + public static T cloneIfPossible(final T o) { + final T clone = clone(o); + return clone == null ? o : clone; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CompositeClassLoader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CompositeClassLoader.java (.../CompositeClassLoader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CompositeClassLoader.java (.../CompositeClassLoader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,10 +1,26 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2011, 2013, 2014 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 16. November 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; import java.util.List; +import com.thoughtworks.xstream.core.JVM; + /** * ClassLoader that is composed of other classloaders. Each loader will be used to try to load the particular class, until * one of them succeeds. Note: The loaders will always be called in the REVERSE order they were added in. @@ -28,47 +44,103 @@ *
  • The thread's context classloader (and all its parents)
  • *
  • The classloader for XStream (and all its parents)
  • * + * + *

    The added classloaders are kept with weak references to allow an application container to reload classes.

    * * @author Joe Walnes + * @author Jörg Schaible * @since 1.0.3 */ public class CompositeClassLoader extends ClassLoader { + static { + if (JVM.is17()) { + // see http://www.cs.duke.edu/csed/java/jdk1.7/technotes/guides/lang/cl-mt.html + try { + final Method m = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable"); + if (!m.isAccessible()) { + m.setAccessible(true); + } + m.invoke(null); + } catch (final Exception e) { + // ignore errors, JVM will synchronize class for Java 7 or higher + } + } + } - private final List classLoaders = Collections.synchronizedList(new ArrayList()); + private final ReferenceQueue queue = new ReferenceQueue(); + private final List> classLoaders = new ArrayList>(); public CompositeClassLoader() { - add(Object.class.getClassLoader()); // bootstrap loader. - add(getClass().getClassLoader()); // whichever classloader loaded this jar. + addInternal(Object.class.getClassLoader()); // bootstrap loader. + addInternal(getClass().getClassLoader()); // whichever classloader loaded this jar. } /** * Add a loader to the n * @param classLoader */ - public void add(ClassLoader classLoader) { + public synchronized void add(final ClassLoader classLoader) { + cleanup(); if (classLoader != null) { - classLoaders.add(0, classLoader); + addInternal(classLoader); } } - public Class loadClass(String name) throws ClassNotFoundException { - for (Iterator iterator = classLoaders.iterator(); iterator.hasNext();) { - ClassLoader classLoader = (ClassLoader) iterator.next(); + private void addInternal(final ClassLoader classLoader) { + WeakReference refClassLoader = null; + for (final Iterator> iterator = classLoaders.iterator(); iterator.hasNext();) { + final WeakReference ref = iterator.next(); + final ClassLoader cl = ref.get(); + if (cl == null) { + iterator.remove(); + } else if (cl == classLoader) { + iterator.remove(); + refClassLoader = ref; + } + } + classLoaders.add(0, refClassLoader != null ? refClassLoader : new WeakReference(classLoader, queue)); + } + + @Override + public Class loadClass(final String name) throws ClassNotFoundException { + final List copy = new ArrayList(classLoaders.size()); + synchronized(this) { + cleanup(); + for(final WeakReference ref : classLoaders) { + final ClassLoader cl = ref.get(); + if (cl != null) { + copy.add(cl); + } + } + } + + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + for (final ClassLoader classLoader : copy) { + if (classLoader == contextClassLoader) { + contextClassLoader = null; + } try { return classLoader.loadClass(name); - } catch (ClassNotFoundException notFound) { + } catch (final ClassNotFoundException notFound) { // ok.. try another one } } + // One last try - the context class loader associated with the current thread. Often used in j2ee servers. // Note: The contextClassLoader cannot be added to the classLoaders list up front as the thread that constructs // XStream is potentially different to thread that uses it. - ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); if (contextClassLoader != null) { return contextClassLoader.loadClass(name); } else { throw new ClassNotFoundException(name); } } + private void cleanup() { + Reference ref; + while ((ref = queue.poll()) != null) + { + classLoaders.remove(ref); + } + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectInputStream.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectInputStream.java (.../CustomObjectInputStream.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectInputStream.java (.../CustomObjectInputStream.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,236 +1,358 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014 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 23. August 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; -import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.converters.DataHolder; - import java.io.IOException; import java.io.InvalidObjectException; import java.io.NotActiveException; import java.io.ObjectInputStream; import java.io.ObjectInputValidation; import java.io.ObjectStreamClass; +import java.io.StreamCorruptedException; import java.util.Map; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.core.ClassLoaderReference; + + public class CustomObjectInputStream extends ObjectInputStream { - private StreamCallback callback; + private final FastStack callbacks = new FastStack(1); + private final ClassLoaderReference classLoaderReference; private static final String DATA_HOLDER_KEY = CustomObjectInputStream.class.getName(); public static interface StreamCallback { Object readFromStream() throws IOException; - Map readFieldsFromStream() throws IOException; + + Map readFieldsFromStream() throws IOException; + void defaultReadObject() throws IOException; - void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException, InvalidObjectException; + + void registerValidation(ObjectInputValidation validation, int priority) + throws NotActiveException, InvalidObjectException; + void close() throws IOException; } - public static synchronized CustomObjectInputStream getInstance(DataHolder whereFrom, CustomObjectInputStream.StreamCallback callback) { + /** + * @deprecated As of 1.4 use {@link #getInstance(DataHolder, StreamCallback, ClassLoader)} + */ + @Deprecated + public static CustomObjectInputStream getInstance(final DataHolder whereFrom, + final CustomObjectInputStream.StreamCallback callback) { + return getInstance(whereFrom, callback, (ClassLoader)null); + } + + /** + * @deprecated As of 1.4.5 use {@link #getInstance(DataHolder, StreamCallback, ClassLoaderReference)} + */ + @Deprecated + public static synchronized CustomObjectInputStream getInstance(final DataHolder whereFrom, + final CustomObjectInputStream.StreamCallback callback, final ClassLoader classLoader) { + return getInstance(whereFrom, callback, new ClassLoaderReference(classLoader)); + } + + public static synchronized CustomObjectInputStream getInstance(final DataHolder whereFrom, + final CustomObjectInputStream.StreamCallback callback, final ClassLoaderReference classLoaderReference) { try { - CustomObjectInputStream result = (CustomObjectInputStream) whereFrom.get(DATA_HOLDER_KEY); + CustomObjectInputStream result = (CustomObjectInputStream)whereFrom.get(DATA_HOLDER_KEY); if (result == null) { - result = new CustomObjectInputStream(callback); + result = new CustomObjectInputStream(callback, classLoaderReference); whereFrom.put(DATA_HOLDER_KEY, result); } else { - result.setCallback(callback); + result.pushCallback(callback); } return result; - } catch (IOException e) { + } catch (final IOException e) { throw new ConversionException("Cannot create CustomObjectStream", e); } } /** - * Warning, this object is expensive to create (due to functionality inherited from superclass). - * Use the static fetch() method instead, wherever possible. - * - * @see #getInstance(com.thoughtworks.xstream.converters.DataHolder, com.thoughtworks.xstream.core.util.CustomObjectInputStream.StreamCallback) + * Warning, this object is expensive to create (due to functionality inherited from superclass). Use the static + * fetch() method instead, wherever possible. + * + * @see #getInstance(DataHolder, StreamCallback, ClassLoaderReference) */ - public CustomObjectInputStream(StreamCallback callback) throws IOException, SecurityException { + public CustomObjectInputStream(final StreamCallback callback, final ClassLoaderReference classLoaderReference) + throws IOException, SecurityException { super(); - this.callback = callback; + callbacks.push(callback); + this.classLoaderReference = classLoaderReference; } /** + * @deprecated As of 1.4.5 use {@link #CustomObjectInputStream(StreamCallback, ClassLoaderReference)} + */ + @Deprecated + public CustomObjectInputStream(final StreamCallback callback, final ClassLoader classLoader) + throws IOException, SecurityException { + this(callback, new ClassLoaderReference(classLoader)); + } + + /** * Allows the CustomObjectInputStream (which is expensive to create) to be reused. */ - public void setCallback(StreamCallback callback) { - this.callback = callback; + public void pushCallback(final StreamCallback callback) { + callbacks.push(callback); } - public void defaultReadObject() throws IOException, ClassNotFoundException { - callback.defaultReadObject(); + public StreamCallback popCallback() { + return callbacks.pop(); } - protected Object readObjectOverride() throws IOException, ClassNotFoundException { - return callback.readFromStream(); + public StreamCallback peekCallback() { + return callbacks.peek(); } + @Override + protected Class resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException { + final ClassLoader classLoader = classLoaderReference.getReference(); + if (classLoader == null) { + return super.resolveClass(desc); + } else { + return Class.forName(desc.getName(), false, classLoader); + } + } + + @Override + public void defaultReadObject() throws IOException { + peekCallback().defaultReadObject(); + } + + @Override + protected Object readObjectOverride() throws IOException { + return peekCallback().readFromStream(); + } + + @Override + public Object readUnshared() throws IOException, ClassNotFoundException { + return readObject(); + } + + @Override public boolean readBoolean() throws IOException { - return ((Boolean)callback.readFromStream()).booleanValue(); + return ((Boolean)peekCallback().readFromStream()).booleanValue(); } + @Override public byte readByte() throws IOException { - return ((Byte)callback.readFromStream()).byteValue(); + return ((Byte)peekCallback().readFromStream()).byteValue(); } + @Override + public int readUnsignedByte() throws IOException { + int b = ((Byte)peekCallback().readFromStream()).byteValue(); + if (b < 0) { + b += Byte.MAX_VALUE; + } + return b; + } + + @Override public int readInt() throws IOException { - return ((Integer)callback.readFromStream()).intValue(); + return ((Integer)peekCallback().readFromStream()).intValue(); } + @Override public char readChar() throws IOException { - return ((Character)callback.readFromStream()).charValue(); + return ((Character)peekCallback().readFromStream()).charValue(); } + @Override public float readFloat() throws IOException { - return ((Float)callback.readFromStream()).floatValue(); + return ((Float)peekCallback().readFromStream()).floatValue(); } + @Override public double readDouble() throws IOException { - return ((Double)callback.readFromStream()).doubleValue(); + return ((Double)peekCallback().readFromStream()).doubleValue(); } + @Override public long readLong() throws IOException { - return ((Long)callback.readFromStream()).longValue(); + return ((Long)peekCallback().readFromStream()).longValue(); } + @Override public short readShort() throws IOException { - return ((Short)callback.readFromStream()).shortValue(); + return ((Short)peekCallback().readFromStream()).shortValue(); } + @Override + public int readUnsignedShort() throws IOException { + int b = ((Short)peekCallback().readFromStream()).shortValue(); + if (b < 0) { + b += Short.MAX_VALUE; + } + return b; + } + + @Override public String readUTF() throws IOException { - return (String) callback.readFromStream(); + return (String)peekCallback().readFromStream(); } - public void readFully(byte[] buf) throws IOException { + @Override + public void readFully(final byte[] buf) throws IOException { readFully(buf, 0, buf.length); } - public void readFully(byte[] buf, int off, int len) throws IOException { - byte[] b = (byte[])callback.readFromStream(); + @Override + public void readFully(final byte[] buf, final int off, final int len) throws IOException { + final byte[] b = (byte[])peekCallback().readFromStream(); System.arraycopy(b, 0, buf, off, len); } - public GetField readFields() throws IOException, ClassNotFoundException { - return new CustomGetField(callback.readFieldsFromStream()); + @Override + public int read() throws IOException { + return readUnsignedByte(); } + @Override + public int read(final byte[] buf, final int off, final int len) throws IOException { + final byte[] b = (byte[])peekCallback().readFromStream(); + if (b.length != len) { + throw new StreamCorruptedException("Expected " + len + " bytes from stream, got " + b.length); + } + System.arraycopy(b, 0, buf, off, len); + return len; + } + + @Override + public int read(final byte b[]) throws IOException { + return read(b, 0, b.length); + } + + @Override + public GetField readFields() throws IOException { + return new CustomGetField(peekCallback().readFieldsFromStream()); + } + private class CustomGetField extends GetField { - private Map fields; + private final Map fields; - public CustomGetField(Map fields) { + public CustomGetField(final Map fields) { this.fields = fields; } + @Override public ObjectStreamClass getObjectStreamClass() { throw new UnsupportedOperationException(); } - private Object get(String name) { + private Object get(final String name) { return fields.get(name); } - public boolean defaulted(String name) throws IOException { + @Override + public boolean defaulted(final String name) { return !fields.containsKey(name); } - public byte get(String name, byte val) throws IOException { + @Override + public byte get(final String name, final byte val) { return defaulted(name) ? val : ((Byte)get(name)).byteValue(); } - public char get(String name, char val) throws IOException { + @Override + public char get(final String name, final char val) { return defaulted(name) ? val : ((Character)get(name)).charValue(); } - public double get(String name, double val) throws IOException { + @Override + public double get(final String name, final double val) { return defaulted(name) ? val : ((Double)get(name)).doubleValue(); } - public float get(String name, float val) throws IOException { + @Override + public float get(final String name, final float val) { return defaulted(name) ? val : ((Float)get(name)).floatValue(); } - public int get(String name, int val) throws IOException { + @Override + public int get(final String name, final int val) { return defaulted(name) ? val : ((Integer)get(name)).intValue(); } - public long get(String name, long val) throws IOException { + @Override + public long get(final String name, final long val) { return defaulted(name) ? val : ((Long)get(name)).longValue(); } - public short get(String name, short val) throws IOException { + @Override + public short get(final String name, final short val) { return defaulted(name) ? val : ((Short)get(name)).shortValue(); } - public boolean get(String name, boolean val) throws IOException { + @Override + public boolean get(final String name, final boolean val) { return defaulted(name) ? val : ((Boolean)get(name)).booleanValue(); } - public Object get(String name, Object val) throws IOException { + @Override + public Object get(final String name, final Object val) { return defaulted(name) ? val : get(name); } } - public void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException, InvalidObjectException { - callback.registerValidation(validation, priority); + @Override + public void registerValidation(final ObjectInputValidation validation, final int priority) + throws NotActiveException, InvalidObjectException { + peekCallback().registerValidation(validation, priority); } - /****** Unsupported methods ******/ - - public int available() throws IOException { - throw new UnsupportedOperationException(); - } - + @Override public void close() throws IOException { - callback.close(); + peekCallback().close(); } - public int readUnsignedByte() throws IOException { - throw new UnsupportedOperationException(); - } + /****** Unsupported methods ******/ - public String readLine() throws IOException { + @Override + public int available() { throw new UnsupportedOperationException(); } - public Object readUnshared() throws IOException, ClassNotFoundException { + @Override + public String readLine() { throw new UnsupportedOperationException(); } - public int readUnsignedShort() throws IOException { + @Override + public int skipBytes(final int len) { throw new UnsupportedOperationException(); } - public int read() throws IOException { + @Override + public long skip(final long n) { throw new UnsupportedOperationException(); } - public int read(byte[] buf, int off, int len) throws IOException { + @Override + public synchronized void mark(final int readlimit) { throw new UnsupportedOperationException(); } - public int skipBytes(int len) throws IOException { + @Override + public synchronized void reset() { throw new UnsupportedOperationException(); } - public int read(byte b[]) throws IOException { - throw new UnsupportedOperationException(); - } - - public long skip(long n) throws IOException { - throw new UnsupportedOperationException(); - } - - public void mark(int readlimit) { - throw new UnsupportedOperationException(); - } - - public void reset() throws IOException { - throw new UnsupportedOperationException(); - } - + @Override public boolean markSupported() { return false; } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectOutputStream.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectOutputStream.java (.../CustomObjectOutputStream.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/CustomObjectOutputStream.java (.../CustomObjectOutputStream.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,209 +1,268 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 23. August 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; -import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.converters.DataHolder; - import java.io.IOException; -import java.io.ObjectOutputStream; import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.HashMap; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.DataHolder; + + public class CustomObjectOutputStream extends ObjectOutputStream { - private StreamCallback callback; - private FastStack customFields = new FastStack(1); + private final FastStack callbacks = new FastStack(1); + private final FastStack customFields = new FastStack(1); private static final String DATA_HOLDER_KEY = CustomObjectOutputStream.class.getName(); - public static synchronized CustomObjectOutputStream getInstance(DataHolder whereFrom, StreamCallback callback) { + public static synchronized CustomObjectOutputStream getInstance(final DataHolder whereFrom, + final StreamCallback callback) { try { - CustomObjectOutputStream result = (CustomObjectOutputStream) whereFrom.get(DATA_HOLDER_KEY); + CustomObjectOutputStream result = (CustomObjectOutputStream)whereFrom.get(DATA_HOLDER_KEY); if (result == null) { result = new CustomObjectOutputStream(callback); whereFrom.put(DATA_HOLDER_KEY, result); } else { - result.setCallback(callback); + result.pushCallback(callback); } return result; - } catch (IOException e) { + } catch (final IOException e) { throw new ConversionException("Cannot create CustomObjectStream", e); } } public static interface StreamCallback { void writeToStream(Object object) throws IOException; - void writeFieldsToStream(Map fields) throws IOException; + + void writeFieldsToStream(Map fields) throws IOException; + void defaultWriteObject() throws IOException; + void flush() throws IOException; + void close() throws IOException; } /** - * Warning, this object is expensive to create (due to functionality inherited from superclass). - * Use the static fetch() method instead, wherever possible. - * - * @see #getInstance(com.thoughtworks.xstream.converters.DataHolder, com.thoughtworks.xstream.core.util.CustomObjectOutputStream.StreamCallback) + * Warning, this object is expensive to create (due to functionality inherited from superclass). Use the static + * fetch() method instead, wherever possible. + * + * @see #getInstance(com.thoughtworks.xstream.converters.DataHolder, + * com.thoughtworks.xstream.core.util.CustomObjectOutputStream.StreamCallback) */ - public CustomObjectOutputStream(StreamCallback callback) throws IOException, SecurityException { - this.callback = callback; + public CustomObjectOutputStream(final StreamCallback callback) throws IOException, SecurityException { + callbacks.push(callback); } /** * Allows the CustomObjectOutputStream (which is expensive to create) to be reused. */ - public void setCallback(StreamCallback callback) { - this.callback = callback; + public void pushCallback(final StreamCallback callback) { + callbacks.push(callback); } + public StreamCallback popCallback() { + return callbacks.pop(); + } + + public StreamCallback peekCallback() { + return callbacks.peek(); + } + /*** Methods to delegate to callback ***/ + @Override public void defaultWriteObject() throws IOException { - callback.defaultWriteObject(); + peekCallback().defaultWriteObject(); } - protected void writeObjectOverride(Object obj) throws IOException { - callback.writeToStream(obj); + @Override + protected void writeObjectOverride(final Object obj) throws IOException { + peekCallback().writeToStream(obj); } - public void writeBoolean(boolean val) throws IOException { - callback.writeToStream(val ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly + @Override + public void writeBoolean(final boolean val) throws IOException { + peekCallback().writeToStream(Boolean.valueOf(val)); } - public void writeByte(int val) throws IOException { - callback.writeToStream(new Byte((byte) val)); + @Override + public void writeByte(final int val) throws IOException { + peekCallback().writeToStream(Byte.valueOf((byte)val)); } - public void writeInt(int val) throws IOException { - callback.writeToStream(new Integer(val)); + @Override + public void writeInt(final int val) throws IOException { + peekCallback().writeToStream(Integer.valueOf(val)); } - public void writeChar(int val) throws IOException { - callback.writeToStream(new Character((char)val)); + @Override + public void writeChar(final int val) throws IOException { + peekCallback().writeToStream(Character.valueOf((char)val)); } - public void writeDouble(double val) throws IOException { - callback.writeToStream(new Double(val)); + @Override + public void writeDouble(final double val) throws IOException { + peekCallback().writeToStream(Double.valueOf(val)); } - public void writeFloat(float val) throws IOException { - callback.writeToStream(new Float(val)); + @Override + public void writeFloat(final float val) throws IOException { + peekCallback().writeToStream(Float.valueOf(val)); } - public void writeLong(long val) throws IOException { - callback.writeToStream(new Long(val)); + @Override + public void writeLong(final long val) throws IOException { + peekCallback().writeToStream(Long.valueOf(val)); } - public void writeShort(int val) throws IOException { - callback.writeToStream(new Short((short) val)); + @Override + public void writeShort(final int val) throws IOException { + peekCallback().writeToStream(Short.valueOf((short)val)); } - public void write(byte[] buf) throws IOException { - callback.writeToStream(buf); + @Override + public void write(final byte[] buf) throws IOException { + peekCallback().writeToStream(buf); } - public void writeChars(String str) throws IOException { - callback.writeToStream(str.toCharArray()); + @Override + public void writeChars(final String str) throws IOException { + peekCallback().writeToStream(str.toCharArray()); } - public void writeUTF(String str) throws IOException { - callback.writeToStream(str); + @Override + public void writeUTF(final String str) throws IOException { + peekCallback().writeToStream(str); } - public void write(int val) throws IOException { - callback.writeToStream(new Byte((byte) val)); + @Override + public void write(final int val) throws IOException { + peekCallback().writeToStream(Byte.valueOf((byte)val)); } - public void write(byte[] buf, int off, int len) throws IOException { - byte[] b = new byte[len]; + @Override + public void write(final byte[] buf, final int off, final int len) throws IOException { + final byte[] b = new byte[len]; System.arraycopy(buf, off, b, 0, len); - callback.writeToStream(b); + peekCallback().writeToStream(b); } + @Override public void flush() throws IOException { - callback.flush(); + peekCallback().flush(); } + @Override public void close() throws IOException { - callback.close(); + peekCallback().close(); } - public PutField putFields() throws IOException { - CustomPutField result = new CustomPutField(); + @Override + public PutField putFields() { + final CustomPutField result = new CustomPutField(); customFields.push(result); return result; } + @Override public void writeFields() throws IOException { - CustomPutField customPutField = (CustomPutField) customFields.pop(); - callback.writeFieldsToStream(customPutField.asMap()); + final CustomPutField customPutField = customFields.pop(); + peekCallback().writeFieldsToStream(customPutField.asMap()); } private class CustomPutField extends PutField { - private final Map fields = new OrderRetainingMap(); + private final Map fields = new LinkedHashMap(); - public Map asMap() { + public Map asMap() { return fields; } - public void write(ObjectOutput out) throws IOException { - callback.writeToStream(asMap()); + @Override + public void write(final ObjectOutput out) throws IOException { + peekCallback().writeToStream(asMap()); } - public void put(String name, Object val) { + @Override + public void put(final String name, final Object val) { fields.put(name, val); } - public void put(String name, byte val) { - put(name, new Byte(val)); + @Override + public void put(final String name, final byte val) { + put(name, Byte.valueOf(val)); } - public void put(String name, char val) { - put(name, new Character(val)); + @Override + public void put(final String name, final char val) { + put(name, Character.valueOf(val)); } - public void put(String name, double val) { - put(name, new Double(val)); + @Override + public void put(final String name, final double val) { + put(name, Double.valueOf(val)); } - public void put(String name, float val) { - put(name, new Float(val)); + @Override + public void put(final String name, final float val) { + put(name, Float.valueOf(val)); } - public void put(String name, int val) { - put(name, new Integer(val)); + @Override + public void put(final String name, final int val) { + put(name, Integer.valueOf(val)); } - public void put(String name, long val) { - put(name, new Long(val)); + @Override + public void put(final String name, final long val) { + put(name, Long.valueOf(val)); } - public void put(String name, short val) { - put(name, new Short(val)); + @Override + public void put(final String name, final short val) { + put(name, Short.valueOf(val)); } - public void put(String name, boolean val) { - put(name, val ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly + @Override + public void put(final String name, final boolean val) { + put(name, Boolean.valueOf(val)); } } /****** Unsupported methods ******/ - public void reset() throws IOException { + @Override + public void reset() { throw new UnsupportedOperationException(); } - public void useProtocolVersion(int version) throws IOException { + @Override + public void useProtocolVersion(final int version) { throw new UnsupportedOperationException(); } - public void writeBytes(String str) throws IOException { + @Override + public void writeBytes(final String str) { throw new UnsupportedOperationException(); } - public void writeUnshared(Object obj) throws IOException { + @Override + public void writeUnshared(final Object obj) { throw new UnsupportedOperationException(); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/DependencyInjectionFactory.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/DependencyInjectionFactory.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/DependencyInjectionFactory.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2007, 2009, 2010, 2011, 2012, 2013, 2014 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 30. March 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Comparator; +import java.util.List; + +import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; + + +/** + * A dependency injection factory. + * + * @author Jörg Schaible + * @since 1.2.2 + */ +public class DependencyInjectionFactory { + + /** + * Create an instance with dependency injection. The given dependencies are used to match the parameters of the + * constructors of the type. Constructors with most parameters are examined first. A parameter type sequence + * matching the sequence of the dependencies' types match first. Otherwise all the types of the dependencies must + * match one of the the parameters although no dependency is used twice. Use a {@link TypedNull} instance to inject + * null as parameter. + * + * @param type the type to create an instance of + * @param dependencies the possible dependencies + * @return the instantiated object + * @throws ObjectAccessException if no instance can be generated + * @throws IllegalArgumentException if more than 63 dependencies have been provided + * @since 1.2.2 + */ + public static T newInstance(final Class type, final Object... dependencies) { + return newInstance(null, type, dependencies); + } + + /** + * Create an instance with dependency injection. The given dependencies are used to match the parameters of the + * constructors of the type. Constructors with most parameters are examined first. A parameter type sequence + * matching the sequence of the dependencies' types match first. Otherwise all the types of the dependencies must + * match one of the the parameters although no dependency is used twice. Use a {@link TypedNull} instance to inject + * null as parameter. + * + * @param type the type to create an instance of + * @param dependencies the possible dependencies + * @param usedDependencies bit mask set by the method for all used dependencies (may be null) + * @return the instantiated object + * @throws ObjectAccessException if no instance can be generated + * @throws IllegalArgumentException if more than 63 dependencies have been provided + * @since 1.4 + * @deprecated As of upcoming use {@link #newInstance(BitSet, Class, Object...)} + */ + @Deprecated + public static T newInstance(final Class type, final Object[] dependencies, final BitSet usedDependencies) { + return newInstance(usedDependencies, type, dependencies); + } + + /** + * Create an instance with dependency injection. The given dependencies are used to match the parameters of the + * constructors of the type. Constructors with most parameters are examined first. A parameter type sequence + * matching the sequence of the dependencies' types match first. Otherwise all the types of the dependencies must + * match one of the the parameters although no dependency is used twice. Use a {@link TypedNull} instance to inject + * null as parameter. + * + * @param usedDependencies bit mask set by the method for all used dependencies (may be null) + * @param type the type to create an instance of + * @param dependencies the possible dependencies + * @return the instantiated object + * @throws ObjectAccessException if no instance can be generated + * @throws IllegalArgumentException if more than 63 dependencies have been provided + * @since upcoming + */ + public static T newInstance(final BitSet usedDependencies, final Class type, final Object... dependencies) { + if (dependencies != null && dependencies.length > 63) { + throw new IllegalArgumentException("More than 63 arguments are not supported"); + } + Constructor bestMatchingCtor = null; + final ArrayList matchingDependencies = new ArrayList(); + List possibleMatchingDependencies = null; + long usedDeps = 0; + long possibleUsedDeps = 0; + + if (dependencies != null && dependencies.length > 0) { + // sort available ctors according their arity + final Constructor[] ctors = type.getConstructors(); + if (ctors.length > 1) { + Arrays.sort(ctors, new Comparator>() { + @Override + public int compare(final Constructor o1, final Constructor o2) { + return o2.getParameterTypes().length - o1.getParameterTypes().length; + } + }); + } + + final TypedValue[] typedDependencies = new TypedValue[dependencies.length]; + for (int i = 0; i < dependencies.length; i++) { + Object dependency = dependencies[i]; + Class depType = dependency.getClass(); + if (depType.isPrimitive()) { + depType = Primitives.box(depType); + } else if (depType == TypedNull.class) { + depType = ((TypedNull)dependency).getType(); + dependency = null; + } + typedDependencies[i] = new TypedValue(depType, dependency); + } + + Constructor possibleCtor = null; + int arity = Integer.MAX_VALUE; + for (int i = 0; bestMatchingCtor == null && i < ctors.length; i++) { + final Constructor constructor = ctors[i]; + final Class[] parameterTypes = constructor.getParameterTypes(); + if (parameterTypes.length > dependencies.length) { + continue; + } else if (parameterTypes.length == 0) { + if (possibleCtor == null) { + bestMatchingCtor = constructor; + } + break; + } + + if (arity > parameterTypes.length) { + if (possibleCtor != null) { + continue; + } + arity = parameterTypes.length; + } + + for (int j = 0; j < parameterTypes.length; j++) { + if (parameterTypes[j].isPrimitive()) { + parameterTypes[j] = Primitives.box(parameterTypes[j]); + } + } + + // first approach: test the ctor params against the dependencies in the sequence of the parameter + // declaration + matchingDependencies.clear(); + usedDeps = 0; + for (int j = 0, k = 0; j < parameterTypes.length + && parameterTypes.length + k - j <= typedDependencies.length; k++) { + if (parameterTypes[j].isAssignableFrom(typedDependencies[k].type)) { + matchingDependencies.add(typedDependencies[k].value); + usedDeps |= 1L << k; + if (++j == parameterTypes.length) { + bestMatchingCtor = constructor; + break; + } + } + } + + if (bestMatchingCtor == null) { + boolean possible = true; // assumption + + // try to match all dependencies in the sequence of the parameter declaration + final TypedValue[] deps = new TypedValue[typedDependencies.length]; + System.arraycopy(typedDependencies, 0, deps, 0, deps.length); + matchingDependencies.clear(); + usedDeps = 0; + for (final Class parameterType : parameterTypes) { + int assignable = -1; + for (int k = 0; k < deps.length; k++) { + if (deps[k] == null) { + continue; + } + + if (deps[k].type == parameterType) { + assignable = k; + // optimal match + break; + } else if (parameterType.isAssignableFrom(deps[k].type)) { + // use most specific type + if (assignable < 0 + || deps[assignable].type != deps[k].type + && deps[assignable].type.isAssignableFrom(deps[k].type)) { + assignable = k; + } + } + } + + if (assignable >= 0) { + matchingDependencies.add(deps[assignable].value); + usedDeps |= 1L << assignable; + deps[assignable] = null; // do not match same dep twice + } else { + possible = false; + break; + } + } + + if (possible) { + // the smaller the value, the smaller the indices in the deps array + if (possibleCtor != null && usedDeps >= possibleUsedDeps) { + continue; + } + possibleCtor = constructor; + @SuppressWarnings("unchecked") + final List clone = (List)matchingDependencies.clone(); + possibleMatchingDependencies = clone; + possibleUsedDeps = usedDeps; + } + } + } + + if (bestMatchingCtor == null) { + if (possibleCtor == null) { + usedDeps = 0; + throw new ObjectAccessException("Cannot construct " + + type.getName() + + ", none of the dependencies match any constructor's parameters"); + } else { + bestMatchingCtor = possibleCtor; + matchingDependencies.clear(); + matchingDependencies.addAll(possibleMatchingDependencies); + usedDeps = possibleUsedDeps; + } + } + } + + try { + final T instance; + if (bestMatchingCtor == null) { + instance = type.newInstance(); + } else { + @SuppressWarnings("unchecked") + final T obj = (T)bestMatchingCtor.newInstance(matchingDependencies.toArray()); + instance = obj; + } + if (usedDependencies != null) { + usedDependencies.clear(); + int i = 0; + for(long l = 1; l < usedDeps; l <<= 1, ++i) { + if ((usedDeps & l) > 0) { + usedDependencies.set(i); + } + } + } + + return instance; + } catch (final InstantiationException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (final IllegalAccessException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (final InvocationTargetException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (final SecurityException e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } catch (final ExceptionInInitializerError e) { + throw new ObjectAccessException("Cannot construct " + type.getName(), e); + } + } + + private static class TypedValue { + final Class type; + final Object value; + + public TypedValue(final Class type, final Object value) { + super(); + this.type = type; + this.value = value; + } + + @Override + public String toString() { + return type.getName() + ":" + value; + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/FastField.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/FastField.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/FastField.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008, 2010, 2014 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 13. October 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +public final class FastField { + private final String name; + private final String declaringClass; + + public FastField(final String definedIn, final String name) { + this.name = name; + declaringClass = definedIn; + } + + public FastField(final Class definedIn, final String name) { + this(definedIn == null ? null : definedIn.getName(), name); + } + + public String getName() { + return name; + } + + public String getDeclaringClass() { + return declaringClass; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (obj instanceof FastField) { + final FastField field = (FastField)obj; + if (declaringClass == null && field.declaringClass != null + || declaringClass != null && field.declaringClass == null) { + return false; + } + return name.equals(field.getName()) + && (declaringClass == null || declaringClass.equals(field.getDeclaringClass())); + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode() ^ (declaringClass == null ? 0 : declaringClass.hashCode()); + } + + @Override + public String toString() { + return (declaringClass == null ? "" : declaringClass + ".") + name; + } +} \ No newline at end of file Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/FastStack.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/FastStack.java (.../FastStack.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/FastStack.java (.../FastStack.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,15 +1,41 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2014 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 02. September 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; -public final class FastStack { +import java.util.Arrays; - private Object[] stack; + +/** + * An array-based stack implementation. + * + * @author Joe Walnes + * @author Jörg Schaible + */ +public final class FastStack { + + private T[] stack; private int pointer; - public FastStack(int initialCapacity) { - stack = new Object[initialCapacity]; + public FastStack(final int initialCapacity) { + @SuppressWarnings("unchecked") + final T[] array = getArray(initialCapacity); + stack = array; } - public Object push(Object value) { + private T[] getArray(final int capacity, final T... t) { + return Arrays.copyOf(t, capacity); + } + + public T push(final T value) { if (pointer + 1 >= stack.length) { resizeStack(stack.length * 2); } @@ -21,16 +47,26 @@ stack[--pointer] = null; } - public Object pop() { - final Object result = stack[--pointer]; - stack[pointer] = null; + public T pop() { + final T result = stack[--pointer]; + stack[pointer] = null; return result; } - public Object peek() { + public T peek() { return pointer == 0 ? null : stack[pointer - 1]; } + public Object replace(final T value) { + final T result = stack[pointer - 1]; + stack[pointer - 1] = value; + return result; + } + + public void replaceSilently(final T value) { + stack[pointer - 1] = value; + } + public int size() { return pointer; } @@ -39,18 +75,20 @@ return pointer > 0; } - public Object get(int i) { + public T get(final int i) { return stack[i]; } - private void resizeStack(int newCapacity) { - Object[] newStack = new Object[newCapacity]; - System.arraycopy(stack, 0, newStack, 0, Math.min(stack.length, newCapacity)); + private void resizeStack(final int newCapacity) { + @SuppressWarnings("unchecked") + final T[] newStack = getArray(newCapacity); + System.arraycopy(stack, 0, newStack, 0, Math.min(pointer, newCapacity)); stack = newStack; } + @Override public String toString() { - StringBuffer result = new StringBuffer("["); + final StringBuffer result = new StringBuffer("["); for (int i = 0; i < pointer; i++) { if (i > 0) { result.append(", "); Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Fields.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Fields.java (.../Fields.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Fields.java (.../Fields.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,37 +1,89 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014 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 06. April 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; + + /** * Slightly nicer way to find, get and set fields in classes. Wraps standard java.lang.reflect.Field calls but wraps - * wraps exception in RuntimeExceptions. - * + * wraps exception in XStreamExceptions. + * * @author Joe Walnes + * @author Jörg Schaible */ public class Fields { - public static Field find(Class type, String name) { + public static Field locate(final Class definedIn, final Class fieldType, final boolean isStatic) { + Field field = null; try { - Field result = type.getDeclaredField(name); - result.setAccessible(true); + final Field[] fields = definedIn.getDeclaredFields(); + for (final Field field2 : fields) { + if (Modifier.isStatic(field2.getModifiers()) == isStatic) { + if (fieldType.isAssignableFrom(field2.getType())) { + field = field2; + } + } + } + if (field != null && !field.isAccessible()) { + field.setAccessible(true); + } + } catch (final SecurityException e) { + // active SecurityManager + } catch (final NoClassDefFoundError e) { + // restricted type in GAE + } + return field; + } + + public static Field find(final Class type, final String name) { + try { + final Field result = type.getDeclaredField(name); + if (!result.isAccessible()) { + result.setAccessible(true); + } return result; - } catch (NoSuchFieldException e) { - throw new RuntimeException("Could not access " + type.getName() + "." + name + " field"); + } catch (final NoSuchFieldException e) { + final String message = "Could not access " + type.getName() + "." + name + " field: " + e.getMessage(); + throw new IllegalArgumentException(message); + } catch (final NoClassDefFoundError e) { + final String message = "Could not access " + type.getName() + "." + name + " field: " + e.getMessage(); + throw new ObjectAccessException(message); } } - public static void write(Field field, Object instance, Object value) { + public static void write(final Field field, final Object instance, final Object value) { try { field.set(instance, value); - } catch (IllegalAccessException e) { - throw new RuntimeException("Could not write " + field.getType().getName() + "." + field.getName() + " field"); + } catch (final IllegalAccessException e) { + final String message = "Could not write " + field.getType().getName() + "." + field.getName() + " field"; + throw new ObjectAccessException(message, e); + } catch (final NoClassDefFoundError e) { + final String message = "Could not write " + field.getType().getName() + "." + field.getName() + " field"; + throw new ObjectAccessException(message, e); } } - public static Object read(Field field, Object instance) { + public static Object read(final Field field, final Object instance) { try { return field.get(instance); - } catch (IllegalAccessException e) { - throw new RuntimeException("Could not read " + field.getType().getName() + "." + field.getName() + " field"); + } catch (final IllegalAccessException e) { + final String message = "Could not read " + field.getType().getName() + "." + field.getName() + " field"; + throw new ObjectAccessException(message, e); + } catch (final NoClassDefFoundError e) { + final String message = "Could not read " + field.getType().getName() + "." + field.getName() + " field"; + throw new ObjectAccessException(message, e); } } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/HierarchicalStreams.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/HierarchicalStreams.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/HierarchicalStreams.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008, 2014 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 09. October 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Helper methods for {@link HierarchicalStreamReader} and {@link HierarchicalStreamWriter}. + * + * @author Jörg Schaible + * @since 1.3.1 + */ +public class HierarchicalStreams { + + public static Class readClassType(final HierarchicalStreamReader reader, final Mapper mapper) { + final String classAttribute = readClassAttribute(reader, mapper); + Class type; + if (classAttribute == null) { + type = mapper.realClass(reader.getNodeName()); + } else { + type = mapper.realClass(classAttribute); + } + return type; + } + + public static String readClassAttribute(final HierarchicalStreamReader reader, final Mapper mapper) { + String attributeName = mapper.aliasForSystemAttribute("resolves-to"); + String classAttribute = attributeName == null ? null : reader.getAttribute(attributeName); + if (classAttribute == null) { + attributeName = mapper.aliasForSystemAttribute("class"); + if (attributeName != null) { + classAttribute = reader.getAttribute(attributeName); + } + } + return classAttribute; + } + +} Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/IntQueue.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ObjectIdDictionary.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ObjectIdDictionary.java (.../ObjectIdDictionary.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ObjectIdDictionary.java (.../ObjectIdDictionary.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,52 +1,134 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2010, 2014 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 09. May 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; + /** * Store IDs against given object references. - *

    - * Behaves the same way as java.util.IdentityHashMap, but in JDK1.3 as well. + *

    + * Behaves similar to java.util.IdentityHashMap, but in JDK1.3 as well. Additionally the implementation keeps track of + * orphaned IDs by using a WeakReference to store the reference object. + *

    */ -public class ObjectIdDictionary { +public class ObjectIdDictionary { - private Map map = new HashMap(); + private final Map map = new HashMap(); + private final ReferenceQueue queue = new ReferenceQueue(); - private static class IdWrapper { + private static interface Wrapper { + @Override + int hashCode(); + @Override + boolean equals(Object obj); + + @Override + String toString(); + + Object get(); + } + + private static class IdWrapper implements Wrapper { + private final Object obj; + private final int hashCode; - public IdWrapper(Object obj) { + public IdWrapper(final Object obj) { + hashCode = System.identityHashCode(obj); this.obj = obj; } + @Override public int hashCode() { - return System.identityHashCode(obj); + return hashCode; } - public boolean equals(Object other) { - return obj == ((IdWrapper)other).obj; + @Override + public boolean equals(final Object other) { + return obj == ((Wrapper)other).get(); } + @Override public String toString() { return obj.toString(); } + + @Override + public Object get() { + return obj; + } } - public void associateId(Object obj, Object id) { - map.put(new IdWrapper(obj), id); + private class WeakIdWrapper extends WeakReference implements Wrapper { + + private final int hashCode; + + public WeakIdWrapper(final Object obj) { + super(obj, queue); + hashCode = System.identityHashCode(obj); + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(final Object other) { + return get() == ((Wrapper)other).get(); + } + + @Override + public String toString() { + final Object obj = get(); + return obj == null ? "(null)" : obj.toString(); + } } - public Object lookupId(Object obj) { - return map.get(new IdWrapper(obj)); + public void associateId(final Object obj, final E id) { + map.put(new WeakIdWrapper(obj), id); + cleanup(); } - public boolean containsId(Object item) { - return map.containsKey(new IdWrapper(item)); + public E lookupId(final Object obj) { + final E id = map.get(new IdWrapper(obj)); + return id; } - public void removeId(Object item) { + public boolean containsId(final Object item) { + final boolean b = map.containsKey(new IdWrapper(item)); + return b; + } + + public void removeId(final Object item) { map.remove(new IdWrapper(item)); + cleanup(); } + public int size() { + cleanup(); + return map.size(); + } + + @SuppressWarnings("unchecked") + private void cleanup() { + WeakIdWrapper wrapper; + while ((wrapper = (WeakIdWrapper)queue.poll()) != null) { + map.remove(wrapper); + } + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/OrderRetainingMap.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/OrderRetainingMap.java (.../OrderRetainingMap.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/OrderRetainingMap.java (.../OrderRetainingMap.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,37 +1,101 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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 06. February 2005 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; -import java.util.HashMap; -import java.util.List; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.TreeSet; -public class OrderRetainingMap extends HashMap { - private Set keyOrder = new ArraySet(); - private List valueOrder = new ArrayList(); - - public Object put(Object key, Object value) { - keyOrder.add(key); - valueOrder.add(value); +/** + * @deprecated As of upcoming use {@link java.util.LinkedHashMap} + */ +@Deprecated +public class OrderRetainingMap extends HashMap { + + private final ArraySet keyOrder = new ArraySet(); + private final List valueOrder = new ArrayList(); + + public OrderRetainingMap() { + super(); + } + + public OrderRetainingMap(final Map m) { + super(); + putAll(m); + } + + @Override + public void putAll(final Map m) { + for (final Map.Entry entry : m.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + @Override + public V put(final K key, final V value) { + final int idx = keyOrder.lastIndexOf(key); + if (idx < 0) { + keyOrder.add(key); + valueOrder.add(value); + } else { + valueOrder.set(idx, value); + } return super.put(key, value); } - public Collection values() { - return Collections.unmodifiableList(valueOrder); + @Override + public V remove(final Object key) { + final int idx = keyOrder.lastIndexOf(key); + if (idx != 0) { + keyOrder.remove(idx); + valueOrder.remove(idx); + } + return super.remove(key); } - public Set keySet() { - return Collections.unmodifiableSet(keyOrder); + @Override + public void clear() { + keyOrder.clear(); + valueOrder.clear(); + super.clear(); } - public Set entrySet() { - throw new UnsupportedOperationException(); + @Override + public Collection values() { + return Collections.unmodifiableList(valueOrder); } - private static class ArraySet extends ArrayList implements Set { + @Override + public Set keySet() { + return Collections.unmodifiableSet(keyOrder); } + @Override + public Set> entrySet() { + @SuppressWarnings("unchecked") + final Map.Entry[] entries = new Map.Entry[size()]; + for (final Map.Entry entry : super.entrySet()) { + entries[keyOrder.indexOf(entry.getKey())] = entry; + } + final Set> set = new ArraySet>(); + set.addAll(Arrays.asList(entries)); + return Collections.unmodifiableSet(set); + } + + private static class ArraySet extends ArrayList implements Set {} } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Pool.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Pool.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Pool.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2007, 2014 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 10. May 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import java.util.Arrays; + + +/** + * A simple pool implementation. + * + * @author Jörg Schaible + * @author Joe Walnes + */ +public class Pool { + + public interface Factory { + public T newInstance(); + } + + private final int initialPoolSize; + private final int maxPoolSize; + private final Factory factory; + private transient T[] pool; + private transient int nextAvailable; + + public Pool(final int initialPoolSize, final int maxPoolSize, final Factory factory) { + this.initialPoolSize = initialPoolSize; + this.maxPoolSize = maxPoolSize; + this.factory = factory; + } + + private T[] newArray(final int capacity, final T... t) { + return Arrays.copyOf(t, capacity); + } + + public T fetchFromPool() { + T result; + synchronized (this) { + if (pool == null) { + @SuppressWarnings("unchecked") + final T[] all = newArray(maxPoolSize); + pool = all; + for (nextAvailable = initialPoolSize; nextAvailable > 0;) { + putInPool(factory.newInstance()); + } + } + while (nextAvailable == maxPoolSize) { + try { + wait(); + } catch (final InterruptedException e) { + throw new RuntimeException("Interrupted whilst waiting for a free item in the pool: " + + e.getMessage()); + } + } + result = pool[nextAvailable++]; + if (result == null) { + result = factory.newInstance(); + putInPool(result); + ++nextAvailable; + } + } + return result; + } + + protected void putInPool(final T object) { + synchronized (this) { + if (nextAvailable == 0) { + throw new IllegalStateException("Cannot put more objects than " + + maxPoolSize + + " elements into this pool"); + } + pool[--nextAvailable] = object; + if (object == null) { + for (int i = maxPoolSize; i > nextAvailable;) { + if (pool[--i] != null) { + pool[nextAvailable] = pool[i]; + pool[i] = null; + break; + } + } + } + + notify(); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PresortedMap.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PresortedMap.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PresortedMap.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2006, 2007, 2010, 2014 XStream Committers. + * All rights reserved. + * + * Created on 12.10.2010 by Joerg Schaible, extracted from TreeMapConverter. + */ +package com.thoughtworks.xstream.core.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + + +/** + * @author Jörg Schaible + */ +public class PresortedMap implements SortedMap { + + private static class ArraySet extends ArrayList implements Set {} + + private final PresortedMap.ArraySet> set; + private final Comparator comparator; + + public PresortedMap() { + this(null, new ArraySet>()); + } + + public PresortedMap(final Comparator comparator) { + this(comparator, new ArraySet>()); + } + + private PresortedMap(final Comparator comparator, final PresortedMap.ArraySet> set) { + this.comparator = comparator != null ? comparator : new ArraySetComparator(set); + this.set = set; + } + + @Override + public Comparator comparator() { + return comparator; + } + + @Override + public Set> entrySet() { + return set; + } + + @Override + public K firstKey() { + throw new UnsupportedOperationException(); + } + + @Override + public SortedMap headMap(final Object toKey) { + throw new UnsupportedOperationException(); + } + + @Override + public Set keySet() { + final Set keySet = new ArraySet(); + for (final Map.Entry entry : set) { + keySet.add(entry.getKey()); + } + return keySet; + } + + @Override + public K lastKey() { + throw new UnsupportedOperationException(); + } + + @Override + public SortedMap subMap(final Object fromKey, final Object toKey) { + throw new UnsupportedOperationException(); + } + + @Override + public SortedMap tailMap(final Object fromKey) { + throw new UnsupportedOperationException(); + } + + @Override + public Collection values() { + final Set values = new ArraySet(); + for (final Map.Entry entry : set) { + values.add(entry.getValue()); + } + return values; + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsKey(final Object key) { + return false; + } + + @Override + public boolean containsValue(final Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public V get(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEmpty() { + return set.isEmpty(); + } + + @Override + public V put(final K key, final V value) { + set.add(new Map.Entry() { + + @Override + public K getKey() { + return key; + } + + @Override + public V getValue() { + return value; + } + + @Override + public V setValue(final V value) { + throw new UnsupportedOperationException(); + } + }); + return null; + } + + @Override + public void putAll(final Map m) { + for (final Map.Entry entry : m.entrySet()) { + @SuppressWarnings("unchecked") + final Map.Entry e = (Map.Entry)entry; + set.add(e); + } + } + + @Override + public V remove(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + return set.size(); + } + + private static class ArraySetComparator implements Comparator { + + private final ArrayList> list; + private Map.Entry[] array; + + ArraySetComparator(final ArrayList> list) { + this.list = list; + } + + @Override + public int compare(final K object1, final K object2) { + if (array == null || list.size() != array.length) { + @SuppressWarnings("unchecked") + final Map.Entry[] a = new Map.Entry[list.size()]; + if (array != null) { + System.arraycopy(array, 0, a, 0, array.length); + } + for (int i = array == null ? 0 : array.length; i < list.size(); ++i) { + a[i] = list.get(i); + } + array = a; + } + int idx1 = Integer.MAX_VALUE, idx2 = Integer.MAX_VALUE; + for (int i = 0; i < array.length && !(idx1 < Integer.MAX_VALUE && idx2 < Integer.MAX_VALUE); ++i) { + if (idx1 == Integer.MAX_VALUE && object1 == array[i].getKey()) { + idx1 = i; + } + if (idx2 == Integer.MAX_VALUE && object2 == array[i].getKey()) { + idx2 = i; + } + } + return idx1 - idx2; + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PresortedSet.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PresortedSet.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PresortedSet.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2006, 2007, 2010, 2014 XStream Committers. + * All rights reserved. + * + * Created on 12.10.2010 by Joerg Schaible, extracted from TreeSetConverter. + */ +package com.thoughtworks.xstream.core.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + + +/** + * @author Jörg Schaible + */ +public class PresortedSet implements SortedSet { + private final List list = new ArrayList(); + private final Comparator comparator; + + public PresortedSet() { + this(null); + } + + public PresortedSet(final Comparator comparator) { + this(comparator, null); + } + + public PresortedSet(final Comparator comparator, final Collection c) { + this.comparator = comparator; + if (c != null) { + addAll(c); + } + } + + @Override + public boolean add(final E e) { + return this.list.add(e); + } + + @Override + public boolean addAll(final Collection c) { + return this.list.addAll(c); + } + + @Override + public void clear() { + this.list.clear(); + } + + @Override + public boolean contains(final Object o) { + return this.list.contains(o); + } + + @Override + public boolean containsAll(final Collection c) { + return this.list.containsAll(c); + } + + @Override + public boolean equals(final Object o) { + return this.list.equals(o); + } + + @Override + public int hashCode() { + return this.list.hashCode(); + } + + @Override + public boolean isEmpty() { + return this.list.isEmpty(); + } + + @Override + public Iterator iterator() { + return this.list.iterator(); + } + + @Override + public boolean remove(final Object o) { + return this.list.remove(o); + } + + @Override + public boolean removeAll(final Collection c) { + return this.list.removeAll(c); + } + + @Override + public boolean retainAll(final Collection c) { + return this.list.retainAll(c); + } + + @Override + public int size() { + return this.list.size(); + } + + @Override + public Object[] toArray() { + return this.list.toArray(); + } + + @Override + public T[] toArray(final T[] a) { + return this.list.toArray(a); + } + + @Override + public Comparator comparator() { + return comparator; + } + + @Override + public E first() { + return list.isEmpty() ? null : list.get(0); + } + + @Override + public SortedSet headSet(final Object toElement) { + throw new UnsupportedOperationException(); + } + + @Override + public E last() { + return list.isEmpty() ? null : list.get(list.size() - 1); + } + + @Override + public SortedSet subSet(final Object fromElement, final Object toElement) { + throw new UnsupportedOperationException(); + } + + @Override + public SortedSet tailSet(final Object fromElement) { + throw new UnsupportedOperationException(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Primitives.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Primitives.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/Primitives.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2006, 2007, 2011, 2014 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 11. October 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import java.util.HashMap; +import java.util.Map; + + +/** + * Utility class for primitives. + * + * @author Jörg Schaible + * @since 1.2.1 + */ +public final class Primitives { + private final static Map, Class> BOX = new HashMap, Class>(); + private final static Map, Class> UNBOX = new HashMap, Class>(); + private final static Map> NAMED_PRIMITIVE = new HashMap>(); + private final static Map, Character> REPRESENTING_CHAR = new HashMap, Character>(); + + static { + final Class[][] boxing = new Class[][]{ + {Byte.TYPE, Byte.class}, {Character.TYPE, Character.class}, {Short.TYPE, Short.class}, + {Integer.TYPE, Integer.class}, {Long.TYPE, Long.class}, {Float.TYPE, Float.class}, + {Double.TYPE, Double.class}, {Boolean.TYPE, Boolean.class}, {Void.TYPE, Void.class},}; + final Character[] representingChars = { + new Character('B'), new Character('C'), new Character('S'), new Character('I'), new Character('J'), + new Character('F'), new Character('D'), new Character('Z'), null}; + for (int i = 0; i < boxing.length; i++) { + final Class primitiveType = boxing[i][0]; + final Class boxedType = boxing[i][1]; + BOX.put(primitiveType, boxedType); + UNBOX.put(boxedType, primitiveType); + NAMED_PRIMITIVE.put(primitiveType.getName(), primitiveType); + REPRESENTING_CHAR.put(primitiveType, representingChars[i]); + } + } + + /** + * Get the boxed type for a primitive. + * + * @param type the primitive type + * @return the boxed type or null + */ + static public Class box(final Class type) { + return BOX.get(type); + } + + /** + * Get the primitive type for a boxed one. + * + * @param type the boxed type + * @return the primitive type or null + */ + static public Class unbox(final Class type) { + return UNBOX.get(type); + } + + /** + * Check for a boxed type. + * + * @param type the type to check + * @return true if the type is boxed + * @since 1.4 + */ + static public boolean isBoxed(final Class type) { + return UNBOX.containsKey(type); + } + + /** + * Get the primitive type by name. + * + * @param name the name of the type + * @return the Java type or null + * @since 1.4 + */ + static public Class primitiveType(final String name) { + return NAMED_PRIMITIVE.get(name); + } + + /** + * Get the representing character of a primitive type. + * + * @param type the primitive type + * @return the representing character or 0 + * @since 1.4 + */ + static public char representingChar(final Class type) { + final Character ch = REPRESENTING_CHAR.get(type); + return ch == null ? 0 : ch.charValue(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PrioritizedList.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PrioritizedList.java (.../PrioritizedList.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/PrioritizedList.java (.../PrioritizedList.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,97 +1,106 @@ +/* + * Copyright (C) 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2011, 2014 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 06. February 2005 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; -import com.thoughtworks.xstream.converters.Converter; - import java.util.Iterator; +import java.util.Set; +import java.util.TreeSet; + /** * List that allows items to be added with a priority that will affect the order in which they are later iterated over. - * * Objects with a high priority will appear before objects with a low priority in the list. If two objects of the same - * priority are added to the list, the most recently added one will be iterated over first. - * + * priority are added to the list, the most recently added one will be iterated over first. Implementation uses a + * TreeSet, which has a guaranteed add time of O(log(n)). + * * @author Joe Walnes + * @author Guilherme Silveira */ -public class PrioritizedList { +public class PrioritizedList implements Iterable { - /** - * Start of forward only linked list. Each item contains a value, priority and pointer to next item. - * The first item does not contain a value, rather just a pointer to the next real item. This makes - * the add() algorithm easier as there is no special case for adding to the beginning of the list. - */ - private final LinkedItem pointerToFirst = new LinkedItem(null, 0, null); - + private final Set> set = new TreeSet>(); private int lowestPriority = Integer.MAX_VALUE; + private int lastId = 0; - /** - * Add an item with a default priority of zero. - */ - public void add(Object item) { - add(item, 0); - } - - public void add(Object item, int priority) { - // Note: this is quite efficient if the client tends to add low priority items before high priority items - // as it will not have to iterate over much of the list. However for the other way round, maybe some - // optimizations can be made? -joe - LinkedItem current = pointerToFirst; - while(current.next != null && priority < current.next.priority) { - current = current.next; + public void add(final E item, final int priority) { + if (this.lowestPriority > priority) { + this.lowestPriority = priority; } - current.next = new LinkedItem(item, priority, current.next); - if (priority < lowestPriority) { - lowestPriority = priority; - } + this.set.add(new PrioritizedItem(item, priority, ++lastId)); } - public Iterator iterator() { - return new LinkedItemIterator(pointerToFirst.next); + @Override + public Iterator iterator() { + return new PrioritizedItemIterator(this.set.iterator()); } - public Object firstOfLowestPriority() { - for(LinkedItem current = pointerToFirst.next; current != null; current = current.next) { - if (current.priority == lowestPriority) { - return current.value; - } - } - return null; - } + private static class PrioritizedItem implements Comparable> { - private static class LinkedItem { - - final Object value; + final V value; final int priority; + final int id; - LinkedItem next; - - public LinkedItem(Object value, int priority, LinkedItem next) { + public PrioritizedItem(final V value, final int priority, final int id) { this.value = value; this.priority = priority; - this.next = next; + this.id = id; } + @Override + public int compareTo(final PrioritizedItem other) { + if (this.priority != other.priority) { + return other.priority - this.priority; + } + return other.id - this.id; + } + + @Override + public int hashCode() { + return Integer.valueOf(id).hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof PrioritizedItem)) { + return false; + } + @SuppressWarnings("unchecked") + final PrioritizedItem other = (PrioritizedItem)obj; + return this.id == other.id; + } + } - private static class LinkedItemIterator implements Iterator { + private static class PrioritizedItemIterator implements Iterator { - private LinkedItem current; + private final Iterator> iterator; - public LinkedItemIterator(LinkedItem current) { - this.current = current; + public PrioritizedItemIterator(final Iterator> iterator) { + this.iterator = iterator; } + @Override public void remove() { throw new UnsupportedOperationException(); } + @Override public boolean hasNext() { - return current != null; + return iterator.hasNext(); } - public Object next() { - Object result = current.value; - current = current.next; - return result; + @Override + public V next() { + return iterator.next().value; } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/QuickWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/QuickWriter.java (.../QuickWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/QuickWriter.java (.../QuickWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,28 +1,40 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.core.util; -import com.thoughtworks.xstream.io.StreamException; - +import java.io.Closeable; import java.io.IOException; import java.io.Writer; -public class QuickWriter { +import com.thoughtworks.xstream.io.StreamException; + +public class QuickWriter implements Closeable { + private final Writer writer; - private char[] buffer; + private final char[] buffer; private int pointer; - public QuickWriter(Writer writer) { - this.writer = writer; - buffer = new char[1024]; + public QuickWriter(final Writer writer) { + this(writer, 1024); } - public QuickWriter(Writer writer, int bufferSize) { + public QuickWriter(final Writer writer, final int bufferSize) { this.writer = writer; buffer = new char[bufferSize]; } - public void write(String str) { - int len = str.length(); + public void write(final String str) { + final int len = str.length(); if (pointer + len >= buffer.length) { flush(); if (len > buffer.length) { @@ -34,15 +46,19 @@ pointer += len; } - public void write(char c) { + public void write(final char c) { if (pointer + 1 >= buffer.length) { flush(); + if (buffer.length == 0) { + raw(c); + return; + } } buffer[pointer++] = c; } - public void write(char[] c) { - int len = c.length; + public void write(final char[] c) { + final int len = c.length; if (pointer + len >= buffer.length) { flush(); if (len > buffer.length) { @@ -59,27 +75,37 @@ writer.write(buffer, 0, pointer); pointer = 0; writer.flush(); - } catch (IOException e) { + } catch (final IOException e) { throw new StreamException(e); } } + @Override public void close() { try { writer.write(buffer, 0, pointer); pointer = 0; writer.close(); - } catch (IOException e) { + } catch (final IOException e) { throw new StreamException(e); } } - private void raw(char[] c) { + private void raw(final char[] c) { try { writer.write(c); writer.flush(); - } catch (IOException e) { + } catch (final IOException e) { throw new StreamException(e); } } + + private void raw(final char c) { + try { + writer.write(c); + writer.flush(); + } catch (final IOException e) { + throw new StreamException(e); + } + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/SelfStreamingInstanceChecker.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/SelfStreamingInstanceChecker.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/SelfStreamingInstanceChecker.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006, 2007, 2013, 2014 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 01. March 2013 by Joerg Schaible, moved from package + * com.thoughtworks.xstream.converters.reflection. + */ +package com.thoughtworks.xstream.core.util; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * A special converter that prevents self-serialization. The serializing XStream instance adds a converter of this type + * to prevent self-serialization and will throw an exception instead. + * + * @author Jörg Schaible + * @since 1.2 + */ +public class SelfStreamingInstanceChecker implements Converter { + + private final Object self; + private Converter defaultConverter; + private final ConverterLookup lookup; + + /** + * @since 1.4.5 + */ + public SelfStreamingInstanceChecker(final ConverterLookup lookup, final Object xstream) { + this.lookup = lookup; + self = xstream; + } + + /** + * @deprecated As of 1.4.5 use {@link #SelfStreamingInstanceChecker(ConverterLookup, Object)} + */ + @Deprecated + public SelfStreamingInstanceChecker(final Converter defaultConverter, final Object xstream) { + this.defaultConverter = defaultConverter; + self = xstream; + lookup = null; + } + + @Override + public boolean canConvert(final Class type) { + return type == self.getClass(); + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + if (source == self) { + throw new ConversionException("Cannot marshal the XStream instance in action"); + } + getConverter().marshal(source, writer, context); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + return getConverter().unmarshal(reader, context); + } + + private Converter getConverter() { + return defaultConverter != null ? defaultConverter : lookup.lookupConverterForType(Object.class); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ThreadSafePropertyEditor.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ThreadSafePropertyEditor.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ThreadSafePropertyEditor.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2007, 2008, 2014 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 20. September 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import java.beans.PropertyEditor; + +import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; + + +/** + * Wrapper around {@link PropertyEditor} that can be called by multiple threads concurrently. + *

    + * A PropertyEditor is not thread safe. To make best use of resources, the PropertyEditor provides a dynamically sizing + * pool of instances, each of which will only be called by a single thread at a time. + *

    + *

    + * The pool has a maximum capacity, to limit overhead. If all instances in the pool are in use and another is required, + * it shall block until one becomes available. + *

    + * + * @author Jörg Schaible + * @since 1.3 + */ +public class ThreadSafePropertyEditor { + + private final Class editorType; + private final Pool pool; + + public ThreadSafePropertyEditor( + final Class type, final int initialPoolSize, final int maxPoolSize) { + if (!PropertyEditor.class.isAssignableFrom(type)) { + throw new IllegalArgumentException(type.getName() + " is not a " + PropertyEditor.class.getName()); + } + editorType = type; + pool = new Pool(initialPoolSize, maxPoolSize, new Pool.Factory() { + @Override + public PropertyEditor newInstance() { + try { + return editorType.newInstance(); + } catch (final InstantiationException e) { + throw new ObjectAccessException("Could not call default constructor of " + editorType.getName(), e); + } catch (final IllegalAccessException e) { + throw new ObjectAccessException("Could not call default constructor of " + editorType.getName(), e); + } + } + + }); + } + + public String getAsText(final Object object) { + final PropertyEditor editor = fetchFromPool(); + try { + editor.setValue(object); + return editor.getAsText(); + } finally { + pool.putInPool(editor); + } + } + + public Object setAsText(final String str) { + final PropertyEditor editor = fetchFromPool(); + try { + editor.setAsText(str); + return editor.getValue(); + } finally { + pool.putInPool(editor); + } + } + + private PropertyEditor fetchFromPool() { + return pool.fetchFromPool(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ThreadSafeSimpleDateFormat.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ThreadSafeSimpleDateFormat.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/ThreadSafeSimpleDateFormat.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2012, 2014 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 06. May 2004 by Joe Walnes + */ +package com.thoughtworks.xstream.core.util; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + + +/** + * Wrapper around java.text.SimpleDateFormat that can be called by multiple threads concurrently. + *

    + * SimpleDateFormat has a high overhead in creating and is not thread safe. To make best use of resources, the + * ThreadSafeSimpleDateFormat provides a dynamically sizing pool of instances, each of which will only be called by a + * single thread at a time. + *

    + *

    + * The pool has a maximum capacity, to limit overhead. If all instances in the pool are in use and another is required, + * it shall block until one becomes available. + *

    + * + * @author Joe Walnes + * @author Jörg Schaible + */ +public class ThreadSafeSimpleDateFormat { + + private final String formatString; + private final Pool pool; + private final TimeZone timeZone; + + public ThreadSafeSimpleDateFormat( + final String format, final TimeZone timeZone, final int initialPoolSize, final int maxPoolSize, + final boolean lenient) { + this(format, timeZone, Locale.ENGLISH, initialPoolSize, maxPoolSize, lenient); + } + + public ThreadSafeSimpleDateFormat( + final String format, final TimeZone timeZone, final Locale locale, final int initialPoolSize, + final int maxPoolSize, final boolean lenient) { + formatString = format; + this.timeZone = timeZone; + pool = new Pool(initialPoolSize, maxPoolSize, new Pool.Factory() { + @Override + public SimpleDateFormat newInstance() { + final SimpleDateFormat dateFormat = new SimpleDateFormat(formatString, locale); + dateFormat.setLenient(lenient); + return dateFormat; + } + + }); + } + + public String format(final Date date) { + final DateFormat format = fetchFromPool(); + try { + return format.format(date); + } finally { + pool.putInPool(format); + } + } + + public Date parse(final String date) throws ParseException { + final DateFormat format = fetchFromPool(); + try { + return format.parse(date); + } finally { + pool.putInPool(format); + } + } + + private DateFormat fetchFromPool() { + final DateFormat format = pool.fetchFromPool(); + final TimeZone tz = timeZone != null ? timeZone : TimeZone.getDefault(); + if (!tz.equals(format.getTimeZone())) { + format.setTimeZone(tz); + } + return format; + } + + @Override + public String toString() { + return formatString; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/TypedNull.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/TypedNull.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/TypedNull.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2007, 2014 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 30. March 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +/** + * A placeholder for a null value of a specific type. + * + * @author Jörg Schaible + * @since 1.2.2 + */ +public class TypedNull { + private final Class type; + + public TypedNull(final Class type) { + super(); + this.type = type; + } + + public Class getType() { + return this.type; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/WeakCache.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/WeakCache.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/WeakCache.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2011, 2013, 2014 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 12. July 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + + +/** + * A HashMap implementation with weak references values and by default for the key. When the value is garbage collected, + * the key will also vanish from the map. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class WeakCache extends AbstractMap { + + private final Map> map; + + /** + * Construct a WeakCache with weak keys. + *

    + * Note, that the internally used WeakHashMap is not thread-safe. + *

    + * + * @since 1.4 + */ + public WeakCache() { + this(new WeakHashMap>()); + } + + /** + * Construct a WeakCache. + * + * @param map the map to use + * @since 1.4 + */ + public WeakCache(final Map> map) { + this.map = map; + } + + @Override + public V get(final Object key) { + final Reference reference = map.get(key); + return reference != null ? reference.get() : null; + } + + @Override + public V put(final K key, final V value) { + final Reference ref = map.put(key, createReference(value)); + return ref == null ? null : ref.get(); + } + + @Override + public V remove(final Object key) { + final Reference ref = map.remove(key); + return ref == null ? null : ref.get(); + } + + protected Reference createReference(final V value) { + return new WeakReference(value); + } + + @Override + public boolean containsValue(final Object value) { + final Boolean result = (Boolean)iterate(new Visitor() { + + @Override + public Object visit(final Object element) { + return element.equals(value) ? Boolean.TRUE : null; + } + + }, Visitor.Type.value); + return result == Boolean.TRUE; + } + + @Override + public int size() { + if (map.size() == 0) { + return 0; + } + final int i[] = new int[1]; + i[0] = 0; + iterate(new Visitor() { + + @Override + public Object visit(final Object element) { + ++i[0]; + return null; + } + + }, Visitor.Type.key); + return i[0]; + } + + @Override + public Collection values() { + final Collection collection = new ArrayList(); + if (map.size() != 0) { + iterate(new Visitor() { + + @Override + public Object visit(final Object element) { + @SuppressWarnings("unchecked") + final V value = (V)element; + collection.add(value); + return null; + } + + }, Visitor.Type.value); + } + return collection; + } + + @Override + public Set> entrySet() { + final Set> set = new HashSet>(); + if (map.size() != 0) { + iterate(new Visitor() { + + @Override + public Object visit(final Object element) { + @SuppressWarnings("unchecked") + final Map.Entry> entry = (Map.Entry>)element; + set.add(new Map.Entry() { + + @Override + public K getKey() { + return entry.getKey(); + } + + @Override + public V getValue() { + return entry.getValue().get(); + } + + @Override + public V setValue(final V value) { + final Reference reference = entry.setValue(createReference(value)); + return reference != null ? reference.get() : null; + } + + }); + return null; + } + + }, Visitor.Type.entry); + } + return set; + } + + private Object iterate(final Visitor visitor, final Visitor.Type type) { + Object result = null; + for (final Iterator>> iter = map.entrySet().iterator(); result == null + && iter.hasNext();) { + final Map.Entry> entry = iter.next(); + final Reference reference = entry.getValue(); + final V element = reference.get(); + if (element == null) { + iter.remove(); + continue; + } + switch (type) { + case value: + result = visitor.visit(element); + break; + case key: + result = visitor.visit(entry.getKey()); + break; + case entry: + result = visitor.visit(entry); + break; + } + + } + return result; + } + + private interface Visitor { + enum Type {key, value, entry}; + Object visit(Object element); + } + + @Override + public boolean containsKey(final Object key) { + return map.containsKey(key); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public Set keySet() { + return map.keySet(); + } + + @Override + public boolean equals(final Object o) { + return map.equals(o); + } + + @Override + public int hashCode() { + return map.hashCode(); + } + + @Override + public String toString() { + return map.toString(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/XmlHeaderAwareReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/XmlHeaderAwareReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/core/util/XmlHeaderAwareReader.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2007, 2008, 2010, 2014 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 13. September 2007 by Joerg Schaible. + */ + +package com.thoughtworks.xstream.core.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PushbackInputStream; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.nio.CharBuffer; +import java.util.HashMap; +import java.util.Map; + + +/** + * A {@link Reader} that evaluates the XML header. It selects its encoding based on the encoding read with the XML + * header of the provided {@link InputStream}. The default encoding is UTF-8 and the version is 1.0 if the + * stream does not contain an XML header or the attributes are not set within the header. + * + * @author Jörg Schaible + * @since 1.3 + */ +public final class XmlHeaderAwareReader extends Reader { + + private final InputStreamReader reader; + private final double version; + + private static final String KEY_ENCODING = "encoding"; + private static final String KEY_VERSION = "version"; + + private static final String XML_TOKEN = "?xml"; + + private static final int STATE_BOM = 0; + private static final int STATE_START = 1; + private static final int STATE_AWAIT_XML_HEADER = 2; + private static final int STATE_ATTR_NAME = 3; + private static final int STATE_ATTR_VALUE = 4; + + /** + * Constructs an XmlHeaderAwareReader. + * + * @param in the {@link InputStream} + * @throws UnsupportedEncodingException if the encoding is not supported + * @throws IOException occurred while reading the XML header + * @since 1.3 + */ + public XmlHeaderAwareReader(final InputStream in) throws UnsupportedEncodingException, IOException { + final PushbackInputStream[] pin = new PushbackInputStream[]{in instanceof PushbackInputStream + ? (PushbackInputStream)in + : new PushbackInputStream(in, 64)}; + final Map header = getHeader(pin); + version = Double.parseDouble(header.get(KEY_VERSION)); + reader = new InputStreamReader(pin[0], header.get(KEY_ENCODING)); + } + + private Map getHeader(final PushbackInputStream[] in) throws IOException { + final Map header = new HashMap(); + header.put(KEY_ENCODING, "utf-8"); + header.put(KEY_VERSION, "1.0"); + + int state = STATE_BOM; + final ByteArrayOutputStream out = new ByteArrayOutputStream(64); + int i = 0; + char ch = 0; + char valueEnd = 0; + final StringBuffer name = new StringBuffer(); + final StringBuffer value = new StringBuffer(); + boolean escape = false; + while (i != -1 && (i = in[0].read()) != -1) { + out.write(i); + ch = (char)i; + switch (state) { + case STATE_BOM: + if (ch == 0xEF && out.size() == 1 || ch == 0xBB && out.size() == 2 || ch == 0xBF && out.size() == 3) { + if (ch == 0xBF) { + out.reset(); + state = STATE_START; + } + break; + } else if (out.size() > 1) { + i = -1; + break; + } else { + state = STATE_START; + } + //$FALL-THROUGH$ + case STATE_START: + if (!Character.isWhitespace(ch)) { + if (ch == '<') { + state = STATE_AWAIT_XML_HEADER; + } else { + i = -1; + } + } + break; + case STATE_AWAIT_XML_HEADER: + if (!Character.isWhitespace(ch)) { + name.append(Character.toLowerCase(ch)); + if (!XML_TOKEN.startsWith(name.substring(0))) { + i = -1; + } + } else { + if (name.toString().equals(XML_TOKEN)) { + state = STATE_ATTR_NAME; + name.setLength(0); + } else { + i = -1; + } + } + break; + case STATE_ATTR_NAME: + if (!Character.isWhitespace(ch)) { + if (ch == '=') { + state = STATE_ATTR_VALUE; + } else { + ch = Character.toLowerCase(ch); + if (Character.isLetter(ch)) { + name.append(ch); + } else { + i = -1; + } + } + } else if (name.length() > 0) { + i = -1; + } + break; + case STATE_ATTR_VALUE: + if (valueEnd == 0) { + if (ch == '"' || ch == '\'') { + valueEnd = ch; + } else { + i = -1; + } + } else { + if (ch == '\\' && !escape) { + escape = true; + break; + } + if (ch == valueEnd && !escape) { + valueEnd = 0; + state = STATE_ATTR_NAME; + header.put(name.toString(), value.toString()); + name.setLength(0); + value.setLength(0); + } else { + escape = false; + if (ch != '\n') { + value.append(ch); + } else { + i = -1; + } + } + } + break; + } + } + + final byte[] pushbackData = out.toByteArray(); + for (i = pushbackData.length; i-- > 0;) { + final byte b = pushbackData[i]; + try { + in[0].unread(b); + } catch (final IOException ex) { + in[0] = new PushbackInputStream(in[0], ++i); + } + } + return header; + } + + /** + * @see InputStreamReader#getEncoding() + * @since 1.3 + */ + public String getEncoding() { + return reader.getEncoding(); + } + + /** + * @return the XML version + * @since 1.3 + */ + public double getVersion() { + return version; + } + + @Override + public void mark(final int readAheadLimit) throws IOException { + reader.mark(readAheadLimit); + } + + @Override + public boolean markSupported() { + return reader.markSupported(); + } + + @Override + public int read() throws IOException { + return reader.read(); + } + + @Override + public int read(final char[] cbuf, final int offset, final int length) throws IOException { + return reader.read(cbuf, offset, length); + } + + @Override + public int read(final char[] cbuf) throws IOException { + return reader.read(cbuf); + } + + @Override + public int read(final CharBuffer target) throws IOException { + return reader.read(target); + } + + @Override + public boolean ready() throws IOException { + return reader.ready(); + } + + @Override + public void reset() throws IOException { + reader.reset(); + } + + @Override + public long skip(final long n) throws IOException { + return reader.skip(n); + } + + @Override + public void close() throws IOException { + reader.close(); + } + + @Override + public boolean equals(final Object obj) { + return reader.equals(obj); + } + + @Override + public int hashCode() { + return reader.hashCode(); + } + + @Override + public String toString() { + return reader.toString(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AbstractDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AbstractDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AbstractDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 15. August 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; + +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.naming.NoNameCoder; + + +/** + * Abstract base class for all HierarchicalStreamDriver implementations. Implementations of + * {@link HierarchicalStreamDriver} should rather be derived from this class then implementing the interface directly. + * + * @author Jörg Schaible + * @since 1.4 + */ +public abstract class AbstractDriver implements HierarchicalStreamDriver { + + private final NameCoder replacer; + + /** + * Creates an AbstractDriver with a NameCoder that does nothing. + */ + public AbstractDriver() { + this(new NoNameCoder()); + } + + /** + * Creates an AbstractDriver with a provided {@link NameCoder}. + * + * @param nameCoder the name coder for the target format + */ + public AbstractDriver(final NameCoder nameCoder) { + replacer = nameCoder; + } + + protected NameCoder getNameCoder() { + return replacer; + } + + @Override + public HierarchicalStreamReader createReader(final URL in) { + try { + return createReader(in.openStream()); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamReader createReader(final File in) { + try { + return createReader(new FileInputStream(in)); + } catch (final FileNotFoundException e) { + throw new StreamException(e); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AbstractReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AbstractReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AbstractReader.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 16. August 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io; + +import com.thoughtworks.xstream.core.util.Cloneables; +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.naming.NoNameCoder; + + +/** + * Abstract base class for all HierarchicalStreamReader implementations. Implementations of + * {@link HierarchicalStreamReader} should rather be derived from this class then implementing the interface directly. + * + * @author Jörg Schaible + * @since 1.4 + */ +public abstract class AbstractReader implements ExtendedHierarchicalStreamReader { + + private final NameCoder nameCoder; + + /** + * Creates an AbstractReader with a NameCoder that does nothing. + * + * @since 1.4 + */ + protected AbstractReader() { + this(new NoNameCoder()); + } + + /** + * Creates an AbstractReader with a provided {@link NameCoder}. + * + * @param nameCoder the name coder used to read names from the incoming format + * @since 1.4 + */ + protected AbstractReader(final NameCoder nameCoder) { + this.nameCoder = Cloneables.cloneIfPossible(nameCoder); + } + + @Override + public HierarchicalStreamReader underlyingReader() { + return this; + } + + /** + * Decode a node name from the target format. + * + * @param name the name in the target format + * @return the original name + * @since 1.4 + */ + public String decodeNode(final String name) { + return nameCoder.decodeNode(name); + } + + /** + * Decode an attribute name from the target format. + * + * @param name the name in the target format + * @return the original name + * @since 1.4 + */ + public String decodeAttribute(final String name) { + return nameCoder.decodeAttribute(name); + } + + /** + * Encode the node name again into the name of the target format. Internally used. + * + * @param name the original name + * @return the name in the target format + * @since 1.4 + */ + protected String encodeNode(final String name) { + return nameCoder.encodeNode(name); + } + + /** + * Encode the attribute name again into the name of the target format. Internally used. + * + * @param name the original name + * @return the name in the target format + * @since 1.4 + */ + protected String encodeAttribute(final String name) { + return nameCoder.encodeAttribute(name); + } + + @Override + public String peekNextChild() { + throw new UnsupportedOperationException("peekNextChild"); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AbstractWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AbstractWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AbstractWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 17. August 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io; + +import com.thoughtworks.xstream.core.util.Cloneables; +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.naming.NoNameCoder; + + +/** + * Abstract base class for all HierarchicalStreamWriter implementations. Implementations of + * {@link HierarchicalStreamWriter} should rather be derived from this class then implementing the interface directly. + * + * @author Jörg Schaible + * @since 1.4 + */ +public abstract class AbstractWriter implements ExtendedHierarchicalStreamWriter { + + private final NameCoder nameCoder; + + /** + * Creates an AbstractWriter with a NameCoder that does nothing. + * + * @since 1.4 + */ + protected AbstractWriter() { + this(new NoNameCoder()); + } + + /** + * Creates an AbstractWriter with a provided {@link NameCoder}. + * + * @param nameCoder the name coder used to write names in the target format + * @since 1.4 + */ + protected AbstractWriter(final NameCoder nameCoder) { + this.nameCoder = Cloneables.cloneIfPossible(nameCoder); + } + + @Override + public void startNode(final String name, final Class clazz) { + startNode(name); + } + + @Override + public HierarchicalStreamWriter underlyingWriter() { + return this; + } + + /** + * Encode the node name into the name of the target format. + * + * @param name the original name + * @return the name in the target format + * @since 1.4 + */ + public String encodeNode(final String name) { + return nameCoder.encodeNode(name); + } + + /** + * Encode the attribute name into the name of the target format. + * + * @param name the original name + * @return the name in the target format + * @since 1.4 + */ + public String encodeAttribute(final String name) { + return nameCoder.encodeAttribute(name); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AttributeNameIterator.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AttributeNameIterator.java (.../AttributeNameIterator.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/AttributeNameIterator.java (.../AttributeNameIterator.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,33 +1,48 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 24. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.io; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; - import java.util.Iterator; + /** * Provide an iterator over the attribute names of the current node of a reader. - * + * * @author Joe Walnes + * @deprecated As of upcoming, it is an internal helper class only */ -public class AttributeNameIterator implements Iterator { +@Deprecated +public class AttributeNameIterator implements Iterator { private int current; private final int count; private final HierarchicalStreamReader reader; - public AttributeNameIterator(HierarchicalStreamReader reader) { + public AttributeNameIterator(final HierarchicalStreamReader reader) { this.reader = reader; count = reader.getAttributeCount(); } + @Override public boolean hasNext() { return current < count; } - public Object next() { + @Override + public String next() { return reader.getAttributeName(current++); } + @Override public void remove() { throw new UnsupportedOperationException(); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamReader.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2011 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 13. October 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.io; + +/** + * @author Jörg Schaible + * @since 1.4.2 + */ +public interface ExtendedHierarchicalStreamReader extends HierarchicalStreamReader { + + /** + * Peek the name of the next child. In situation where {@link #hasMoreChildren()} returns + * true, peek the tag name of the child. + * + * @since 1.4.2 + */ + String peekNextChild(); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 22. June 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.io; + +/** + * @author Paul Hammant + */ +public interface ExtendedHierarchicalStreamWriter extends HierarchicalStreamWriter { + + void startNode(String name, Class clazz); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriterHelper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriterHelper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriterHelper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 22. June 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.io; + +public class ExtendedHierarchicalStreamWriterHelper { + public static void startNode(final HierarchicalStreamWriter writer, final String name, final Class clazz) { + if (writer instanceof ExtendedHierarchicalStreamWriter) { + ((ExtendedHierarchicalStreamWriter)writer).startNode(name, clazz); + } else { + writer.startNode(name); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamDriver.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamDriver.java (.../HierarchicalStreamDriver.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamDriver.java (.../HierarchicalStreamDriver.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,24 +1,85 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2011 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io; -import java.io.Reader; -import java.io.Writer; +import java.io.File; import java.io.InputStream; import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; /** - * Provides implementation of XML parsers and writers to XStream. + * Provides implementation of stream parsers and writers to XStream. * * @author Joe Walnes * @author James Strachan */ public interface HierarchicalStreamDriver { + /** + * Create the HierarchicalStreamReader with the stream parser reading from the IO reader. + * + * @param in the {@link Reader} with the data to parse + * @return the HierarchicalStreamReader + */ HierarchicalStreamReader createReader(Reader in); - /** @since 1.2 */ + + /** + * Create the HierarchicalStreamReader with the stream parser reading from the input stream. + * + * @param in the {@link InputStream} with the data to parse + * @since 1.1.3 + */ HierarchicalStreamReader createReader(InputStream in); + /** + * Create the HierarchicalStreamReader with the stream parser reading from a URL. + * + * Depending on the parser implementation, some might take the URL as SystemId to resolve + * additional references. + * + * @param in the {@link URL} defining the location with the data to parse + * @return the HierarchicalStreamReader + * @since 1.4 + */ + HierarchicalStreamReader createReader(URL in); + + /** + * Create the HierarchicalStreamReader with the stream parser reading from a File. + * + * Depending on the parser implementation, some might take the file path as SystemId to + * resolve additional references. + * + * @param in the {@link URL} defining the location with the data to parse + * @return the HierarchicalStreamReader + * @since 1.4 + */ + HierarchicalStreamReader createReader(File in); + + /** + * Create the HierarchicalStreamWriter with the formatted writer. + * + * @param out the {@link Writer} to receive the formatted data + * @return the HierarchicalStreamWriter + */ HierarchicalStreamWriter createWriter(Writer out); - /** @since 1.2 */ + /** + * Create the HierarchicalStreamWriter with the formatted writer. + * + * @param out the {@link OutputStream} to receive the formatted data + * @return the HierarchicalStreamWriter + * @since 1.1.3 + */ HierarchicalStreamWriter createWriter(OutputStream out); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamReader.java (.../HierarchicalStreamReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamReader.java (.../HierarchicalStreamReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,21 +1,42 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io; +import java.io.Closeable; +import java.util.Iterator; + +import com.thoughtworks.xstream.converters.ErrorReporter; import com.thoughtworks.xstream.converters.ErrorWriter; -import java.util.Iterator; /** * @author Joe Walnes */ -public interface HierarchicalStreamReader { +public interface HierarchicalStreamReader extends ErrorReporter, Closeable { /** * Does the node have any more children remaining that have not yet been read? */ boolean hasMoreChildren(); + /** + * Select the current child as current node. A call to this function must be balanced with a call to + * {@link #moveUp()}. + */ void moveDown(); + /** + * Select the parent node as current node. + */ void moveUp(); /** @@ -37,7 +58,7 @@ * Get the value of an attribute of the current node, by index. */ String getAttribute(int index); - + /** * Number of attributes in current node. */ @@ -49,46 +70,49 @@ String getAttributeName(int index); /** - * Names of attributes (as Strings). + * Names of attributes. */ - Iterator getAttributeNames(); + Iterator getAttributeNames(); /** - * If any errors are detected, allow the reader to add any additional information that can aid debugging - * (such as line numbers, XPath expressions, etc). + * If any errors are detected, allow the reader to add any additional information that can aid debugging (such as + * line numbers, XPath expressions, etc). */ + @Override void appendErrors(ErrorWriter errorWriter); /** * Close the reader, if necessary. */ + @Override void close(); /** * Return the underlying HierarchicalStreamReader implementation. - * - *

    If a Converter needs to access methods of a specific HierarchicalStreamReader implementation that are not - * defined in the HierarchicalStreamReader interface, it should call this method before casting. This is because - * the reader passed to the Converter is often wrapped/decorated by another implementation to provide additional - * functionality (such as XPath tracking).

    - * - *

    For example:

    - *
    MySpecificReader mySpecificReader = (MySpecificReader)reader; // INCORRECT!
    -     * mySpecificReader.doSomethingSpecific();
    - - *
    MySpecificReader mySpecificReader = (MySpecificReader)reader.underlyingReader();  // CORRECT!
    -     * mySpecificReader.doSomethingSpecific();
    - * - *

    Implementations of HierarchicalStreamReader should return 'this', unless they are a decorator, in which case - * they should delegate to whatever they are wrapping.

    + *

    + * If a Converter needs to access methods of a specific HierarchicalStreamReader implementation that are not defined + * in the HierarchicalStreamReader interface, it should call this method before casting. This is because the reader + * passed to the Converter is often wrapped/decorated by another implementation to provide additional functionality + * (such as XPath tracking). + *

    + *

    + * For example: + *

    + * + *
    +     * MySpecificReader mySpecificReader = (MySpecificReader)reader; // INCORRECT!
    +     * mySpecificReader.doSomethingSpecific();
    +     * 
    + * + *
    +     * MySpecificReader mySpecificReader = (MySpecificReader)reader.underlyingReader();  // CORRECT!
    +     * mySpecificReader.doSomethingSpecific();
    +     * 
    + *

    + * Implementations of HierarchicalStreamReader should return 'this', unless they are a decorator, in which case they + * should delegate to whatever they are wrapping. + *

    */ HierarchicalStreamReader underlyingReader(); - /** - * @deprecated This method should not be used and is only provided for backwards compatability. - * As of XStream 1.1.1, you can use the {@link #underlyingReader()} method to get the underlying - * reader implementation and call implementation specific methods on that. - */ - Object peekUnderlyingNode(); - } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamWriter.java (.../HierarchicalStreamWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/HierarchicalStreamWriter.java (.../HierarchicalStreamWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,9 +1,23 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io; +import java.io.Closeable; + + /** * @author Joe Walnes */ -public interface HierarchicalStreamWriter { +public interface HierarchicalStreamWriter extends Closeable { void startNode(String name); @@ -24,25 +38,34 @@ /** * Close the writer, if necessary. */ + @Override void close(); /** * Return the underlying HierarchicalStreamWriter implementation. - * - *

    If a Converter needs to access methods of a specific HierarchicalStreamWriter implementation that are not - * defined in the HierarchicalStreamWriter interface, it should call this method before casting. This is because - * the writer passed to the Converter is often wrapped/decorated by another implementation to provide additional - * functionality (such as XPath tracking).

    - * - *

    For example:

    - *
    MySpecificWriter mySpecificWriter = (MySpecificWriter)writer; // INCORRECT!
    -     * mySpecificWriter.doSomethingSpecific();
    - - *
    MySpecificWriter mySpecificWriter = (MySpecificWriter)writer.underlyingWriter();  // CORRECT!
    -     * mySpecificWriter.doSomethingSpecific();
    - * - *

    Implementations of HierarchicalStreamWriter should return 'this', unless they are a decorator, in which case - * they should delegate to whatever they are wrapping.

    + *

    + * If a Converter needs to access methods of a specific HierarchicalStreamWriter implementation that are not defined + * in the HierarchicalStreamWriter interface, it should call this method before casting. This is because the writer + * passed to the Converter is often wrapped/decorated by another implementation to provide additional functionality + * (such as XPath tracking). + *

    + *

    + * For example: + *

    + * + *
    +     * MySpecificWriter mySpecificWriter = (MySpecificWriter)writer; // INCORRECT!
    +     * mySpecificWriter.doSomethingSpecific();
    +     * 
    + * + *
    +     * MySpecificWriter mySpecificWriter = (MySpecificWriter)writer.underlyingWriter();  // CORRECT!
    +     * mySpecificWriter.doSomethingSpecific();
    +     * 
    + *

    + * Implementations of HierarchicalStreamWriter should return 'this', unless they are a decorator, in which case they + * should delegate to whatever they are wrapping. + *

    */ HierarchicalStreamWriter underlyingWriter(); Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ReaderWrapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ReaderWrapper.java (.../ReaderWrapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/ReaderWrapper.java (.../ReaderWrapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,74 +1,103 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2011, 2014 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 10. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.io; +import java.util.Iterator; + import com.thoughtworks.xstream.converters.ErrorWriter; -import java.util.Iterator; /** * Base class to make it easy to create wrappers (decorators) for HierarchicalStreamReader. - * + * * @author Joe Walnes */ -public abstract class ReaderWrapper implements HierarchicalStreamReader { +public abstract class ReaderWrapper implements ExtendedHierarchicalStreamReader { protected HierarchicalStreamReader wrapped; - protected ReaderWrapper(HierarchicalStreamReader reader) { - this.wrapped = reader; + protected ReaderWrapper(final HierarchicalStreamReader reader) { + wrapped = reader; } + @Override public boolean hasMoreChildren() { return wrapped.hasMoreChildren(); } + @Override public void moveDown() { wrapped.moveDown(); } + @Override public void moveUp() { wrapped.moveUp(); } + @Override public String getNodeName() { return wrapped.getNodeName(); } + @Override public String getValue() { return wrapped.getValue(); } - public String getAttribute(String name) { + @Override + public String getAttribute(final String name) { return wrapped.getAttribute(name); } - public String getAttribute(int index) { + @Override + public String getAttribute(final int index) { return wrapped.getAttribute(index); } + @Override public int getAttributeCount() { return wrapped.getAttributeCount(); } - public String getAttributeName(int index) { + @Override + public String getAttributeName(final int index) { return wrapped.getAttributeName(index); } - public Iterator getAttributeNames() { + @Override + public Iterator getAttributeNames() { return wrapped.getAttributeNames(); } - public Object peekUnderlyingNode() { - return wrapped.peekUnderlyingNode(); - } - - public void appendErrors(ErrorWriter errorWriter) { + @Override + public void appendErrors(final ErrorWriter errorWriter) { wrapped.appendErrors(errorWriter); } + @Override public void close() { wrapped.close(); } + @Override + public String peekNextChild() { + if (!(wrapped instanceof ExtendedHierarchicalStreamReader)) { + throw new UnsupportedOperationException("peekNextChild"); + } + return ((ExtendedHierarchicalStreamReader)wrapped).peekNextChild(); + } + + @Override public HierarchicalStreamReader underlyingReader() { return wrapped.underlyingReader(); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/StatefulWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/StatefulWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/StatefulWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 15. March 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.io; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import com.thoughtworks.xstream.core.util.FastStack; + + +/** + * An wrapper for all {@link HierarchicalStreamWriter} implementations, that keeps the state. + *

    + * Writing in a wrong state will throw a {@link StreamException}, that wraps either an {@link IOException} (writing to a + * closed writer) or an {@link IllegalStateException}. The implementation will also track unbalanced nodes or multiple + * attributes with the same name. + *

    + * + * @author Jörg Schaible + * @since 1.2 + */ +public class StatefulWriter extends WriterWrapper { + + /** + * STATE_OPEN is the initial value of the writer. + * + * @since 1.2 + */ + public static int STATE_OPEN = 0; + /** + * STATE_NODE_START is the state of a new node has been started. + * + * @since 1.2 + */ + public static int STATE_NODE_START = 1; + /** + * STATE_VALUE is the state if the value of a node has been written. + * + * @since 1.2 + */ + public static int STATE_VALUE = 2; + /** + * STATE_NODE_END is the state if a node has ended + * + * @since 1.2 + */ + public static int STATE_NODE_END = 3; + /** + * STATE_CLOSED is the state if the writer has been closed. + * + * @since 1.2 + */ + public static int STATE_CLOSED = 4; + + private transient int state = STATE_OPEN; + private transient int balance; + private transient FastStack> attributes; + + /** + * Constructs a StatefulWriter. + * + * @param wrapped the wrapped writer + * @since 1.2 + */ + public StatefulWriter(final HierarchicalStreamWriter wrapped) { + super(wrapped); + attributes = new FastStack>(16); + } + + @Override + public void startNode(final String name) { + startNodeCommon(); + super.startNode(name); + } + + @Override + public void startNode(final String name, final Class clazz) { + startNodeCommon(); + super.startNode(name, clazz); + } + + private void startNodeCommon() { + checkClosed(); + if (state == STATE_VALUE) { + // legal XML, but not in XStream ... ? + throw new StreamException(new IllegalStateException("Opening node after writing text")); + } + state = STATE_NODE_START; + ++balance; + attributes.push(new HashSet()); + } + + @Override + public void addAttribute(final String name, final String value) { + checkClosed(); + if (state != STATE_NODE_START) { + throw new StreamException(new IllegalStateException("Writing attribute '" + + name + + "' without an opened node")); + } + final Set currentAttributes = attributes.peek(); + if (currentAttributes.contains(name)) { + throw new StreamException(new IllegalStateException("Writing attribute '" + name + "' twice")); + } + currentAttributes.add(name); + super.addAttribute(name, value); + } + + @Override + public void setValue(final String text) { + checkClosed(); + if (state != STATE_NODE_START) { + // STATE_NODE_END is legal XML, but not in XStream ... ? + throw new StreamException(new IllegalStateException("Writing text without an opened node")); + } + state = STATE_VALUE; + super.setValue(text); + } + + @Override + public void endNode() { + checkClosed(); + if (balance-- == 0) { + throw new StreamException(new IllegalStateException("Unbalanced node")); + } + attributes.popSilently(); + state = STATE_NODE_END; + super.endNode(); + } + + @Override + public void flush() { + checkClosed(); + super.flush(); + } + + @Override + public void close() { + if (state != STATE_NODE_END && state != STATE_OPEN) { + // calling close in a finally block should not throw again + // throw new StreamException(new IllegalStateException("Closing with unbalanced tag")); + } + state = STATE_CLOSED; + super.close(); + } + + private void checkClosed() { + if (state == STATE_CLOSED) { + throw new StreamException(new IOException("Writing on a closed stream")); + } + } + + /** + * Retrieve the state of the writer. + * + * @return one of the states + * @see #STATE_OPEN + * @see #STATE_NODE_START + * @see #STATE_VALUE + * @see #STATE_NODE_END + * @see #STATE_CLOSED + * @since 1.2 + */ + public int state() { + return state; + } + + private Object readResolve() { + attributes = new FastStack>(16); + return this; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/StreamException.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/StreamException.java (.../StreamException.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/StreamException.java (.../StreamException.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,9 +1,31 @@ +/* + * Copyright (C) 2004, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io; -import com.thoughtworks.xstream.core.BaseException; +import com.thoughtworks.xstream.XStreamException; -public class StreamException extends BaseException { +public class StreamException extends XStreamException { public StreamException(Throwable e) { super(e); } + + public StreamException(String message) { + super(message); + } + + /** + * @since 1.4 + */ + public StreamException(String message, Throwable cause) { + super(message, cause); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/WriterWrapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/WriterWrapper.java (.../WriterWrapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/WriterWrapper.java (.../WriterWrapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,42 +1,66 @@ +/* + * Copyright (C) 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 10. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.io; /** * Base class to make it easy to create wrappers (decorators) for HierarchicalStreamWriter. - * + * * @author Joe Walnes */ -public abstract class WriterWrapper implements HierarchicalStreamWriter { +public abstract class WriterWrapper implements ExtendedHierarchicalStreamWriter { protected HierarchicalStreamWriter wrapped; - protected WriterWrapper(HierarchicalStreamWriter wrapped) { + protected WriterWrapper(final HierarchicalStreamWriter wrapped) { this.wrapped = wrapped; } - public void startNode(String name) { + @Override + public void startNode(final String name) { wrapped.startNode(name); } + @Override + public void startNode(final String name, final Class clazz) { + + ((ExtendedHierarchicalStreamWriter)wrapped).startNode(name, clazz); + } + + @Override public void endNode() { wrapped.endNode(); } - public void addAttribute(String key, String value) { + @Override + public void addAttribute(final String key, final String value) { wrapped.addAttribute(key, value); } - public void setValue(String text) { + @Override + public void setValue(final String text) { wrapped.setValue(text); } + @Override public void flush() { wrapped.flush(); } + @Override public void close() { wrapped.close(); } + @Override public HierarchicalStreamWriter underlyingWriter() { return wrapped.underlyingWriter(); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/BinaryStreamDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/BinaryStreamDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/BinaryStreamDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011, 2014 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 14. October 2011 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.binary; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +import com.thoughtworks.xstream.io.AbstractDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * HierarchicalStreamDriver for binary input and output. The driver uses an optimized binary format to store an object + * graph. The format is not as compact as Java serialization, but a lot more than typical text-based formats like XML. + * However, due to its nature it cannot use a {@link Reader} for input or a {@link Writer} for output. + * + * @author Jörg Schaible + * @since 1.4.2 + */ +public class BinaryStreamDriver extends AbstractDriver { + + /** + * @throws UnsupportedOperationException if called + */ + @Override + public HierarchicalStreamReader createReader(final Reader in) { + throw new UnsupportedOperationException("The BinaryDriver cannot use character-oriented input streams."); + } + + @Override + public HierarchicalStreamReader createReader(final InputStream in) { + return new BinaryStreamReader(in); + } + + /** + * @throws UnsupportedOperationException if called + */ + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { + throw new UnsupportedOperationException("The BinaryDriver cannot use character-oriented output streams."); + } + + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { + return new BinaryStreamWriter(out); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2011, 2013, 2014 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 04. June 2006 by Joe Walnes + */ +package com.thoughtworks.xstream.io.binary; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.StreamException; + + +/** + * A HierarchicalStreamReader that reads from a binary stream created by {@link BinaryStreamWriter}. + * + * @author Joe Walnes + * @see BinaryStreamReader + * @since 1.2 + */ +public class BinaryStreamReader implements ExtendedHierarchicalStreamReader { + + private final DataInputStream in; + private final ReaderDepthState depthState = new ReaderDepthState(); + private final IdRegistry idRegistry = new IdRegistry(); + + private Token pushback; + private final Token.Formatter tokenFormatter = new Token.Formatter(); + + public BinaryStreamReader(final InputStream inputStream) { + in = new DataInputStream(inputStream); + moveDown(); + } + + @Override + public boolean hasMoreChildren() { + return depthState.hasMoreChildren(); + } + + @Override + public String getNodeName() { + return depthState.getName(); + } + + @Override + public String getValue() { + return depthState.getValue(); + } + + @Override + public String getAttribute(final String name) { + return depthState.getAttribute(name); + } + + @Override + public String getAttribute(final int index) { + return depthState.getAttribute(index); + } + + @Override + public int getAttributeCount() { + return depthState.getAttributeCount(); + } + + @Override + public String getAttributeName(final int index) { + return depthState.getAttributeName(index); + } + + @Override + public Iterator getAttributeNames() { + return depthState.getAttributeNames(); + } + + @Override + public void moveDown() { + depthState.push(); + final Token firstToken = readToken(); + switch (firstToken.getType()) { + case Token.TYPE_START_NODE: + depthState.setName(idRegistry.get(firstToken.getId())); + break; + default: + throw new StreamException("Expected StartNode"); + } + while (true) { + final Token nextToken = readToken(); + switch (nextToken.getType()) { + case Token.TYPE_ATTRIBUTE: + depthState.addAttribute(idRegistry.get(nextToken.getId()), nextToken.getValue()); + break; + case Token.TYPE_VALUE: + depthState.setValue(nextToken.getValue()); + break; + case Token.TYPE_END_NODE: + depthState.setHasMoreChildren(false); + pushBack(nextToken); + return; + case Token.TYPE_START_NODE: + depthState.setHasMoreChildren(true); + pushBack(nextToken); + return; + default: + throw new StreamException("Unexpected token " + nextToken); + } + } + } + + @Override + public void moveUp() { + depthState.pop(); + // We're done with this depth. Skip over all tokens until we get to the end. + int depth = 0; + slurp: + while (true) { + final Token nextToken = readToken(); + switch (nextToken.getType()) { + case Token.TYPE_END_NODE: + if (depth == 0) { + break slurp; + } else { + depth--; + } + break; + case Token.TYPE_START_NODE: + depth++; + break; + default: + // Ignore other tokens + } + } + // Peek ahead to determine if there are any more kids at this level. + final Token nextToken = readToken(); + switch (nextToken.getType()) { + case Token.TYPE_END_NODE: + depthState.setHasMoreChildren(false); + break; + case Token.TYPE_START_NODE: + depthState.setHasMoreChildren(true); + break; + default: + throw new StreamException("Unexpected token " + nextToken); + } + pushBack(nextToken); + } + + private Token readToken() { + if (pushback == null) { + try { + final Token token = tokenFormatter.read(in); + switch (token.getType()) { + case Token.TYPE_MAP_ID_TO_VALUE: + idRegistry.put(token.getId(), token.getValue()); + return readToken(); // Next one please. + default: + return token; + } + } catch (final IOException e) { + throw new StreamException(e); + } + } else { + final Token result = pushback; + pushback = null; + return result; + } + } + + public void pushBack(final Token token) { + if (pushback == null) { + pushback = token; + } else { + // If this happens, I've messed up :( -joe. + throw new Error("Cannot push more than one token back"); + } + } + + @Override + public void close() { + try { + in.close(); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public String peekNextChild() { + if (depthState.hasMoreChildren()) { + return idRegistry.get(pushback.getId()); + } + return null; + } + + @Override + public HierarchicalStreamReader underlyingReader() { + return this; + } + + @Override + public void appendErrors(final ErrorWriter errorWriter) { + // TODO: When things go bad, it would be good to know where! + } + + private static class IdRegistry { + + private final Map map = new HashMap(); + + public void put(final long id, final String value) { + map.put(Long.valueOf(id), value); + } + + public String get(final long id) { + final String result = map.get(Long.valueOf(id)); + if (result == null) { + throw new StreamException("Unknown ID : " + id); + } else { + return result; + } + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/BinaryStreamWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/BinaryStreamWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/BinaryStreamWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 04. June 2006 by Joe Walnes + */ +package com.thoughtworks.xstream.io.binary; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; + +import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; + + +/** + * @since 1.2 + */ +public class BinaryStreamWriter implements ExtendedHierarchicalStreamWriter { + + private final IdRegistry idRegistry = new IdRegistry(); + private final DataOutputStream out; + private final Token.Formatter tokenFormatter = new Token.Formatter(); + + public BinaryStreamWriter(final OutputStream outputStream) { + out = new DataOutputStream(outputStream); + } + + @Override + public void startNode(final String name) { + write(new Token.StartNode(idRegistry.getId(name))); + } + + @Override + public void startNode(final String name, final Class clazz) { + startNode(name); + } + + @Override + public void addAttribute(final String name, final String value) { + write(new Token.Attribute(idRegistry.getId(name), value)); + } + + @Override + public void setValue(final String text) { + write(new Token.Value(text)); + } + + @Override + public void endNode() { + write(new Token.EndNode()); + } + + @Override + public void flush() { + try { + out.flush(); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public void close() { + try { + out.close(); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamWriter underlyingWriter() { + return this; + } + + private void write(final Token token) { + try { + tokenFormatter.write(out, token); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + private class IdRegistry { + + private long nextId = 0; + private final Map ids = new HashMap(); + + public long getId(final String value) { + Long id = ids.get(value); + if (id == null) { + id = Long.valueOf(++nextId); + ids.put(value, id); + write(new Token.MapIdToValue(id.longValue(), value)); + } + return id.longValue(); + } + + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/ReaderDepthState.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/ReaderDepthState.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/ReaderDepthState.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 04. June 2006 by Joe Walnes + */ +package com.thoughtworks.xstream.io.binary; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + + +/** + * Maintains the state of a pull reader at various states in the document depth. Used by the {@link BinaryStreamReader} + * + * @author Joe Walnes + * @since 1.2 + */ +class ReaderDepthState { + + private static final String EMPTY_STRING = ""; + + private static class State { + String name; + String value; + List attributes; + boolean hasMoreChildren; + State parent; + } + + private static class Attribute { + String name; + String value; + } + + private State current; + + public void push() { + final State newState = new State(); + newState.parent = current; + current = newState; + } + + public void pop() { + current = current.parent; + } + + public String getName() { + return current.name; + } + + public void setName(final String name) { + current.name = name; + } + + public String getValue() { + return current.value == null ? EMPTY_STRING : current.value; + } + + public void setValue(final String value) { + current.value = value; + } + + public boolean hasMoreChildren() { + return current.hasMoreChildren; + } + + public void setHasMoreChildren(final boolean hasMoreChildren) { + current.hasMoreChildren = hasMoreChildren; + } + + public void addAttribute(final String name, final String value) { + final Attribute attribute = new Attribute(); + attribute.name = name; + attribute.value = value; + if (current.attributes == null) { + current.attributes = new ArrayList(); + } + current.attributes.add(attribute); + } + + public String getAttribute(final String name) { + if (current.attributes == null) { + return null; + } else { + // For short maps, it's faster to iterate then do a hashlookup. + for (final Attribute attribute : current.attributes) { + if (attribute.name.equals(name)) { + return attribute.value; + } + } + return null; + } + } + + public String getAttribute(final int index) { + if (current.attributes == null) { + return null; + } else { + final Attribute attribute = current.attributes.get(index); + return attribute.value; + } + } + + public String getAttributeName(final int index) { + if (current.attributes == null) { + return null; + } else { + final Attribute attribute = current.attributes.get(index); + return attribute.name; + } + } + + public int getAttributeCount() { + return current.attributes == null ? 0 : current.attributes.size(); + } + + public Iterator getAttributeNames() { + if (current.attributes == null) { + return Collections.emptySet().iterator(); + } else { + final Iterator attributeIterator = current.attributes.iterator(); + return new Iterator() { + @Override + public boolean hasNext() { + return attributeIterator.hasNext(); + } + + @Override + public String next() { + final Attribute attribute = attributeIterator.next(); + return attribute.name; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/Token.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/Token.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/binary/Token.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2013, 2014 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 04. June 2006 by Joe Walnes + */ +package com.thoughtworks.xstream.io.binary; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import com.thoughtworks.xstream.io.StreamException; + + +/** + * Represents the Tokens stored in the binary stream used by {@link BinaryStreamReader} and {@link BinaryStreamWriter}. + *

    + * A token consists of a type and (depending on this type) it may additionally have an ID (positive long number) and/or + * a value (String). + *

    + *

    + * The first byte of the token represents how many subsequent bytes are used by the ID. + *

    + * + * @author Joe Walnes + * @see BinaryStreamReader + * @see BinaryStreamWriter + * @since 1.2 + */ +public abstract class Token { + + private static final byte TYPE_MASK = 0x7; + public static final byte TYPE_VERSION = 0x1; + public static final byte TYPE_MAP_ID_TO_VALUE = 0x2; + public static final byte TYPE_START_NODE = 0x3; + public static final byte TYPE_END_NODE = 0x4; + public static final byte TYPE_ATTRIBUTE = 0x5; + public static final byte TYPE_VALUE = 0x6; + + private static final byte ID_MASK = 0x38; + private static final byte ID_ONE_BYTE = 0x08; + private static final byte ID_TWO_BYTES = 0x10; + private static final byte ID_FOUR_BYTES = 0x18; + private static final byte ID_EIGHT_BYTES = 0x20; + + private static final String ID_SPLITTED = "\u0000\u2021\u0000"; + private static final int MAX_UTF8_LENGTH = 0xffff; + + private final byte type; + + protected long id = -1; + protected String value; + + public Token(final byte type) { + this.type = type; + } + + public byte getType() { + return type; + } + + public long getId() { + return id; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return getClass().getName() + " [id=" + id + ", value='" + value + "']"; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final Token token = (Token)o; + + if (id != token.id) { + return false; + } + if (type != token.type) { + return false; + } + return !(value != null ? !value.equals(token.value) : token.value != null); + } + + @Override + public int hashCode() { + int result; + result = type; + result = 29 * result + (int)(id ^ id >>> 32); + result = 29 * result + (value != null ? value.hashCode() : 0); + return result; + } + + public abstract void writeTo(DataOutput out, byte idType) throws IOException; + + public abstract void readFrom(DataInput in, byte idType) throws IOException; + + protected void writeId(final DataOutput out, final long id, final byte idType) throws IOException { + if (id < 0) { + throw new IOException("id must not be negative " + id); + } + switch (idType) { + case ID_ONE_BYTE: + out.writeByte((byte)id + Byte.MIN_VALUE); + break; + case ID_TWO_BYTES: + out.writeShort((short)id + Short.MIN_VALUE); + break; + case ID_FOUR_BYTES: + out.writeInt((int)id + Integer.MIN_VALUE); + break; + case ID_EIGHT_BYTES: + out.writeLong(id + Long.MIN_VALUE); + break; + default: + throw new Error("Unknown idType " + idType); + } + } + + protected void writeString(final DataOutput out, final String string) throws IOException { + final byte[] bytes = string.length() > MAX_UTF8_LENGTH / 4 ? string.getBytes("utf-8") : new byte[0]; + final int length = bytes.length; + if (length <= MAX_UTF8_LENGTH) { + out.writeUTF(string); + } else { + out.writeUTF(ID_SPLITTED); + out.writeInt(bytes.length); + out.write(bytes); + } + } + + protected long readId(final DataInput in, final byte idType) throws IOException { + switch (idType) { + case ID_ONE_BYTE: + return in.readByte() - Byte.MIN_VALUE; + case ID_TWO_BYTES: + return in.readShort() - Short.MIN_VALUE; + case ID_FOUR_BYTES: + return in.readInt() - Integer.MIN_VALUE; + case ID_EIGHT_BYTES: + return in.readLong() - Long.MIN_VALUE; + default: + throw new Error("Unknown idType " + idType); + } + } + + protected String readString(final DataInput in) throws IOException { + final String string = in.readUTF(); + if (!ID_SPLITTED.equals(string)) { + return string; + } + final int size = in.readInt(); + final byte[] bytes = new byte[size]; + in.readFully(bytes); + return new String(bytes, "utf-8"); + } + + public static class Formatter { + + public void write(final DataOutput out, final Token token) throws IOException { + final long id = token.getId(); + byte idType; + if (id <= Byte.MAX_VALUE - Byte.MIN_VALUE) { + idType = ID_ONE_BYTE; + } else if (id <= Short.MAX_VALUE - Short.MIN_VALUE) { + idType = ID_TWO_BYTES; + } else if (id <= (long)Integer.MAX_VALUE - (long)Integer.MIN_VALUE) { // cast to long to prevent overflow + idType = ID_FOUR_BYTES; + } else { + idType = ID_EIGHT_BYTES; + } + out.write(token.getType() + idType); + token.writeTo(out, idType); + } + + public Token read(final DataInput in) throws IOException { + final byte nextByte = in.readByte(); + final byte type = (byte)(nextByte & TYPE_MASK); + final byte idType = (byte)(nextByte & ID_MASK); + final Token token = contructToken(type); + token.readFrom(in, idType); + return token; + } + + private Token contructToken(final byte type) { + switch (type) { + case Token.TYPE_START_NODE: + return new StartNode(); + case Token.TYPE_MAP_ID_TO_VALUE: + return new MapIdToValue(); + case Token.TYPE_ATTRIBUTE: + return new Attribute(); + case Token.TYPE_END_NODE: + return new EndNode(); + case Token.TYPE_VALUE: + return new Value(); + default: + throw new StreamException("Unknown token type"); + } + } + } + + public static class MapIdToValue extends Token { + + public MapIdToValue(final long id, final String value) { + super(TYPE_MAP_ID_TO_VALUE); + this.id = id; + this.value = value; + } + + public MapIdToValue() { + super(TYPE_MAP_ID_TO_VALUE); + } + + @Override + public void writeTo(final DataOutput out, final byte idType) throws IOException { + writeId(out, id, idType); + writeString(out, value); + } + + @Override + public void readFrom(final DataInput in, final byte idType) throws IOException { + id = readId(in, idType); + value = readString(in); + } + + } + + public static class StartNode extends Token { + + public StartNode(final long id) { + super(TYPE_START_NODE); + this.id = id; + } + + public StartNode() { + super(TYPE_START_NODE); + } + + @Override + public void writeTo(final DataOutput out, final byte idType) throws IOException { + writeId(out, id, idType); + } + + @Override + public void readFrom(final DataInput in, final byte idType) throws IOException { + id = readId(in, idType); + } + + } + + public static class EndNode extends Token { + + public EndNode() { + super(TYPE_END_NODE); + } + + @Override + public void writeTo(final DataOutput out, final byte idType) { + } + + @Override + public void readFrom(final DataInput in, final byte idType) { + } + + } + + public static class Attribute extends Token { + + public Attribute(final long id, final String value) { + super(TYPE_ATTRIBUTE); + this.id = id; + this.value = value; + } + + public Attribute() { + super(TYPE_ATTRIBUTE); + } + + @Override + public void writeTo(final DataOutput out, final byte idType) throws IOException { + writeId(out, id, idType); + writeString(out, value); + } + + @Override + public void readFrom(final DataInput in, final byte idType) throws IOException { + id = readId(in, idType); + value = readString(in); + } + + } + + public static class Value extends Token { + + public Value(final String value) { + super(TYPE_VALUE); + this.value = value; + } + + public Value() { + super(TYPE_VALUE); + } + + @Override + public void writeTo(final DataOutput out, final byte idType) throws IOException { + writeString(out, value); + } + + @Override + public void readFrom(final DataInput in, final byte idType) throws IOException { + value = readString(in); + } + + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/copy/HierarchicalStreamCopier.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/copy/HierarchicalStreamCopier.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/copy/HierarchicalStreamCopier.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2013 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 04. June 2006 by Joe Walnes + */ +package com.thoughtworks.xstream.io.copy; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * Tool for copying the contents of one HierarichalStreamReader to a HierarichalStreamWriter. + *

    + * This is useful for transforming the output of one format to another (e.g. binary to XML) + * without needing to know details about the classes and avoiding the overhead of serialization.

    + * + *

    Example

    + *
    + * HierarchicalStreamReader reader = new BinaryStreamReader(someBinaryInput);
    + * HierarchicalStreamWriter writer = new PrettyPrintWriter(someXmlOutput);
    + * HierarchicalStreamCopier copier = new HierarchicalStreamCopier();
    + * copier.copy(reader, writer);
    + * 
    + * + * @author Joe Walnes + * @since 1.2 + */ +public class HierarchicalStreamCopier { + public void copy(HierarchicalStreamReader source, HierarchicalStreamWriter destination) { + destination.startNode(source.getNodeName()); + int attributeCount = source.getAttributeCount(); + for (int i = 0; i < attributeCount; i++) { + destination.addAttribute(source.getAttributeName(i), source.getAttribute(i)); + } + String value = source.getValue(); + if (value != null && value.length() > 0) { + destination.setValue(value); + } + while (source.hasMoreChildren()) { + source.moveDown(); + copy(source, destination); + source.moveUp(); + } + destination.endNode(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/AbstractJsonWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/AbstractJsonWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/AbstractJsonWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,677 @@ +/* + * Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 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 20. August 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.json; + +import java.io.Externalizable; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.io.AbstractWriter; +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * An abstract implementation of a writer that calls abstract methods to build JSON structures. Note, that XStream's + * implicit collection feature is only compatible with the syntax in {@link #EXPLICIT_MODE}. + * + * @author Jörg Schaible + * @since 1.4 + */ +public abstract class AbstractJsonWriter extends AbstractWriter { + /** + * DROP_ROOT_MODE drops the JSON root node. + *

    + * The root node is the first level of the JSON object i.e. + *

    + * + *
    +     * { "person": {
    +     *     "name": "Joe"
    +     * }}
    +     * 
    + *

    + * will be written without root simply as + *

    + * + *
    +     * {
    +     *     "name": "Joe"
    +     * }
    +     * 
    + *

    + * Without a root node, the top level element might now also be an array. However, it is possible to generate + * invalid JSON unless {@link #STRICT_MODE} is also set. + *

    + * + * @since 1.3.1 + */ + public static final int DROP_ROOT_MODE = 1; + /** + * STRICT_MODE prevents invalid JSON for single value objects when dropping the root. + *

    + * The mode is only useful in combination with the {@link #DROP_ROOT_MODE}. An object with a single value as first + * node i.e. + *

    + * + *
    +     * { "name": "Joe" }
    +     * 
    + *

    + * is simply written as + *

    + * + *
    +     * "Joe"
    +     * 
    + *

    + * However, this is no longer valid JSON. Therefore you can activate {@link #STRICT_MODE} and a + * {@link ConversionException} is thrown instead. + *

    + * + * @since 1.3.1 + */ + public static final int STRICT_MODE = 2; + /** + * EXPLICIT_MODE assures that all data has its explicit equivalent in the resulting JSON. + *

    + * XStream is normally using attributes in XML that have no real equivalent in JSON. Additionally it is essential in + * XML that the individual child elements of a tag keep order and may have the same tag name. XStream's model relies + * on both characteristics. However, properties of a JSON object do not have a defined order, but their names have + * to be unique. Only a JSON array defines the order of its elements. + *

    + *

    + * Therefore XStream uses in explicit mode a JSON format that supports the original requirements at the expense of + * the simplicity of the JSON objects and arrays. Each Java object will be represented by a JSON object with a + * single property representing the name of the object and an array as value that contains two more arrays. The + * first one contains a JSON object with all attributes, the second one the value of the Java object which can be + * null, a string or integer value or again a new JSON object representing a Java object. Here an example of an + * string array with one member, where the array and the string has an additional attribute 'id': + *

    + * + *
    +     * {"string-array":[[{"id":"1"}],[{"string":[[{"id":"2"}],["Joe"]]}]]}
    +     * 
    + *

    + * This format can be used to always deserialize into Java again. + *

    + *

    + * This mode cannot combined with {@link #STRICT_MODE} or {@link #DROP_ROOT_MODE}. + *

    + * + * @since 1.4 + */ + public static final int EXPLICIT_MODE = 4; + /** + * IEEE_754_MODE keeps precision of 64-bit integer values. + *

    + * In JavaScript every number is expressed as 64-bit double value with a precision of 53 bits following IEEE 754. + * Therefore it is not possible to represent the complete value range of 64-bit integer values. Any integer value + * > 253 (9007199254740992) or < -253 (-9007199254740992) will therefore be written as + * string value. + *

    + *

    + * CAUTION: A client must be aware that the element may contain a number or a string value. + *

    + * + * @since 1.4.5 + * @see ECMA Specification: The Number Type + */ + public static final int IEEE_754_MODE = 8; + + public static class Type { + public static Type NULL = new Type(); + public static Type STRING = new Type(); + public static Type NUMBER = new Type(); + public static Type BOOLEAN = new Type(); + } + + private static class StackElement { + final Class type; + int status; + + public StackElement(final Class type, final int status) { + this.type = type; + this.status = status; + } + } + + private static class IllegalWriterStateException extends IllegalStateException { + public IllegalWriterStateException(final int from, final int to, final String element) { + super("Cannot turn from state " + + getState(from) + + " into state " + + getState(to) + + (element == null ? "" : " for property " + element)); + } + + private static String getState(final int state) { + switch (state) { + case STATE_ROOT: + return "ROOT"; + case STATE_END_OBJECT: + return "END_OBJECT"; + case STATE_START_OBJECT: + return "START_OBJECT"; + case STATE_START_ATTRIBUTES: + return "START_ATTRIBUTES"; + case STATE_NEXT_ATTRIBUTE: + return "NEXT_ATTRIBUTE"; + case STATE_END_ATTRIBUTES: + return "END_ATTRIBUTES"; + case STATE_START_ELEMENTS: + return "START_ELEMENTS"; + case STATE_NEXT_ELEMENT: + return "NEXT_ELEMENT"; + case STATE_END_ELEMENTS: + return "END_ELEMENTS"; + case STATE_SET_VALUE: + return "SET_VALUE"; + default: + throw new IllegalArgumentException("Unknown state provided: " + + state + + ", cannot create message for IllegalWriterStateException"); + } + } + } + + private static final int STATE_ROOT = 1 << 0; + private static final int STATE_END_OBJECT = 1 << 1; + private static final int STATE_START_OBJECT = 1 << 2; + private static final int STATE_START_ATTRIBUTES = 1 << 3; + private static final int STATE_NEXT_ATTRIBUTE = 1 << 4; + private static final int STATE_END_ATTRIBUTES = 1 << 5; + private static final int STATE_START_ELEMENTS = 1 << 6; + private static final int STATE_NEXT_ELEMENT = 1 << 7; + private static final int STATE_END_ELEMENTS = 1 << 8; + private static final int STATE_SET_VALUE = 1 << 9; + + private static final Set> NUMBER_TYPES = new HashSet>(Arrays.>asList(byte.class, + Byte.class, short.class, Short.class, int.class, Integer.class, long.class, Long.class, float.class, + Float.class, double.class, Double.class, BigInteger.class, BigDecimal.class)); + private final int mode; + private final FastStack stack = new FastStack(16); + private int expectedStates; + + /** + * Construct a JSON writer. + * + * @since 1.4 + */ + public AbstractJsonWriter() { + this(new NoNameCoder()); + } + + /** + * Construct a JSON writer with a special mode. + * + * @param mode a bit mask of the mode constants + * @since 1.4 + */ + public AbstractJsonWriter(final int mode) { + this(mode, new NoNameCoder()); + } + + /** + * Construct a JSON writer with a special name coder. + * + * @param nameCoder the name coder to use + * @since 1.4 + */ + public AbstractJsonWriter(final NameCoder nameCoder) { + this(0, nameCoder); + } + + /** + * Construct a JSON writer with a special mode and name coder. + * + * @param mode a bit mask of the mode constants + * @param nameCoder the name coder to use + * @since 1.4 + */ + public AbstractJsonWriter(final int mode, final NameCoder nameCoder) { + super(nameCoder); + this.mode = (mode & EXPLICIT_MODE) > 0 ? EXPLICIT_MODE : mode; + stack.push(new StackElement(null, STATE_ROOT)); + expectedStates = STATE_START_OBJECT; + } + + @Override + public void startNode(final String name, final Class clazz) { + if (name == null) { + throw new NullPointerException("name"); + } + stack.push(new StackElement(clazz, stack.peek().status)); + handleCheckedStateTransition(STATE_START_OBJECT, name, null); + expectedStates = STATE_SET_VALUE | STATE_NEXT_ATTRIBUTE | STATE_START_OBJECT | STATE_NEXT_ELEMENT | STATE_ROOT; + } + + @Override + public void startNode(final String name) { + startNode(name, null); + } + + @Override + public void addAttribute(final String name, final String value) { + handleCheckedStateTransition(STATE_NEXT_ATTRIBUTE, name, value); + expectedStates = STATE_SET_VALUE | STATE_NEXT_ATTRIBUTE | STATE_START_OBJECT | STATE_NEXT_ELEMENT | STATE_ROOT; + } + + @Override + public void setValue(String text) { + final Class type = stack.peek().type; + if ((type == Character.class || type == Character.TYPE) && "".equals(text)) { + text = "\u0000"; + } + handleCheckedStateTransition(STATE_SET_VALUE, null, text); + expectedStates = STATE_NEXT_ELEMENT | STATE_ROOT; + } + + @Override + public void endNode() { + final int size = stack.size(); + final int nextState = size > 2 ? STATE_NEXT_ELEMENT : STATE_ROOT; + handleCheckedStateTransition(nextState, null, null); + stack.pop(); + stack.peek().status = nextState; + expectedStates = STATE_START_OBJECT; + if (size > 2) { + expectedStates |= STATE_NEXT_ELEMENT | STATE_ROOT; + } + } + + private void handleCheckedStateTransition(final int requiredState, final String elementToAdd, + final String valueToAdd) { + final StackElement stackElement = stack.peek(); + if ((expectedStates & requiredState) == 0) { + throw new IllegalWriterStateException(stackElement.status, requiredState, elementToAdd); + } + final int currentState = handleStateTransition(stackElement.status, requiredState, elementToAdd, valueToAdd); + stackElement.status = currentState; + } + + private int handleStateTransition(int currentState, final int requiredState, final String elementToAdd, + final String valueToAdd) { + final int size = stack.size(); + final Class currentType = stack.peek().type; + final boolean isArray = size > 1 && isArray(currentType); + final boolean isArrayElement = size > 1 && isArray(stack.get(size - 2).type); + switch (currentState) { + case STATE_ROOT: + if (requiredState == STATE_START_OBJECT) { + currentState = handleStateTransition(STATE_START_ELEMENTS, STATE_START_OBJECT, elementToAdd, null); + return requiredState; + } + throw new IllegalWriterStateException(currentState, requiredState, elementToAdd); + + case STATE_END_OBJECT: + switch (requiredState) { + case STATE_START_OBJECT: + currentState = handleStateTransition(currentState, STATE_NEXT_ELEMENT, null, null); + currentState = handleStateTransition(currentState, STATE_START_OBJECT, elementToAdd, null); + return requiredState; + case STATE_NEXT_ELEMENT: + nextElement(); + return requiredState; + case STATE_ROOT: + if (((mode & DROP_ROOT_MODE) == 0 || size > 2) && (mode & EXPLICIT_MODE) == 0) { + endObject(); + } + return requiredState; + default: + throw new IllegalWriterStateException(currentState, requiredState, elementToAdd); + } + + case STATE_START_OBJECT: + switch (requiredState) { + case STATE_SET_VALUE: + case STATE_START_OBJECT: + case STATE_ROOT: + case STATE_NEXT_ELEMENT: + if (!isArrayElement || (mode & EXPLICIT_MODE) != 0) { + currentState = handleStateTransition(currentState, STATE_START_ATTRIBUTES, null, null); + currentState = handleStateTransition(currentState, STATE_END_ATTRIBUTES, null, null); + } + currentState = STATE_START_ELEMENTS; + + switch (requiredState) { + case STATE_SET_VALUE: + currentState = handleStateTransition(currentState, STATE_SET_VALUE, null, valueToAdd); + break; + case STATE_START_OBJECT: + currentState = handleStateTransition(currentState, STATE_START_OBJECT, elementToAdd, null); + break; + case STATE_ROOT: + case STATE_NEXT_ELEMENT: + currentState = handleStateTransition(currentState, STATE_SET_VALUE, null, null); + currentState = handleStateTransition(currentState, requiredState, null, null); + break; + } + return requiredState; + case STATE_START_ATTRIBUTES: + if ((mode & EXPLICIT_MODE) != 0) { + startArray(); + } + return requiredState; + case STATE_NEXT_ATTRIBUTE: + if ((mode & EXPLICIT_MODE) != 0 || !isArray) { + currentState = handleStateTransition(currentState, STATE_START_ATTRIBUTES, null, null); + currentState = handleStateTransition(currentState, STATE_NEXT_ATTRIBUTE, elementToAdd, valueToAdd); + return requiredState; + } else { + return STATE_START_OBJECT; + } + default: + throw new IllegalWriterStateException(currentState, requiredState, elementToAdd); + } + + case STATE_NEXT_ELEMENT: + switch (requiredState) { + case STATE_START_OBJECT: + nextElement(); + if (!isArrayElement && (mode & EXPLICIT_MODE) == 0) { + addLabel(encodeNode(elementToAdd)); + if ((mode & EXPLICIT_MODE) == 0 && isArray) { + startArray(); + } + return requiredState; + } + break; + case STATE_ROOT: + currentState = handleStateTransition(currentState, STATE_END_OBJECT, null, null); + currentState = handleStateTransition(currentState, STATE_ROOT, null, null); + return requiredState; + case STATE_NEXT_ELEMENT: + case STATE_END_OBJECT: + currentState = handleStateTransition(currentState, STATE_END_ELEMENTS, null, null); + currentState = handleStateTransition(currentState, STATE_END_OBJECT, null, null); + if ((mode & EXPLICIT_MODE) == 0 && !isArray) { + endObject(); + } + return requiredState; + case STATE_END_ELEMENTS: + if ((mode & EXPLICIT_MODE) == 0 && isArray) { + endArray(); + } + return requiredState; + default: + throw new IllegalWriterStateException(currentState, requiredState, elementToAdd); + } + //$FALL-THROUGH$ + case STATE_START_ELEMENTS: + switch (requiredState) { + case STATE_START_OBJECT: + if ((mode & DROP_ROOT_MODE) == 0 || size > 2) { + if (!isArrayElement || (mode & EXPLICIT_MODE) != 0) { + if (!"".equals(valueToAdd)) { + startObject(); + } + addLabel(encodeNode(elementToAdd)); + } + if ((mode & EXPLICIT_MODE) != 0) { + startArray(); + } + } + if ((mode & EXPLICIT_MODE) == 0) { + if (isArray) { + startArray(); + } + } + return requiredState; + case STATE_SET_VALUE: + if ((mode & STRICT_MODE) != 0 && size == 2) { + throw new ConversionException("Single value cannot be root element"); + } + if (valueToAdd == null) { + if (currentType == Mapper.Null.class) { + addValue("null", Type.NULL); + } else if ((mode & EXPLICIT_MODE) == 0 && !isArray) { + startObject(); + endObject(); + } + } else { + if ((mode & IEEE_754_MODE) != 0 && (currentType == long.class || currentType == Long.class)) { + final long longValue = Long.parseLong(valueToAdd); + // JavaScript supports a maximum of 2^53 + if (longValue > 9007199254740992L || longValue < -9007199254740992L) { + addValue(valueToAdd, Type.STRING); + } else { + addValue(valueToAdd, getType(currentType)); + } + } else { + addValue(valueToAdd, getType(currentType)); + } + } + return requiredState; + case STATE_END_ELEMENTS: + case STATE_NEXT_ELEMENT: + if ((mode & EXPLICIT_MODE) == 0) { + if (isArray) { + endArray(); + } else { + endObject(); + } + } + return requiredState; + default: + throw new IllegalWriterStateException(currentState, requiredState, elementToAdd); + } + + case STATE_END_ELEMENTS: + switch (requiredState) { + case STATE_END_OBJECT: + if ((mode & EXPLICIT_MODE) != 0) { + endArray(); + endArray(); + endObject(); + } + return requiredState; + default: + throw new IllegalWriterStateException(currentState, requiredState, elementToAdd); + } + + case STATE_START_ATTRIBUTES: + switch (requiredState) { + case STATE_NEXT_ATTRIBUTE: + if (elementToAdd != null) { + final String name = ((mode & EXPLICIT_MODE) == 0 ? "@" : "") + elementToAdd; + startObject(); + addLabel(encodeAttribute(name)); + addValue(valueToAdd, Type.STRING); + } + return requiredState; + } + //$FALL-THROUGH$ + case STATE_NEXT_ATTRIBUTE: + switch (requiredState) { + case STATE_END_ATTRIBUTES: + if ((mode & EXPLICIT_MODE) != 0) { + if (currentState == STATE_NEXT_ATTRIBUTE) { + endObject(); + } + endArray(); + nextElement(); + startArray(); + } + return requiredState; + case STATE_NEXT_ATTRIBUTE: + if (!isArray || (mode & EXPLICIT_MODE) != 0) { + nextElement(); + final String name = ((mode & EXPLICIT_MODE) == 0 ? "@" : "") + elementToAdd; + addLabel(encodeAttribute(name)); + addValue(valueToAdd, Type.STRING); + } + return requiredState; + case STATE_SET_VALUE: + case STATE_START_OBJECT: + currentState = handleStateTransition(currentState, STATE_END_ATTRIBUTES, null, null); + currentState = handleStateTransition(currentState, STATE_START_ELEMENTS, null, null); + switch (requiredState) { + case STATE_SET_VALUE: + if ((mode & EXPLICIT_MODE) == 0) { + addLabel(encodeNode("$")); + } + currentState = handleStateTransition(currentState, STATE_SET_VALUE, null, valueToAdd); + if ((mode & EXPLICIT_MODE) == 0) { + endObject(); + } + break; + case STATE_START_OBJECT: + currentState = handleStateTransition(currentState, STATE_START_OBJECT, elementToAdd, + (mode & EXPLICIT_MODE) == 0 ? "" : null); + break; + case STATE_END_OBJECT: + currentState = handleStateTransition(currentState, STATE_SET_VALUE, null, null); + currentState = handleStateTransition(currentState, STATE_END_OBJECT, null, null); + break; + } + return requiredState; + case STATE_NEXT_ELEMENT: + currentState = handleStateTransition(currentState, STATE_END_ATTRIBUTES, null, null); + currentState = handleStateTransition(currentState, STATE_END_OBJECT, null, null); + return requiredState; + case STATE_ROOT: + currentState = handleStateTransition(currentState, STATE_END_ATTRIBUTES, null, null); + currentState = handleStateTransition(currentState, STATE_END_OBJECT, null, null); + currentState = handleStateTransition(currentState, STATE_ROOT, null, null); + return requiredState; + default: + throw new IllegalWriterStateException(currentState, requiredState, elementToAdd); + } + + case STATE_END_ATTRIBUTES: + switch (requiredState) { + case STATE_START_ELEMENTS: + if ((mode & EXPLICIT_MODE) == 0) { + nextElement(); + } + break; + case STATE_END_OBJECT: + currentState = handleStateTransition(STATE_START_ELEMENTS, STATE_END_ELEMENTS, null, null); + currentState = handleStateTransition(currentState, STATE_END_OBJECT, null, null); + break; + default: + throw new IllegalWriterStateException(currentState, requiredState, elementToAdd); + } + return requiredState; + + case STATE_SET_VALUE: + switch (requiredState) { + case STATE_END_ELEMENTS: + if ((mode & EXPLICIT_MODE) == 0 && isArray) { + endArray(); + } + return requiredState; + case STATE_NEXT_ELEMENT: + currentState = handleStateTransition(currentState, STATE_END_ELEMENTS, null, null); + currentState = handleStateTransition(currentState, STATE_END_OBJECT, null, null); + return requiredState; + case STATE_ROOT: + currentState = handleStateTransition(currentState, STATE_END_ELEMENTS, null, null); + currentState = handleStateTransition(currentState, STATE_END_OBJECT, null, null); + currentState = handleStateTransition(currentState, STATE_ROOT, null, null); + return requiredState; + default: + throw new IllegalWriterStateException(currentState, requiredState, elementToAdd); + } + } + + throw new IllegalWriterStateException(currentState, requiredState, elementToAdd); + } + + /** + * Method to return the appropriate JSON type for a Java type. + * + * @param clazz the type + * @return One of the {@link Type} instances + * @since 1.4.4 + */ + protected Type getType(final Class clazz) { + return clazz == Mapper.Null.class ? Type.NULL : clazz == Boolean.class || clazz == Boolean.TYPE + ? Type.BOOLEAN + : NUMBER_TYPES.contains(clazz) ? Type.NUMBER : Type.STRING; + } + + /** + * Method to declare various Java types to be handles as JSON array. + * + * @param clazz the type + * @return true if handles as array + * @since 1.4 + */ + protected boolean isArray(final Class clazz) { + return clazz != null + && (clazz.isArray() + || Collection.class.isAssignableFrom(clazz) + || Externalizable.class.isAssignableFrom(clazz) + || Map.class.isAssignableFrom(clazz) || Map.Entry.class.isAssignableFrom(clazz)); + } + + /** + * Start a JSON object. + * + * @since 1.4 + */ + protected abstract void startObject(); + + /** + * Add a label to a JSON object. + * + * @param name the label's name + * @since 1.4 + */ + protected abstract void addLabel(String name); + + /** + * Add a value to a JSON object's label or to an array. + * + * @param value the value itself + * @param type the JSON type + * @since 1.4 + */ + protected abstract void addValue(String value, Type type); + + /** + * Start a JSON array. + * + * @since 1.4 + */ + protected abstract void startArray(); + + /** + * Prepare a JSON object or array for another element. + * + * @since 1.4 + */ + protected abstract void nextElement(); + + /** + * End the JSON array. + * + * @since 1.4 + */ + protected abstract void endArray(); + + /** + * End the JSON object. + * + * @since 1.4 + */ + protected abstract void endObject(); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, 2014 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 30. March 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.json; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; + +import javax.xml.stream.XMLStreamException; + +import org.codehaus.jettison.mapped.Configuration; +import org.codehaus.jettison.mapped.MappedNamespaceConvention; +import org.codehaus.jettison.mapped.MappedXMLInputFactory; +import org.codehaus.jettison.mapped.MappedXMLOutputFactory; + +import com.thoughtworks.xstream.io.AbstractDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.xml.QNameMap; +import com.thoughtworks.xstream.io.xml.StaxReader; +import com.thoughtworks.xstream.io.xml.StaxWriter; + + +/** + * Simple XStream driver wrapping Jettison's Mapped reader and writer. Serializes object from and to JSON. + * + * @author Dejan Bosanac + */ +public class JettisonMappedXmlDriver extends AbstractDriver { + + protected final MappedXMLOutputFactory mof; + protected final MappedXMLInputFactory mif; + protected final MappedNamespaceConvention convention; + protected final boolean useSerializeAsArray; + + /** + * Construct a JettisonMappedXmlDriver. + */ + public JettisonMappedXmlDriver() { + this(new Configuration()); + } + + /** + * Construct a JettisonMappedXmlDriver with configuration. + * + * @param config the Jettison configuration + */ + public JettisonMappedXmlDriver(final Configuration config) { + this(config, true); + } + + /** + * Construct a JettisonMappedXmlDriver with configuration. + *

    + * This constructor has been added by special request of Jettison users to support JSON generated by older Jettison + * versions. if the driver is setup to ignore the XStream hints for JSON arrays, there is neither support from + * XStream's side nor are there any tests to ensure this mode. + *

    + * + * @param config the Jettison configuration + * @param useSerializeAsArray flag to use XStream's hints for collections and arrays + * @since 1.4 + */ + public JettisonMappedXmlDriver(final Configuration config, final boolean useSerializeAsArray) { + mof = new MappedXMLOutputFactory(config); + mif = new MappedXMLInputFactory(config); + convention = new MappedNamespaceConvention(config); + this.useSerializeAsArray = useSerializeAsArray; + } + + @Override + public HierarchicalStreamReader createReader(final Reader reader) { + try { + return new StaxReader(new QNameMap(), mif.createXMLStreamReader(reader), getNameCoder()); + } catch (final XMLStreamException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamReader createReader(final InputStream input) { + try { + return new StaxReader(new QNameMap(), mif.createXMLStreamReader(input), getNameCoder()); + } catch (final XMLStreamException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamReader createReader(final URL in) { + InputStream instream = null; + try { + instream = in.openStream(); + return new StaxReader(new QNameMap(), mif.createXMLStreamReader(in.toExternalForm(), instream), + getNameCoder()); + } catch (final XMLStreamException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); + } finally { + if (instream != null) { + try { + instream.close(); + } catch (final IOException e) { + // ignore + } + } + } + } + + @Override + public HierarchicalStreamReader createReader(final File in) { + InputStream instream = null; + try { + instream = new FileInputStream(in); + return new StaxReader(new QNameMap(), mif.createXMLStreamReader(in.toURI().toASCIIString(), instream), + getNameCoder()); + } catch (final XMLStreamException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); + } finally { + if (instream != null) { + try { + instream.close(); + } catch (final IOException e) { + // ignore + } + } + } + } + + @Override + public HierarchicalStreamWriter createWriter(final Writer writer) { + try { + if (useSerializeAsArray) { + return new JettisonStaxWriter(new QNameMap(), mof.createXMLStreamWriter(writer), getNameCoder(), + convention); + } else { + return new StaxWriter(new QNameMap(), mof.createXMLStreamWriter(writer), getNameCoder()); + } + } catch (final XMLStreamException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamWriter createWriter(final OutputStream output) { + try { + if (useSerializeAsArray) { + return new JettisonStaxWriter(new QNameMap(), mof.createXMLStreamWriter(output), getNameCoder(), + convention); + } else { + return new StaxWriter(new QNameMap(), mof.createXMLStreamWriter(output), getNameCoder()); + } + } catch (final XMLStreamException e) { + throw new StreamException(e); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JettisonStaxWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JettisonStaxWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JettisonStaxWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2014 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 17.04.2008 by Joerg Schaible. + */ +package com.thoughtworks.xstream.io.json; + +import java.util.Collection; +import java.util.Map; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.codehaus.jettison.AbstractXMLStreamWriter; +import org.codehaus.jettison.mapped.MappedNamespaceConvention; + +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.xml.QNameMap; +import com.thoughtworks.xstream.io.xml.StaxWriter; +import com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer; + + +/** + * A specialized {@link StaxWriter} that makes usage of internal functionality of Jettison. + * + * @author Jörg Schaible + * @since 1.3.1 + */ +public class JettisonStaxWriter extends StaxWriter { + + private final MappedNamespaceConvention convention; + + /** + * @since 1.4 + */ + public JettisonStaxWriter( + final QNameMap qnameMap, final XMLStreamWriter out, final boolean writeEnclosingDocument, + final boolean namespaceRepairingMode, final NameCoder nameCoder, final MappedNamespaceConvention convention) + throws XMLStreamException { + super(qnameMap, out, writeEnclosingDocument, namespaceRepairingMode, nameCoder); + this.convention = convention; + } + + /** + * @deprecated As of 1.4 use + * {@link JettisonStaxWriter#JettisonStaxWriter(QNameMap, XMLStreamWriter, boolean, boolean, NameCoder, MappedNamespaceConvention)} + * instead + */ + @Deprecated + public JettisonStaxWriter( + final QNameMap qnameMap, final XMLStreamWriter out, final boolean writeEnclosingDocument, + final boolean namespaceRepairingMode, final XmlFriendlyReplacer replacer, + final MappedNamespaceConvention convention) throws XMLStreamException { + this(qnameMap, out, writeEnclosingDocument, namespaceRepairingMode, (NameCoder)replacer, convention); + } + + public JettisonStaxWriter( + final QNameMap qnameMap, final XMLStreamWriter out, final boolean writeEnclosingDocument, + final boolean namespaceRepairingMode, final MappedNamespaceConvention convention) throws XMLStreamException { + super(qnameMap, out, writeEnclosingDocument, namespaceRepairingMode); + this.convention = convention; + } + + public JettisonStaxWriter( + final QNameMap qnameMap, final XMLStreamWriter out, final MappedNamespaceConvention convention) + throws XMLStreamException { + super(qnameMap, out); + this.convention = convention; + } + + /** + * @since 1.4 + */ + public JettisonStaxWriter( + final QNameMap qnameMap, final XMLStreamWriter out, final NameCoder nameCoder, + final MappedNamespaceConvention convention) throws XMLStreamException { + super(qnameMap, out, nameCoder); + this.convention = convention; + } + + @Override + public void startNode(final String name, final Class clazz) { + final XMLStreamWriter out = getXMLStreamWriter(); + if (clazz != null && out instanceof AbstractXMLStreamWriter) { + if (Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz) || clazz.isArray()) { + final QName qname = getQNameMap().getQName(encodeNode(name)); + final String prefix = qname.getPrefix(); + final String uri = qname.getNamespaceURI(); + final String key = convention.createKey(prefix, uri, qname.getLocalPart()); + if (!((AbstractXMLStreamWriter)out).getSerializedAsArrays().contains(key)) { + // Typo is in the API of Jettison ... + ((AbstractXMLStreamWriter)out).seriliazeAsArray(key); + } + } + } + startNode(name); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2011, 2014 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 22. June 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.io.json; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.net.URL; + +import com.thoughtworks.xstream.io.AbstractDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * A driver for JSON that writes optimized JSON format, but is not able to deserialize the result. + * + * @author Paul Hammant + * @since 1.2 + */ +public class JsonHierarchicalStreamDriver extends AbstractDriver { + + /** + * Construct a JsonHierarchicalStreamDriver. + */ + public JsonHierarchicalStreamDriver() { + super(); + } + + /** + * Construct a JsonHierarchicalStreamDriver with name coding. + * + * @param nameCoder the coder to encode and decode the JSON labels. + * @since 1.4.2 + */ + public JsonHierarchicalStreamDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + public HierarchicalStreamReader createReader(final Reader in) { + throw new UnsupportedOperationException("The JsonHierarchicalStreamDriver can only write JSON"); + } + + @Override + public HierarchicalStreamReader createReader(final InputStream in) { + throw new UnsupportedOperationException("The JsonHierarchicalStreamDriver can only write JSON"); + } + + @Override + public HierarchicalStreamReader createReader(final URL in) { + throw new UnsupportedOperationException("The JsonHierarchicalStreamDriver can only write JSON"); + } + + @Override + public HierarchicalStreamReader createReader(final File in) { + throw new UnsupportedOperationException("The JsonHierarchicalStreamDriver can only write JSON"); + } + + /** + * Create a HierarchicalStreamWriter that writes JSON. + */ + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { + return new JsonWriter(out); + } + + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { + try { + // JSON spec requires UTF-8 + return createWriter(new OutputStreamWriter(out, "UTF-8")); + } catch (final UnsupportedEncodingException e) { + throw new StreamException(e); + } + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2014 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 22. June 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.io.json; + +import java.io.Writer; + + +/** + * A simple writer that outputs JSON in a pretty-printed indented stream. Arrays, Lists and Sets rely on you NOT using + * XStream.addImplicitCollection(..) + * + * @author Paul Hammant + * @author Jörg Schaible + * @since 1.2 + * @deprecated As of 1.3.1, use JsonWriter instead + */ +@Deprecated +public class JsonHierarchicalStreamWriter extends JsonWriter { + + /** + * @deprecated As of 1.3.1, use JsonWriter instead + */ + @Deprecated + public JsonHierarchicalStreamWriter(final Writer writer, final char[] lineIndenter, final String newLine) { + super(writer, lineIndenter, newLine); + } + + /** + * @deprecated As of 1.3.1, use JsonWriter instead + */ + @Deprecated + public JsonHierarchicalStreamWriter(final Writer writer, final char[] lineIndenter) { + this(writer, lineIndenter, "\n"); + } + + /** + * @deprecated As of 1.3.1, use JsonWriter instead + */ + @Deprecated + public JsonHierarchicalStreamWriter(final Writer writer, final String lineIndenter, final String newLine) { + this(writer, lineIndenter.toCharArray(), newLine); + } + + /** + * @deprecated As of 1.3.1, use JsonWriter instead + */ + @Deprecated + public JsonHierarchicalStreamWriter(final Writer writer, final String lineIndenter) { + this(writer, lineIndenter.toCharArray()); + } + + /** + * @deprecated As of 1.3.1, use JsonWriter instead + */ + @Deprecated + public JsonHierarchicalStreamWriter(final Writer writer) { + this(writer, new char[]{' ', ' '}); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JsonWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JsonWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/json/JsonWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014 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 28. November 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.json; + +import java.io.Writer; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.core.util.QuickWriter; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.naming.NoNameCoder; + + +/** + * A simple writer that outputs JSON in a pretty-printed indented stream. Arrays, Lists and Sets rely on you NOT using + * XStream.addImplicitCollection(..). + * + * @author Paul Hammant + * @author Jörg Schaible + * @since 1.3.1 + */ +public class JsonWriter extends AbstractJsonWriter { + + protected final QuickWriter writer; + protected final Format format; + private int depth; + private boolean newLineProposed; + + /** + * @deprecated As of 1.4 use {@link JsonWriter#JsonWriter(Writer, Format) instead} + */ + @Deprecated + public JsonWriter(final Writer writer, final char[] lineIndenter, final String newLine) { + this(writer, 0, new Format(lineIndenter, newLine.toCharArray(), Format.SPACE_AFTER_LABEL + | Format.COMPACT_EMPTY_ELEMENT)); + } + + /** + * @deprecated As of 1.4 use {@link JsonWriter#JsonWriter(Writer, Format) instead} + */ + @Deprecated + public JsonWriter(final Writer writer, final char[] lineIndenter) { + this(writer, 0, new Format(lineIndenter, new char[]{'\n'}, Format.SPACE_AFTER_LABEL + | Format.COMPACT_EMPTY_ELEMENT)); + } + + /** + * @deprecated As of 1.4 use {@link JsonWriter#JsonWriter(Writer, Format) instead} + */ + @Deprecated + public JsonWriter(final Writer writer, final String lineIndenter, final String newLine) { + this(writer, 0, new Format(lineIndenter.toCharArray(), newLine.toCharArray(), Format.SPACE_AFTER_LABEL + | Format.COMPACT_EMPTY_ELEMENT)); + } + + /** + * @deprecated As of 1.4 use {@link JsonWriter#JsonWriter(Writer, Format) instead} + */ + @Deprecated + public JsonWriter(final Writer writer, final String lineIndenter) { + this(writer, 0, new Format(lineIndenter.toCharArray(), new char[]{'\n'}, Format.SPACE_AFTER_LABEL + | Format.COMPACT_EMPTY_ELEMENT)); + } + + public JsonWriter(final Writer writer) { + this(writer, 0, new Format(new char[]{' ', ' '}, new char[]{'\n'}, Format.SPACE_AFTER_LABEL + | Format.COMPACT_EMPTY_ELEMENT)); + } + + /** + * @since 1.3.1 + * @deprecated As of 1.4 use {@link JsonWriter#JsonWriter(Writer, int, Format) instead} + */ + @Deprecated + public JsonWriter(final Writer writer, final char[] lineIndenter, final String newLine, final int mode) { + this(writer, mode, new Format(lineIndenter, newLine.toCharArray(), Format.SPACE_AFTER_LABEL + | Format.COMPACT_EMPTY_ELEMENT)); + } + + /** + * Create a JsonWriter where the writer mode can be chosen. + * + * @param writer the {@link Writer} where the JSON is written to + * @param mode the JsonWriter mode + * @since 1.3.1 + * @see #JsonWriter(Writer, int, Format) + */ + public JsonWriter(final Writer writer, final int mode) { + this(writer, mode, new Format()); + } + + /** + * Create a JsonWriter where the format is provided. + * + * @param writer the {@link Writer} where the JSON is written to + * @param format the JSON format definition + * @since 1.4 + * @see #JsonWriter(Writer, int, Format) + */ + public JsonWriter(final Writer writer, final Format format) { + this(writer, 0, format); + } + + /** + * Create a JsonWriter where the writer mode can be chosen and the format definition is provided. + *

    + * Following constants can be used as bit mask for the mode: + *

    + *
      + *
    • {@link #DROP_ROOT_MODE}: drop the root node
    • + *
    • {@link #STRICT_MODE}: do not throw {@link ConversionException}, if writer should generate invalid JSON
    • + *
    • {@link #EXPLICIT_MODE}: ensure that all available data is explicitly written even if addition objects must be + * added
    • + *
    + * + * @param writer the {@link Writer} where the JSON is written to + * @param mode the JsonWriter mode + * @param format the JSON format definition + * @since 1.4 + */ + public JsonWriter(final Writer writer, final int mode, final Format format) { + this(writer, mode, format, 1024); + } + + /** + * Create a JsonWriter. + * + * @param writer the {@link Writer} where the JSON is written to + * @param mode the JsonWriter mode + * @param format the JSON format definition + * @param bufferSize the buffer size of the internally used QuickWriter + * @see JsonWriter#JsonWriter(Writer, int, Format) + * @since 1.4 + */ + public JsonWriter(final Writer writer, final int mode, final Format format, final int bufferSize) { + super(mode, format.getNameCoder()); + this.writer = new QuickWriter(writer, bufferSize); + this.format = format; + depth = (mode & DROP_ROOT_MODE) == 0 ? -1 : 0; + } + + @Override + public void flush() { + writer.flush(); + } + + @Override + public void close() { + writer.close(); + } + + @Override + public HierarchicalStreamWriter underlyingWriter() { + return this; + } + + @Override + protected void startObject() { + if (newLineProposed) { + writeNewLine(); + } + writer.write('{'); + startNewLine(); + } + + @Override + protected void addLabel(final String name) { + if (newLineProposed) { + writeNewLine(); + } + writer.write('"'); + writeText(name); + writer.write("\":"); + if ((format.mode() & Format.SPACE_AFTER_LABEL) != 0) { + writer.write(' '); + } + } + + @Override + protected void addValue(final String value, final Type type) { + if (newLineProposed) { + writeNewLine(); + } + if (type == Type.STRING) { + writer.write('"'); + } + writeText(value); + if (type == Type.STRING) { + writer.write('"'); + } + } + + @Override + protected void startArray() { + if (newLineProposed) { + writeNewLine(); + } + writer.write("["); + startNewLine(); + } + + @Override + protected void nextElement() { + writer.write(","); + writeNewLine(); + } + + @Override + protected void endArray() { + endNewLine(); + writer.write("]"); + } + + @Override + protected void endObject() { + endNewLine(); + writer.write("}"); + } + + private void startNewLine() { + if (++depth > 0) { + newLineProposed = true; + } + } + + private void endNewLine() { + if (depth-- > 0) { + if ((format.mode() & Format.COMPACT_EMPTY_ELEMENT) != 0 && newLineProposed) { + newLineProposed = false; + } else { + writeNewLine(); + } + } + } + + private void writeNewLine() { + int depth = this.depth; + writer.write(format.getNewLine()); + while (depth-- > 0) { + writer.write(format.getLineIndenter()); + } + newLineProposed = false; + } + + private void writeText(final String text) { + final int length = text.length(); + for (int i = 0; i < length; i++) { + final char c = text.charAt(i); + switch (c) { + case '"': + writer.write("\\\""); + break; + case '\\': + writer.write("\\\\"); + break; + // turn this off - it is no CTRL char anyway + // case '/': + // this.writer.write("\\/"); + // break; + case '\b': + writer.write("\\b"); + break; + case '\f': + writer.write("\\f"); + break; + case '\n': + writer.write("\\n"); + break; + case '\r': + writer.write("\\r"); + break; + case '\t': + writer.write("\\t"); + break; + default: + if (c > 0x1f) { + writer.write(c); + } else { + writer.write("\\u"); + final String hex = "000" + Integer.toHexString(c); + writer.write(hex.substring(hex.length() - 4)); + } + } + } + } + + /** + * Format definition for JSON. + * + * @author Jörg Schaible + * @since 1.4 + */ + public static class Format { + + public static int SPACE_AFTER_LABEL = 1; + public static int COMPACT_EMPTY_ELEMENT = 2; + + private final char[] lineIndenter; + private final char[] newLine; + private final int mode; + private final NameCoder nameCoder; + + /** + * Create a new default Formatter. The formatter uses two spaces, normal line feed character, adds a space after + * the label and will try to compact the output. + * + * @since 1.4.2 + */ + public Format() { + this(new char[]{' ', ' '}, new char[]{'\n'}, Format.SPACE_AFTER_LABEL | Format.COMPACT_EMPTY_ELEMENT); + } + + /** + * Create a new Formatter. + * + * @param lineIndenter the characters used for indenting the line + * @param newLine the characters used to create a new line + * @param mode the flags for the format modes + * @since 1.4 + */ + public Format(final char[] lineIndenter, final char[] newLine, final int mode) { + this(lineIndenter, newLine, mode, new NoNameCoder()); + } + + /** + * Create a new Formatter. + * + * @param lineIndenter the characters used for indenting the line + * @param newLine the characters used to create a new line + * @param mode the flags for the format modes + * @param nameCoder the name encoder and decoder + * @since 1.4.2 + */ + public Format(final char[] lineIndenter, final char[] newLine, final int mode, final NameCoder nameCoder) { + this.lineIndenter = lineIndenter; + this.newLine = newLine; + this.mode = mode; + this.nameCoder = nameCoder; + } + + /** + * Retrieve the lineIndenter. + * + * @return the lineIndenter + * @since 1.4 + */ + public char[] getLineIndenter() { + return lineIndenter; + } + + /** + * Retrieve the newLine. + * + * @return the newLine + * @since 1.4 + */ + public char[] getNewLine() { + return newLine; + } + + /** + * Retrieve the mode flags of the formatter. + * + * @return the mode + * @since 1.4 + */ + public int mode() { + return mode; + } + + /** + * Retrieve the NameCoder. + * + * @return the name coder + * @since 1.4.2 + */ + public NameCoder getNameCoder() { + return nameCoder; + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/NameCoder.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/NameCoder.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/NameCoder.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2009, 2011 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 14. August 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.naming; + +/** + * Coder between names in the object graph and names of a target format. + *

    + * The names form the object graph are typically names generated from Java identifiers (Java + * types or field members), but some names may also contain a minus sign. However, the original + * name might have already been aliased, so a wider range of characters can occur. + *

    + *

    + * The target names should satisfy the syntax of the target format. Transforming Java objects to + * XML this affects names that contain or even start with a dollar sign. Such names violate the + * XML specification. + *

    + *

    + * By default all names from the object graph are used as node names in the target format. + * Meta-data that is necessary to unmarshal the object again is typically written as attribute. + * Since such attributes might be represented differently in the target format, the NameCoder + * distinguishes between the names used for meta-data elements and the ones for the object data. + * The names in the target format might even have to follow a different syntax. Remember, that + * XStream can be easily configured to write also object data as attributes. + *

    + *

    + * Note that the instance of a NameCoder should be either thread-safe or implement {@link Cloneable}. + *

    + * + * @author Jörg Schaible + * @since 1.4 + */ +public interface NameCoder { + /** + * Encode an object name for a node in the target format. + * + * @param name the name of the object data + * @return the node name in the target format + * @since 1.4 + */ + String encodeNode(String name); + + /** + * Encode a meta-data name for an attribute in the target format. + * + * @param name the name of the meta-data + * @return the attribute name in the target format + * @since 1.4 + */ + String encodeAttribute(String name); + + /** + * Decode a node name to an object name. + * + * @param nodeName the name of the node + * @return the name of the object + * @since 1.4 + */ + String decodeNode(String nodeName); + + /** + * Decode an attribute name to an object name. + * + * @param attributeName the name of the attribute + * @return the name of the meta-data + * @since 1.4 + */ + String decodeAttribute(String attributeName); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/NameCoderWrapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/NameCoderWrapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/NameCoderWrapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 15. August 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.naming; + +/** + * A wrapper for another NameCoder. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class NameCoderWrapper implements NameCoder { + + private final NameCoder wrapped; + + /** + * Construct a new wrapper for a NameCoder. + * + * @param inner the wrapped NameCoder + * @since 1.4 + */ + public NameCoderWrapper(final NameCoder inner) { + wrapped = inner; + } + + @Override + public String decodeAttribute(final String attributeName) { + return wrapped.decodeAttribute(attributeName); + } + + @Override + public String decodeNode(final String nodeName) { + return wrapped.decodeNode(nodeName); + } + + @Override + public String encodeAttribute(final String name) { + return wrapped.encodeAttribute(name); + } + + @Override + public String encodeNode(final String name) { + return wrapped.encodeNode(name); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/NoNameCoder.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/NoNameCoder.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/NoNameCoder.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 15. August 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.naming; + +/** + * A NameCoder that does nothing. + *

    + * The usage of this implementation implies that the names used for the objects can also be used in the target format + * without any change. This applies also for XML if the object graph contains no object that is an instance of an inner + * class type or is in the default package. + *

    + * + * @author Jörg Schaible + * @since 1.4 + */ +public class NoNameCoder implements NameCoder { + + @Override + public String decodeAttribute(final String attributeName) { + return attributeName; + } + + @Override + public String decodeNode(final String nodeName) { + return nodeName; + } + + @Override + public String encodeAttribute(final String name) { + return name; + } + + @Override + public String encodeNode(final String name) { + return name; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/StaticNameCoder.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/StaticNameCoder.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/naming/StaticNameCoder.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 15. August 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.naming; + +import java.util.HashMap; +import java.util.Map; + + +/** + * A NameCoder that encodes and decodes names based on a map. + *

    + * The provided map should contain a mapping between the name of the Java type or field to the proper element in the + * target format. If a name cannot be found in the map, it is assumed not to be mapped at all. Note that the values of + * the map should be unique also, otherwise the decoding will produce wrong results. + *

    + * + * @author Jörg Schaible + * @since 1.4 + */ +public class StaticNameCoder implements NameCoder { + + private final Map java2Node; + private final Map java2Attribute; + + private transient Map node2Java; + private transient Map attribute2Java; + + /** + * Construct a StaticNameCoder. + * + * @param java2Node mapping of Java names to nodes + * @param java2Attribute mapping of Java names to attributes + * @since 1.4 + */ + public StaticNameCoder(final Map java2Node, final Map java2Attribute) { + this.java2Node = new HashMap(java2Node); + if (java2Node == java2Attribute || java2Attribute == null) { + this.java2Attribute = this.java2Node; + } else { + this.java2Attribute = new HashMap(java2Attribute); + } + readResolve(); + } + + @Override + public String decodeAttribute(final String attributeName) { + final String name = attribute2Java.get(attributeName); + return name == null ? attributeName : name; + } + + @Override + public String decodeNode(final String nodeName) { + final String name = node2Java.get(nodeName); + return name == null ? nodeName : name; + } + + @Override + public String encodeAttribute(final String name) { + final String friendlyName = java2Attribute.get(name); + return friendlyName == null ? name : friendlyName; + } + + @Override + public String encodeNode(final String name) { + final String friendlyName = java2Node.get(name); + return friendlyName == null ? name : friendlyName; + } + + private Object readResolve() { + node2Java = invertMap(java2Node); + if (java2Node == java2Attribute) { + attribute2Java = node2Java; + } else { + attribute2Java = invertMap(java2Attribute); + } + return this; + } + + private Map invertMap(final Map map) { + final Map inverseMap = new HashMap(map.size()); + for (final Map.Entry entry : map.entrySet()) { + inverseMap.put(entry.getValue(), entry.getKey()); + } + return inverseMap; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/Path.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/Path.java (.../Path.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/Path.java (.../Path.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,102 +1,173 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2013, 2014 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 02. September 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.path; +import java.util.ArrayList; +import java.util.List; + import com.thoughtworks.xstream.core.util.FastStack; -import java.util.List; -import java.util.ArrayList; /** - * Represents a path (subset of XPath) to a single node in the tree. - * - *

    Two absolute paths can also be compared to calculate the relative path between them. - * A relative path can be applied to an absolute path to calculate another absolute path.

    - * - *

    Note that the paths produced are XPath compliant, so can be read by other XPath engines. - * The following are examples of path expressions that the Path object supports:

    + * Represents a path to a single node in the tree. + *

    + * Two absolute paths can also be compared to calculate the relative path between them. A relative path can be applied + * to an absolute path to calculate another absolute path. + *

    + *

    + * Note that the paths are normally XPath compliant, so can be read by other XPath engines. However, {@link #toString()} + * will select a node list while {@link #explicit()} will always select an individual node. If the return type of the + * XPath evaluation is a node, the result will be the same, because XPath will then use the first element of the list. + * The following are examples of path expressions that the Path object supports: + *

    + *

    + * Note that the implementation does not take care if the paths are XPath compliant, it simply manages the values + * between the path separator. However, it normalizes the path if a path element ends with a selector for the first + * element (i.e. "[1]"). Those will be handled transparent i.e. two Paths are treated equal if one was created with path + * elements containing this selector and the other one without. + *

    + *

    + * The following are examples of path expressions that the Path object supports: + *

    *
      - *
    • /
    • - *
    • /some/node
    • - *
    • /a/b/c/b/a
    • - *
    • /some[3]/node[2]/a
    • - *
    • ../../../another[3]/node
    • + *
    • /
    • + *
    • /some/node
    • + *
    • /a/b/c/b/a
    • + *
    • /a/b[1]/c[1]/b[1]/a[1]
    • + *
    • /some[3]/node[2]/a
    • + *
    • ../../../another[3]/node
    • *
    - * - *

    Example

    - * + *

    Example

    + * *
    - * Path a = new Path("/html/body/div/table[2]/tr[3]/td/div");
    - * Path b = new Path("/html/body/div/table[2]/tr[6]/td/form");
    - *
    - * Path relativePath = a.relativeTo(b); // produces: "../../../tr[6]/td/form"
    + * Path a = new Path("/html/body/div[1]/table[2]/tr[3]/td/div");
    + * Path b = new Path("/html/body/div/table[2]/tr[6]/td/form");
    + * 
    + * Path relativePath = a.relativeTo(b); // produces: "../../../tr[6]/td/form"
      * Path c = a.apply(relativePath); // same as Path b.
      * 
    - * + * * @see PathTracker - * * @author Joe Walnes */ public class Path { private final String[] chunks; private transient String pathAsString; - private static final Path DOT = new Path(new String[] {"."}); + private transient String pathExplicit; + private static final Path DOT = new Path(new String[]{"."}); - public Path(String pathAsString) { + public Path(final String pathAsString) { // String.split() too slow. StringTokenizer too crappy. - List result = new ArrayList(); + final List result = new ArrayList(); int currentIndex = 0; - int nextSeperator; - while ((nextSeperator = pathAsString.indexOf('/', currentIndex)) != -1) { - result.add(pathAsString.substring(currentIndex, nextSeperator)); - currentIndex = nextSeperator + 1; + int nextSeparator; + this.pathAsString = pathAsString; + while ((nextSeparator = pathAsString.indexOf('/', currentIndex)) != -1) { + // normalize explicit paths + result.add(normalize(pathAsString, currentIndex, nextSeparator)); + currentIndex = nextSeparator + 1; } - result.add(pathAsString.substring(currentIndex)); - String[] arr = new String[result.size()]; + result.add(normalize(pathAsString, currentIndex, pathAsString.length())); + final String[] arr = new String[result.size()]; result.toArray(arr); chunks = arr; - this.pathAsString = pathAsString; } - public Path(String[] chunks) { + private String normalize(final String s, final int start, final int end) { + if (end - start > 3 && s.charAt(end - 3) == '[' && s.charAt(end - 2) == '1' && s.charAt(end - 1) == ']') { + pathAsString = null; + return s.substring(start, end - 3); + } else { + return s.substring(start, end); + } + + } + + public Path(final String[] chunks) { this.chunks = chunks; } + @Override public String toString() { if (pathAsString == null) { - StringBuffer buffer = new StringBuffer(); + final StringBuilder buffer = new StringBuilder(); for (int i = 0; i < chunks.length; i++) { - if (i > 0) buffer.append('/'); + if (i > 0) { + buffer.append('/'); + } buffer.append(chunks[i]); } pathAsString = buffer.toString(); } return pathAsString; } - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Path)) return false; + public String explicit() { + if (pathExplicit == null) { + final StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < chunks.length; i++) { + if (i > 0) { + buffer.append('/'); + } + final String chunk = chunks[i]; + buffer.append(chunk); + final int length = chunk.length(); + if (length > 0) { + final char c = chunk.charAt(length - 1); + if (c != ']' && c != '.') { + buffer.append("[1]"); + } + } + } + pathExplicit = buffer.toString(); + } + return pathExplicit; + } - final Path other = (Path) o; - if (chunks.length != other.chunks.length) return false; + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Path)) { + return false; + } + + final Path other = (Path)o; + if (chunks.length != other.chunks.length) { + return false; + } for (int i = 0; i < chunks.length; i++) { - if (!chunks[i].equals(other.chunks[i])) return false; + if (!chunks[i].equals(other.chunks[i])) { + return false; + } } return true; } + @Override public int hashCode() { int result = 543645643; - for (int i = 0; i < chunks.length; i++) { - result = 29 * result + chunks[i].hashCode(); + for (final String chunk : chunks) { + result = 29 * result + chunk.hashCode(); } return result; } - public Path relativeTo(Path that) { - int depthOfPathDivergence = depthOfPathDivergence(chunks, that.chunks); - String[] result = new String[chunks.length + that.chunks.length - 2 * depthOfPathDivergence]; + public Path relativeTo(final Path that) { + final int depthOfPathDivergence = depthOfPathDivergence(chunks, that.chunks); + final String[] result = new String[chunks.length + that.chunks.length - 2 * depthOfPathDivergence]; int count = 0; for (int i = depthOfPathDivergence; i < chunks.length; i++) { @@ -113,8 +184,8 @@ } } - private int depthOfPathDivergence(String[] path1, String[] path2) { - int minLength = Math.min(path1.length, path2.length); + private int depthOfPathDivergence(final String[] path1, final String[] path2) { + final int minLength = Math.min(path1.length, path2.length); for (int i = 0; i < minLength; i++) { if (!path1[i].equals(path2[i])) { return i; @@ -123,27 +194,38 @@ return minLength; } - public Path apply(Path relativePath) { - FastStack absoluteStack = new FastStack(16); + public Path apply(final Path relativePath) { + final FastStack absoluteStack = new FastStack(16); - for (int i = 0; i < chunks.length; i++) { - absoluteStack.push(chunks[i]); + for (final String chunk : chunks) { + absoluteStack.push(chunk); } - for (int i = 0; i < relativePath.chunks.length; i++) { - String relativeChunk = relativePath.chunks[i]; + for (final String relativeChunk : relativePath.chunks) { if (relativeChunk.equals("..")) { absoluteStack.pop(); } else if (!relativeChunk.equals(".")) { absoluteStack.push(relativeChunk); } } - String[] result = new String[absoluteStack.size()]; + final String[] result = new String[absoluteStack.size()]; for (int i = 0; i < result.length; i++) { - result[i] = (String) absoluteStack.get(i); + result[i] = absoluteStack.get(i); } return new Path(result); } + + public boolean isAncestor(final Path child) { + if (child == null || child.chunks.length < chunks.length) { + return false; + } + for (int i = 0; i < chunks.length; i++) { + if (!chunks[i].equals(child.chunks[i])) { + return false; + } + } + return true; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTracker.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTracker.java (.../PathTracker.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTracker.java (.../PathTracker.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,44 +1,54 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.path; import java.util.HashMap; import java.util.Map; + /** * Maintains the current {@link Path} as a stream is moved through. - * - *

    Can be linked to a HierarchicalStreamWriter or - * HierarchicalStreamReader by wrapping them with a - * PathTrackingWriter or - * PathTrackingReader.

    - * + *

    + * Can be linked to a {@link com.thoughtworks.xstream.io.HierarchicalStreamWriter} or + * {@link com.thoughtworks.xstream.io.HierarchicalStreamReader} by wrapping them with a {@link PathTrackingWriter} or + * {@link PathTrackingReader}. + *

    *

    Example

    - * + * *
      * PathTracker tracker = new PathTracker();
    - * tracker.pushElement("table");
    - * tracker.pushElement("tr");
    - * tracker.pushElement("td");
    - * tracker.pushElement("form");
    - * tracker.popElement("form");
    - * tracker.popElement("td");
    - * tracker.pushElement("td");
    - * tracker.pushElement("div");
    - *
    - * Path path = tracker.getPath(); // returns "/table/tr/td[2]/div"
    + * tracker.pushElement("table");
    + * tracker.pushElement("tr");
    + * tracker.pushElement("td");
    + * tracker.pushElement("form");
    + * tracker.popElement("form");
    + * tracker.popElement("td");
    + * tracker.pushElement("td");
    + * tracker.pushElement("div");
    + * 
    + * Path path = tracker.getPath(); // returns "/table/tr/td[2]/div"
      * 
    - * + * * @see Path * @see PathTrackingReader * @see PathTrackingWriter - * * @author Joe Walnes */ public class PathTracker { private int pointer; private int capacity; private String[] pathStack; - private Map[] indexMapStack; + private Map[] indexMapStack; private Path currentPath; @@ -48,32 +58,34 @@ /** * @param initialCapacity Size of the initial stack of nodes (one level per depth in the tree). Note that this is - * only for optimizations - the stack will resize itself if it exceeds its capacity. If in doubt, - * use the other constructor. + * only for optimizations - the stack will resize itself if it exceeds its capacity. If in doubt, use the + * other constructor. */ - public PathTracker(int initialCapacity) { - this.capacity = initialCapacity; + public PathTracker(final int initialCapacity) { + capacity = Math.max(1, initialCapacity); pathStack = new String[capacity]; - indexMapStack = new Map[capacity]; + @SuppressWarnings("unchecked") + final Map[] newIndexMapStack = new Map[capacity]; + indexMapStack = newIndexMapStack; } /** * Notify the tracker that the stream has moved into a new element. - * + * * @param name Name of the element */ - public void pushElement(String name) { + public void pushElement(final String name) { if (pointer + 1 >= capacity) { resizeStacks(capacity * 2); } pathStack[pointer] = name; - Map indexMap = indexMapStack[pointer]; + Map indexMap = indexMapStack[pointer]; if (indexMap == null) { - indexMap = new HashMap(); + indexMap = new HashMap(); indexMapStack[pointer] = indexMap; } if (indexMap.containsKey(name)) { - indexMap.put(name, new Integer(((Integer) indexMap.get(name)).intValue() + 1)); + indexMap.put(name, new Integer(indexMap.get(name).intValue() + 1)); } else { indexMap.put(name, new Integer(1)); } @@ -86,21 +98,62 @@ */ public void popElement() { indexMapStack[pointer] = null; + pathStack[pointer] = null; currentPath = null; pointer--; } /** - * @deprecated Use {@link #getPath()} instead. + * Get the last path element from the stack. + * + * @return the name of the path element + * @since 1.4.2 */ - public String getCurrentPath() { - return getPath().toString(); + public String peekElement() { + return peekElement(0); } - private void resizeStacks(int newCapacity) { - String[] newPathStack = new String[newCapacity]; - Map[] newIndexMapStack = new Map[newCapacity]; - int min = Math.min(capacity, newCapacity); + /** + * Get a path element from the stack. + * + * @param i path index + * @return the name of the path element + * @since 1.4.2 + * @throws ArrayIndexOutOfBoundsException if the index is >= 0 or <= -depth() + */ + public String peekElement(final int i) { + if (i < -pointer || i > 0) { + throw new ArrayIndexOutOfBoundsException(i); + } + final int idx = pointer + i - 1; + final String name; + final Integer integer = indexMapStack[idx].get(pathStack[idx]); + final int index = integer.intValue(); + if (index > 1) { + final StringBuffer chunk = new StringBuffer(pathStack[idx].length() + 6); + chunk.append(pathStack[idx]).append('[').append(index).append(']'); + name = chunk.toString(); + } else { + name = pathStack[idx]; + } + return name; + } + + /** + * Get the depth of the stack. + * + * @return the stack depth + * @since 1.4.2 + */ + public int depth() { + return pointer; + } + + private void resizeStacks(final int newCapacity) { + final String[] newPathStack = new String[newCapacity]; + @SuppressWarnings("unchecked") + final Map[] newIndexMapStack = new Map[newCapacity]; + final int min = Math.min(capacity, newCapacity); System.arraycopy(pathStack, 0, newPathStack, 0, min); System.arraycopy(indexMapStack, 0, newIndexMapStack, 0, min); pathStack = newPathStack; @@ -113,16 +166,11 @@ */ public Path getPath() { if (currentPath == null) { - String[] chunks = new String[pointer + 1]; + final String[] chunks = new String[pointer + 1]; chunks[0] = ""; - for (int i = 0; i < pointer; i++) { - Integer integer = ((Integer) indexMapStack[i].get(pathStack[i])); - int index = integer.intValue(); - if (index > 1) { - chunks[i + 1] = pathStack[i] + '[' + index + ']'; - } else { - chunks[i + 1] = pathStack[i]; - } + for (int i = -pointer; ++i <= 0;) { + final String name = peekElement(i); + chunks[i + pointer] = name; } currentPath = new Path(chunks); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingReader.java (.../PathTrackingReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingReader.java (.../PathTrackingReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,38 +1,52 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 03. April 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.path; import com.thoughtworks.xstream.converters.ErrorWriter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.ReaderWrapper; + /** * Wrapper for HierarchicalStreamReader that tracks the path (a subset of XPath) of the current node that is being read. - * + * * @see PathTracker * @see Path - * * @author Joe Walnes */ public class PathTrackingReader extends ReaderWrapper { private final PathTracker pathTracker; - public PathTrackingReader(HierarchicalStreamReader reader, PathTracker pathTracker) { + public PathTrackingReader(final HierarchicalStreamReader reader, final PathTracker pathTracker) { super(reader); this.pathTracker = pathTracker; pathTracker.pushElement(getNodeName()); } + @Override public void moveDown() { super.moveDown(); pathTracker.pushElement(getNodeName()); } + @Override public void moveUp() { super.moveUp(); pathTracker.popElement(); } - public void appendErrors(ErrorWriter errorWriter) { + @Override + public void appendErrors(final ErrorWriter errorWriter) { errorWriter.add("path", pathTracker.getPath().toString()); super.appendErrors(errorWriter); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingWriter.java (.../PathTrackingWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/PathTrackingWriter.java (.../PathTrackingWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,33 +1,55 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.path; +import com.thoughtworks.xstream.io.AbstractWriter; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.WriterWrapper; + /** - * Wrapper for HierarchicalStreamWriter that tracks the path (a subset of XPath) of the current node that is being written. - * + * Wrapper for HierarchicalStreamWriter that tracks the path (a subset of XPath) of the current node that is being + * written. + * * @see PathTracker * @see Path - * * @author Joe Walnes */ public class PathTrackingWriter extends WriterWrapper { private final PathTracker pathTracker; + private final boolean isNameEncoding; - public PathTrackingWriter(HierarchicalStreamWriter writer, PathTracker pathTracker) { + public PathTrackingWriter(final HierarchicalStreamWriter writer, final PathTracker pathTracker) { super(writer); + isNameEncoding = writer.underlyingWriter() instanceof AbstractWriter; this.pathTracker = pathTracker; } - public void startNode(String name) { - pathTracker.pushElement(name); + @Override + public void startNode(final String name) { + pathTracker.pushElement(isNameEncoding ? ((AbstractWriter)wrapped.underlyingWriter()).encodeNode(name) : name); super.startNode(name); } + @Override + public void startNode(final String name, final Class clazz) { + pathTracker.pushElement(isNameEncoding ? ((AbstractWriter)wrapped.underlyingWriter()).encodeNode(name) : name); + super.startNode(name, clazz); + } + + @Override public void endNode() { super.endNode(); pathTracker.popElement(); } - } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/package.html =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/package.html (.../package.html) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/path/package.html (.../package.html) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,3 +1,14 @@ + Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractDocumentReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractDocumentReader.java (.../AbstractDocumentReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractDocumentReader.java (.../AbstractDocumentReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,34 +1,67 @@ +/* + * Copyright (C) 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 24. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; +import java.util.Iterator; + import com.thoughtworks.xstream.converters.ErrorWriter; import com.thoughtworks.xstream.core.util.FastStack; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.AttributeNameIterator; +import com.thoughtworks.xstream.io.naming.NameCoder; -import java.util.Iterator; -public abstract class AbstractDocumentReader implements HierarchicalStreamReader { +public abstract class AbstractDocumentReader extends AbstractXmlReader implements DocumentReader { - private FastStack pointers = new FastStack(16); + private final FastStack pointers = new FastStack(16); private Object current; - protected AbstractDocumentReader(Object rootElement) { - this.current = rootElement; + protected AbstractDocumentReader(final Object rootElement) { + this(rootElement, new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4 + */ + protected AbstractDocumentReader(final Object rootElement, final NameCoder nameCoder) { + super(nameCoder); + current = rootElement; pointers.push(new Pointer()); reassignCurrentElement(current); } + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link AbstractDocumentReader#AbstractDocumentReader(Object, NameCoder)} instead. + */ + @Deprecated + protected AbstractDocumentReader(final Object rootElement, final XmlFriendlyReplacer replacer) { + this(rootElement, (NameCoder)replacer); + } + protected abstract void reassignCurrentElement(Object current); + protected abstract Object getParent(); + protected abstract Object getChild(int index); + protected abstract int getChildCount(); private static class Pointer { public int v; } + @Override public boolean hasMoreChildren() { - Pointer pointer = (Pointer) pointers.peek(); + final Pointer pointer = pointers.peek(); if (pointer.v < getChildCount()) { return true; @@ -37,14 +70,16 @@ } } + @Override public void moveUp() { current = getParent(); pointers.popSilently(); reassignCurrentElement(current); } + @Override public void moveDown() { - Pointer pointer = (Pointer) pointers.peek(); + final Pointer pointer = pointers.peek(); pointers.push(new Pointer()); current = getChild(pointer.v); @@ -53,22 +88,22 @@ reassignCurrentElement(current); } - public Iterator getAttributeNames() { + @Override + public Iterator getAttributeNames() { return new AttributeNameIterator(this); } - public void appendErrors(ErrorWriter errorWriter) { + @Override + public void appendErrors(final ErrorWriter errorWriter) { } - public Object peekUnderlyingNode() { + @Override + public Object getCurrent() { return current; } + @Override public void close() { // don't need to do anything } - - public HierarchicalStreamReader underlyingReader() { - return this; - } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractDocumentWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractDocumentWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractDocumentWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 18. October 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import java.util.ArrayList; +import java.util.List; + +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * A generic {@link com.thoughtworks.xstream.io.HierarchicalStreamWriter} for DOM writer implementations. The + * implementation manages a list of top level DOM nodes. Every time the last node is closed on the node stack, the next + * started node is added to the list. This list can be retrieved using the {@link DocumentWriter#getTopLevelNodes()} + * method. + * + * @author Laurent Bihanic + * @author Jörg Schaible + * @since 1.2.1 + */ +public abstract class AbstractDocumentWriter extends AbstractXmlWriter implements DocumentWriter { + + private final List result = new ArrayList(); + private final FastStack nodeStack = new FastStack(16); + + /** + * Constructs an AbstractDocumentWriter. + * + * @param container the top level container for the nodes to create (may be null) + * @param nameCoder the object that creates XML-friendly names + * @since 1.4 + */ + public AbstractDocumentWriter(final Object container, final NameCoder nameCoder) { + super(nameCoder); + if (container != null) { + nodeStack.push(container); + result.add(container); + } + } + + /** + * Constructs an AbstractDocumentWriter. + * + * @param container the top level container for the nodes to create (may be null) + * @param replacer the object that creates XML-friendly names + * @since 1.2.1 + * @deprecated As of 1.4 use {@link AbstractDocumentWriter#AbstractDocumentWriter(Object, NameCoder)} instead. + */ + @Deprecated + public AbstractDocumentWriter(final Object container, final XmlFriendlyReplacer replacer) { + this(container, (NameCoder)replacer); + } + + @Override + public final void startNode(final String name) { + final Object node = createNode(name); + nodeStack.push(node); + } + + /** + * Create a node. The provided node name is not yet XML friendly. If {@link #getCurrent()} returns null + * the node is a top level node. + * + * @param name the node name + * @return the new node + * @since 1.2.1 + */ + protected abstract Object createNode(String name); + + @Override + public final void endNode() { + endNodeInternally(); + final Object node = nodeStack.pop(); + if (nodeStack.size() == 0) { + result.add(node); + } + } + + /** + * Called when a node ends. Hook for derived implementations. + * + * @since 1.2.1 + */ + public void endNodeInternally() { + } + + /** + * @since 1.2.1 + */ + protected final Object getCurrent() { + return nodeStack.peek(); + } + + @Override + public List getTopLevelNodes() { + return result; + } + + @Override + public void flush() { + // don't need to do anything + } + + @Override + public void close() { + // don't need to do anything + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractPullReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractPullReader.java (.../AbstractPullReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractPullReader.java (.../AbstractPullReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,30 +1,43 @@ +/* + * Copyright (C) 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2014 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 24. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; +import java.util.Iterator; + import com.thoughtworks.xstream.core.util.FastStack; import com.thoughtworks.xstream.io.AttributeNameIterator; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.naming.NameCoder; -import java.util.Iterator; /** - * Base class that contains common functionality across HierarchicalStreamReader implementations - * that need to read from a pull parser. - * + * Base class that contains common functionality across HierarchicalStreamReader implementations that need to read from + * a pull parser. + * * @author Joe Walnes * @author James Strachan */ -public abstract class AbstractPullReader implements HierarchicalStreamReader { +public abstract class AbstractPullReader extends AbstractXmlReader { protected static final int START_NODE = 1; protected static final int END_NODE = 2; protected static final int TEXT = 3; protected static final int COMMENT = 4; protected static final int OTHER = 0; - private final FastStack elementStack = new FastStack(16); + private final FastStack elementStack = new FastStack(16); + private final FastStack pool = new FastStack(16); - private final FastStack lookahead = new FastStack(4); - private final FastStack lookback = new FastStack(4); + private final FastStack lookahead = new FastStack(4); + private final FastStack lookback = new FastStack(4); private boolean marked; private static class Event { @@ -33,13 +46,31 @@ } /** + * @since 1.4 + */ + protected AbstractPullReader(final NameCoder nameCoder) { + super(nameCoder); + } + + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link AbstractPullReader#AbstractPullReader(NameCoder)} instead + */ + @Deprecated + protected AbstractPullReader(final XmlFriendlyReplacer replacer) { + this((NameCoder)replacer); + } + + /** * Pull the next event from the stream. - * - *

    This MUST return {@link #START_NODE}, {@link #END_NODE}, {@link #TEXT}, {@link #COMMENT}, - * {@link #OTHER} or throw {@link com.thoughtworks.xstream.io.StreamException}.

    - * - *

    The underlying pull parser will most likely return its own event types. These must be - * mapped to the appropriate events.

    + *

    + * This MUST return {@link #START_NODE}, {@link #END_NODE}, {@link #TEXT}, {@link #COMMENT}, {@link #OTHER} or throw + * {@link com.thoughtworks.xstream.io.StreamException}. + *

    + *

    + * The underlying pull parser will most likely return its own event types. These must be mapped to the appropriate + * events. + *

    */ protected abstract int pullNextEvent(); @@ -53,24 +84,26 @@ */ protected abstract String pullText(); + @Override public boolean hasMoreChildren() { mark(); while (true) { switch (readEvent().type) { - case START_NODE: - reset(); - return true; - case END_NODE: - reset(); - return false; - default: - continue; + case START_NODE: + reset(); + return true; + case END_NODE: + reset(); + return false; + default: + continue; } } } + @Override public void moveDown() { - int currentDepth = elementStack.size(); + final int currentDepth = elementStack.size(); while (elementStack.size() <= currentDepth) { move(); if (elementStack.size() < currentDepth) { @@ -79,47 +112,52 @@ } } + @Override public void moveUp() { - int currentDepth = elementStack.size(); + final int currentDepth = elementStack.size(); while (elementStack.size() >= currentDepth) { move(); } } private void move() { - switch (readEvent().type) { - case START_NODE: - elementStack.push(pullElementName()); - break; - case END_NODE: - elementStack.pop(); - break; + final Event event = readEvent(); + pool.push(event); + switch (event.type) { + case START_NODE: + elementStack.push(pullElementName()); + break; + case END_NODE: + elementStack.pop(); + break; } } private Event readEvent() { if (marked) { if (lookback.hasStuff()) { - return (Event) lookahead.push(lookback.pop()); + return lookahead.push(lookback.pop()); } else { - return (Event) lookahead.push(readRealEvent()); + return lookahead.push(readRealEvent()); } } else { if (lookback.hasStuff()) { - return (Event) lookback.pop(); + return lookback.pop(); } else { return readRealEvent(); } } } private Event readRealEvent() { - Event event = new Event(); + final Event event = pool.hasStuff() ? (Event)pool.pop() : new Event(); event.type = pullNextEvent(); if (event.type == TEXT) { event.value = pullText(); } else if (event.type == START_NODE) { event.value = pullElementName(); + } else { + event.value = null; } return event; } @@ -129,12 +167,13 @@ } public void reset() { - while(lookahead.hasStuff()) { + while (lookahead.hasStuff()) { lookback.push(lookahead.pop()); } marked = false; } + @Override public String getValue() { // we should collapse together any text which // contains comments @@ -148,7 +187,7 @@ Event event = readEvent(); while (true) { if (event.type == TEXT) { - String text = event.value; + final String text = event.value; if (text != null && text.length() > 0) { if (last == null) { last = text; @@ -168,24 +207,35 @@ if (buffer != null) { return buffer.toString(); } else { - return (last == null) ? "" : last; + return last == null ? "" : last; } } - public Iterator getAttributeNames() { + @Override + public Iterator getAttributeNames() { return new AttributeNameIterator(this); } + @Override public String getNodeName() { - return (String) elementStack.peek(); + return unescapeXmlName(elementStack.peek()); } - public Object peekUnderlyingNode() { - throw new UnsupportedOperationException(); + @Override + public String peekNextChild() { + mark(); + while (true) { + final Event ev = readEvent(); + switch (ev.type) { + case START_NODE: + reset(); + return ev.value; + case END_NODE: + reset(); + return null; + default: + continue; + } + } } - - public HierarchicalStreamReader underlyingReader() { - return this; - } - } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXmlDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXmlDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXmlDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 28. May 2005 by Mauro Talevi + */ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.AbstractDriver; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * Base class for HierarchicalStreamDrivers to use XML-based HierarchicalStreamReader and HierarchicalStreamWriter. + * + * @author Mauro Talevi + * @author Jörg Schaible + * @since 1.2 + * @deprecated As of 1.4 + */ +@Deprecated +public abstract class AbstractXmlDriver extends AbstractDriver { + + /** + * Creates a AbstractXmlFriendlyDriver with default XmlFriendlyReplacer + * + * @deprecated As of 1.4 + */ + @Deprecated + public AbstractXmlDriver() { + this(new XmlFriendlyNameCoder()); + } + + /** + * Creates a AbstractXmlFriendlyDriver with default XmlFriendlyReplacer + * + * @since 1.4 + * @deprecated As of 1.4 + */ + @Deprecated + public AbstractXmlDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + /** + * Creates a AbstractXmlFriendlyDriver with custom XmlFriendlyReplacer + * + * @param replacer the XmlFriendlyReplacer + * @deprecated As of 1.4 + */ + @Deprecated + public AbstractXmlDriver(final XmlFriendlyReplacer replacer) { + this((NameCoder)replacer); + } + + /** + * @deprecated As of 1.4 + */ + @Deprecated + protected XmlFriendlyReplacer xmlFriendlyReplacer() { + final NameCoder nameCoder = getNameCoder(); + return nameCoder instanceof XmlFriendlyReplacer ? (XmlFriendlyReplacer)nameCoder : null; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXmlReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXmlReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXmlReader.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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 04. June 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.AbstractReader; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * Abstract base implementation of HierarchicalStreamReader that provides common functionality to all XML-based readers. + * + * @author Mauro Talevi + * @author Jörg Schaible + * @since 1.2 + * @deprecated As of 1.4, use {@link AbstractReader} instead. + */ +@Deprecated +public abstract class AbstractXmlReader extends AbstractReader /* implements XmlFriendlyReader */{ + + protected AbstractXmlReader() { + this(new XmlFriendlyNameCoder()); + } + + /** + * @deprecated As of 1.4, use {@link AbstractReader} instead. + */ + @Deprecated + protected AbstractXmlReader(final XmlFriendlyReplacer replacer) { + this((NameCoder)replacer); + } + + protected AbstractXmlReader(final NameCoder nameCoder) { + super(nameCoder); + } + + /** + * Unescapes XML-friendly name (node or attribute) + * + * @param name the escaped XML-friendly name + * @return An unescaped name with original characters + * @deprecated As of 1.4, use {@link #decodeNode(String)} or {@link #decodeAttribute(String)} instead. + */ + @Deprecated + public String unescapeXmlName(final String name) { + return decodeNode(name); + } + + /** + * Escapes XML-unfriendly name (node or attribute) + * + * @param name the unescaped XML-unfriendly name + * @return An escaped name with original characters + * @deprecated As of 1.4, use {@link AbstractReader} instead. + */ + @Deprecated + protected String escapeXmlName(final String name) { + return encodeNode(name); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXmlWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXmlWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXmlWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 04. June 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.AbstractWriter; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * Abstract base implementation of HierarchicalStreamWriter that provides common functionality to all XML-based writers. + * + * @author Mauro Talevi + * @author Jörg Schaible + * @since 1.2 + * @deprecated As of 1.4 use {@link AbstractWriter} instead + */ +@Deprecated +public abstract class AbstractXmlWriter extends AbstractWriter implements XmlFriendlyWriter { + + protected AbstractXmlWriter() { + this(new XmlFriendlyNameCoder()); + } + + /** + * @deprecated As of 1.4 + */ + @Deprecated + protected AbstractXmlWriter(final XmlFriendlyReplacer replacer) { + this((NameCoder)replacer); + } + + protected AbstractXmlWriter(final NameCoder nameCoder) { + super(nameCoder); + } + + /** + * Escapes XML name (node or attribute) to be XML-friendly + * + * @param name the unescaped XML name + * @return An escaped name with original characters replaced + * @deprecated As of 1.4 use {@link #encodeNode(String)} or {@link #encodeAttribute(String)} instead + */ + @Deprecated + @Override + public String escapeXmlName(final String name) { + return super.encodeNode(name); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXppDomDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXppDomDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXppDomDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 03. May 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import com.thoughtworks.xstream.core.util.XmlHeaderAwareReader; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.xml.xppdom.XppDom; + + +/** + * An abstract base class for a driver using an XPP DOM implementation. + * + * @author Joe Walnes + * @author Jörg Schaible + * @since 1.4 + */ +public abstract class AbstractXppDomDriver extends AbstractXmlDriver { + + /** + * Construct an AbstractXppDomDriver. + * + * @param nameCoder the replacer for XML friendly names + * @since 1.4 + */ + public AbstractXppDomDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + public HierarchicalStreamReader createReader(final Reader in) { + try { + final XmlPullParser parser = createParser(); + parser.setInput(in); + return new XppDomReader(XppDom.build(parser), getNameCoder()); + } catch (final XmlPullParserException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamReader createReader(final InputStream in) { + try { + return createReader(new XmlHeaderAwareReader(in)); + } catch (final UnsupportedEncodingException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { + return new PrettyPrintWriter(out, getNameCoder()); + } + + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { + return createWriter(new OutputStreamWriter(out)); + } + + /** + * Create the parser of the XPP implementation. + * + * @throws XmlPullParserException if the parser cannot be created + * @since 1.4 + */ + protected abstract XmlPullParser createParser() throws XmlPullParserException; +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXppDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXppDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/AbstractXppDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 29. April 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import com.thoughtworks.xstream.core.util.XmlHeaderAwareReader; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * An abstract base class for a driver using an XPP implementation. + * + * @author Joe Walnes + * @author Jörg Schaible + * @since 1.4 + */ +public abstract class AbstractXppDriver extends AbstractXmlDriver { + + /** + * Construct an AbstractXppDriver. + * + * @param nameCoder the replacer for XML friendly tag and attribute names + * @since 1.4 + */ + public AbstractXppDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + public HierarchicalStreamReader createReader(final Reader in) { + try { + return new XppReader(in, createParser(), getNameCoder()); + } catch (final XmlPullParserException e) { + throw new StreamException("Cannot create XmlPullParser"); + } + } + + @Override + public HierarchicalStreamReader createReader(final InputStream in) { + try { + return createReader(new XmlHeaderAwareReader(in)); + } catch (final UnsupportedEncodingException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { + return new PrettyPrintWriter(out, getNameCoder()); + } + + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { + return createWriter(new OutputStreamWriter(out)); + } + + /** + * Create the parser of the XPP implementation. + * + * @throws XmlPullParserException if the parser cannot be created + * @since 1.4 + */ + protected abstract XmlPullParser createParser() throws XmlPullParserException; +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/BEAStaxDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/BEAStaxDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/BEAStaxDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 29. April 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; + +import com.bea.xml.stream.MXParserFactory; +import com.bea.xml.stream.XMLOutputFactoryBase; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * A driver using the BEA StAX implementation. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class BEAStaxDriver extends StaxDriver { + + public BEAStaxDriver() { + super(); + } + + /** + * @deprecated As of 1.4.6 use {@link #BEAStaxDriver(QNameMap, NameCoder)} + */ + @Deprecated + public BEAStaxDriver(final QNameMap qnameMap, final XmlFriendlyNameCoder nameCoder) { + super(qnameMap, nameCoder); + } + + /** + * @since 1.4.6 + */ + public BEAStaxDriver(final QNameMap qnameMap, final NameCoder nameCoder) { + super(qnameMap, nameCoder); + } + + public BEAStaxDriver(final QNameMap qnameMap) { + super(qnameMap); + } + + /** + * @deprecated As of 1.4.6 use {@link #BEAStaxDriver(NameCoder)} + */ + @Deprecated + public BEAStaxDriver(final XmlFriendlyNameCoder nameCoder) { + super(nameCoder); + } + + /** + * @since 1.4.6 + */ + public BEAStaxDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + protected XMLInputFactory createInputFactory() { + return new MXParserFactory(); + } + + @Override + protected XMLOutputFactory createOutputFactory() { + return new XMLOutputFactoryBase(); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/CompactWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/CompactWriter.java (.../CompactWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/CompactWriter.java (.../CompactWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,13 +1,66 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; import java.io.Writer; +import com.thoughtworks.xstream.io.naming.NameCoder; + + public class CompactWriter extends PrettyPrintWriter { - public CompactWriter(Writer writer) { + public CompactWriter(final Writer writer) { super(writer); } + /** + * @since 1.3 + */ + public CompactWriter(final Writer writer, final int mode) { + super(writer, mode); + } + + /** + * @since 1.4 + */ + public CompactWriter(final Writer writer, final NameCoder nameCoder) { + super(writer, nameCoder); + } + + /** + * @since 1.4 + */ + public CompactWriter(final Writer writer, final int mode, final NameCoder nameCoder) { + super(writer, mode, nameCoder); + } + + /** + * @deprecated As of 1.4 use {@link CompactWriter#CompactWriter(Writer, NameCoder)} instead. + */ + @Deprecated + public CompactWriter(final Writer writer, final XmlFriendlyReplacer replacer) { + super(writer, replacer); + } + + /** + * @since 1.3 + * @deprecated As of 1.4 use {@link CompactWriter#CompactWriter(Writer, int, NameCoder)} instead. + */ + @Deprecated + public CompactWriter(final Writer writer, final int mode, final XmlFriendlyReplacer replacer) { + super(writer, mode, replacer); + } + + @Override protected void endOfLine() { // override parent: don't write anything at end of line } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DocumentReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DocumentReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DocumentReader.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2006, 2007 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 18. October 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + + +/** + * A generic interface for all {@link HierarchicalStreamReader} implementations reading a DOM. + * + * @author Jörg Schaible + * @since 1.2.1 + */ +public interface DocumentReader extends HierarchicalStreamReader { + + /** + * Retrieve the current processed node of the DOM. + * + * @return the current node + * @since 1.2.1 + */ + public Object getCurrent(); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DocumentWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DocumentWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DocumentWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2006, 2007, 2014 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 18. October 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import java.util.List; + +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * A generic interface for all {@link HierarchicalStreamWriter} implementations generating a DOM. + * + * @author Jörg Schaible + * @since 1.2.1 + */ +public interface DocumentWriter extends HierarchicalStreamWriter { + + /** + * Retrieve a {@link List} with the top elements. + *

    + * In the standard use case this list will only contain a single element. Additional elements can only occur, if + * {@link HierarchicalStreamWriter#startNode(String)} of the implementing {@link HierarchicalStreamWriter} was + * called multiple times with an empty node stack. Such a situation occurs calling + * {@link com.thoughtworks.xstream.XStream#marshal(Object, HierarchicalStreamWriter)} multiple times directly. + *

    + * + * @return a {@link List} with top nodes + * @since 1.2.1 + */ + List getTopLevelNodes(); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JDriver.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JDriver.java (.../Dom4JDriver.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JDriver.java (.../Dom4JDriver.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,105 +1,160 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.*; +import java.io.File; +import java.io.FilterWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; + import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentFactory; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; -import java.io.*; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; -public class Dom4JDriver implements HierarchicalStreamDriver { +public class Dom4JDriver extends AbstractXmlDriver { + private DocumentFactory documentFactory; private OutputFormat outputFormat; - public Dom4JDriver(DocumentFactory documentFactory, OutputFormat outputFormat) { + public Dom4JDriver() { + this(new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4 + */ + public Dom4JDriver(final NameCoder nameCoder) { + this(new DocumentFactory(), OutputFormat.createPrettyPrint(), nameCoder); + outputFormat.setTrimText(false); + } + + public Dom4JDriver(final DocumentFactory documentFactory, final OutputFormat outputFormat) { + this(documentFactory, outputFormat, new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4 + */ + public Dom4JDriver(final DocumentFactory documentFactory, final OutputFormat outputFormat, final NameCoder nameCoder) { + super(nameCoder); this.documentFactory = documentFactory; this.outputFormat = outputFormat; } - public Dom4JDriver() { - this(new DocumentFactory(), OutputFormat.createPrettyPrint()); + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link Dom4JDriver#Dom4JDriver(DocumentFactory, OutputFormat, NameCoder)} instead. + */ + @Deprecated + public Dom4JDriver( + final DocumentFactory documentFactory, final OutputFormat outputFormat, final XmlFriendlyReplacer replacer) { + this(documentFactory, outputFormat, (NameCoder)replacer); } public DocumentFactory getDocumentFactory() { return documentFactory; } - public void setDocumentFactory(DocumentFactory documentFactory) { + public void setDocumentFactory(final DocumentFactory documentFactory) { this.documentFactory = documentFactory; } public OutputFormat getOutputFormat() { return outputFormat; } - public void setOutputFormat(OutputFormat outputFormat) { + public void setOutputFormat(final OutputFormat outputFormat) { this.outputFormat = outputFormat; } - public HierarchicalStreamReader createReader(Reader text) { + @Override + public HierarchicalStreamReader createReader(final Reader text) { try { - SAXReader reader = new SAXReader(); - Document document = reader.read(text); - return new Dom4JReader(document); - } catch (DocumentException e) { + final SAXReader reader = new SAXReader(); + final Document document = reader.read(text); + return new Dom4JReader(document, getNameCoder()); + } catch (final DocumentException e) { throw new StreamException(e); } } - public HierarchicalStreamReader createReader(InputStream in) { + @Override + public HierarchicalStreamReader createReader(final InputStream in) { try { - SAXReader reader = new SAXReader(); - Document document = reader.read(in); - return new Dom4JReader(document); - } catch (DocumentException e) { + final SAXReader reader = new SAXReader(); + final Document document = reader.read(in); + return new Dom4JReader(document, getNameCoder()); + } catch (final DocumentException e) { throw new StreamException(e); } } - public HierarchicalStreamWriter createWriter(final Writer out) { - final Document document = documentFactory.createDocument(); - HierarchicalStreamWriter writer = new Dom4JWriter(document); + /** + * @since 1.4 + */ + @Override + public HierarchicalStreamReader createReader(final URL in) { + try { + final SAXReader reader = new SAXReader(); + final Document document = reader.read(in); + return new Dom4JReader(document, getNameCoder()); + } catch (final DocumentException e) { + throw new StreamException(e); + } + } - // Ensure that on writer.close(), the Document is written back to the text output. - writer = new WriterWrapper(writer) { - public void close() { - super.close(); - try { - XMLWriter writer = new XMLWriter(out, outputFormat); - writer.write(document); - writer.flush(); - } catch (IOException e) { - throw new StreamException(e); - } - } - }; - - return writer; + /** + * @since 1.4 + */ + @Override + public HierarchicalStreamReader createReader(final File in) { + try { + final SAXReader reader = new SAXReader(); + final Document document = reader.read(in); + return new Dom4JReader(document, getNameCoder()); + } catch (final DocumentException e) { + throw new StreamException(e); + } } - public HierarchicalStreamWriter createWriter(final OutputStream out) { - final Document document = documentFactory.createDocument(); - HierarchicalStreamWriter writer = new Dom4JWriter(document); - - // Ensure that on writer.close(), the Document is written back to the text output. - writer = new WriterWrapper(writer) { + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { + final HierarchicalStreamWriter[] writer = new HierarchicalStreamWriter[1]; + final FilterWriter filter = new FilterWriter(out) { + @Override public void close() { - super.close(); - try { - XMLWriter writer = new XMLWriter(out, outputFormat); - writer.write(document); - writer.flush(); - } catch (IOException e) { - throw new StreamException(e); - } + writer[0].close(); } }; - - return writer; + writer[0] = new Dom4JXmlWriter(new XMLWriter(filter, outputFormat), getNameCoder()); + return writer[0]; } + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { + final Writer writer = new OutputStreamWriter(out); + return createWriter(writer); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JReader.java (.../Dom4JReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JReader.java (.../Dom4JReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,64 +1,131 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.converters.ErrorWriter; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import java.util.List; + import org.dom4j.Document; import org.dom4j.Element; -import org.dom4j.Attribute; +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.io.naming.NameCoder; + + public class Dom4JReader extends AbstractDocumentReader { private Element currentElement; - public Dom4JReader(Element rootElement) { - super(rootElement); + public Dom4JReader(final Element rootElement) { + this(rootElement, new XmlFriendlyNameCoder()); } - public Dom4JReader(Document document) { + public Dom4JReader(final Document document) { this(document.getRootElement()); } + /** + * @since 1.4 + */ + public Dom4JReader(final Element rootElement, final NameCoder nameCoder) { + super(rootElement, nameCoder); + } + + /** + * @since 1.4 + */ + public Dom4JReader(final Document document, final NameCoder nameCoder) { + this(document.getRootElement(), nameCoder); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link Dom4JReader#Dom4JReader(Element, NameCoder)} instead + */ + @Deprecated + public Dom4JReader(final Element rootElement, final XmlFriendlyReplacer replacer) { + this(rootElement, (NameCoder)replacer); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link Dom4JReader#Dom4JReader(Document, NameCoder)} instead + */ + @Deprecated + public Dom4JReader(final Document document, final XmlFriendlyReplacer replacer) { + this(document.getRootElement(), (NameCoder)replacer); + } + + @Override public String getNodeName() { - return currentElement.getName(); + return decodeNode(currentElement.getName()); } + @Override public String getValue() { return currentElement.getText(); } - public String getAttribute(String name) { - return currentElement.attributeValue(name); + @Override + public String getAttribute(final String name) { + return currentElement.attributeValue(encodeAttribute(name)); } - public String getAttribute(int index) { + @Override + public String getAttribute(final int index) { return currentElement.attribute(index).getValue(); } + @Override public int getAttributeCount() { return currentElement.attributeCount(); } - public String getAttributeName(int index) { - return currentElement.attribute(index).getQualifiedName(); + @Override + public String getAttributeName(final int index) { + return decodeAttribute(currentElement.attribute(index).getQualifiedName()); } + @Override protected Object getParent() { return currentElement.getParent(); } - protected Object getChild(int index) { + @Override + protected Object getChild(final int index) { return currentElement.elements().get(index); } + @Override protected int getChildCount() { return currentElement.elements().size(); } - protected void reassignCurrentElement(Object current) { - currentElement = (Element) current; + @Override + protected void reassignCurrentElement(final Object current) { + currentElement = (Element)current; } - public void appendErrors(ErrorWriter errorWriter) { + @Override + public String peekNextChild() { + @SuppressWarnings("unchecked") + final List list = currentElement.elements(); + if (null == list || list.isEmpty()) { + return null; + } + return decodeNode(list.get(0).getName()); + } + + @Override + public void appendErrors(final ErrorWriter errorWriter) { errorWriter.add("xpath", currentElement.getPath()); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JWriter.java (.../Dom4JWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JWriter.java (.../Dom4JWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,52 +1,115 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import org.dom4j.Branch; import org.dom4j.DocumentFactory; import org.dom4j.Element; -import java.util.LinkedList; +import com.thoughtworks.xstream.io.naming.NameCoder; -public class Dom4JWriter implements HierarchicalStreamWriter { - private DocumentFactory documentFactory = new DocumentFactory(); - private LinkedList elementStack = new LinkedList(); +public class Dom4JWriter extends AbstractDocumentWriter { - public Dom4JWriter(Branch container) { - elementStack.addLast(container); + private final DocumentFactory documentFactory; + + /** + * @since 1.4 + */ + public Dom4JWriter(final Branch root, final DocumentFactory factory, final NameCoder nameCoder) { + super(root, nameCoder); + documentFactory = factory; } - public void startNode(String name) { - Element element = documentFactory.createElement(name); - top().add(element); - elementStack.addLast(element); + /** + * @since 1.4 + */ + public Dom4JWriter(final DocumentFactory factory, final NameCoder nameCoder) { + this(null, factory, nameCoder); } - public void setValue(String text) { - top().setText(text); + /** + * @since 1.4 + */ + public Dom4JWriter(final Branch root, final NameCoder nameCoder) { + this(root, new DocumentFactory(), nameCoder); } - public void addAttribute(String key, String value) { - ((Element) top()).addAttribute(key, value); + /** + * @since 1.2.1 + * @deprecated As of 1.4 use {@link Dom4JWriter#Dom4JWriter(Branch, DocumentFactory, NameCoder)} instead. + */ + @Deprecated + public Dom4JWriter(final Branch root, final DocumentFactory factory, final XmlFriendlyReplacer replacer) { + this(root, factory, (NameCoder)replacer); } - public void endNode() { - elementStack.removeLast(); + /** + * @since 1.2.1 + * @deprecated As of 1.4 use {@link Dom4JWriter#Dom4JWriter(DocumentFactory, NameCoder)} instead. + */ + @Deprecated + public Dom4JWriter(final DocumentFactory factory, final XmlFriendlyReplacer replacer) { + this(null, factory, (NameCoder)replacer); } - private Branch top() { - return (Branch) elementStack.getLast(); + /** + * @since 1.2.1 + */ + public Dom4JWriter(final DocumentFactory documentFactory) { + this(documentFactory, new XmlFriendlyNameCoder()); } - public void flush() { - // don't need to do anything + /** + * @since 1.2.1 + * @deprecated As of 1.4 use {@link Dom4JWriter#Dom4JWriter(Branch, NameCoder)} instead + */ + @Deprecated + public Dom4JWriter(final Branch root, final XmlFriendlyReplacer replacer) { + this(root, new DocumentFactory(), (NameCoder)replacer); } - public void close() { - // don't need to do anything + public Dom4JWriter(final Branch root) { + this(root, new DocumentFactory(), new XmlFriendlyNameCoder()); } - public HierarchicalStreamWriter underlyingWriter() { - return this; + /** + * @since 1.2.1 + */ + public Dom4JWriter() { + this(new DocumentFactory(), new XmlFriendlyNameCoder()); } + + @Override + protected Object createNode(final String name) { + final Element element = documentFactory.createElement(encodeNode(name)); + final Branch top = top(); + if (top != null) { + top().add(element); + } + return element; + } + + @Override + public void setValue(final String text) { + top().setText(text); + } + + @Override + public void addAttribute(final String key, final String value) { + ((Element)top()).addAttribute(encodeAttribute(key), value); + } + + private Branch top() { + return (Branch)getCurrent(); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JXmlWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JXmlWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Dom4JXmlWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ +package com.thoughtworks.xstream.io.xml; + +import java.io.IOException; + +import org.dom4j.Element; +import org.dom4j.io.XMLWriter; +import org.dom4j.tree.DefaultElement; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +import com.thoughtworks.xstream.core.util.FastStack; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +public class Dom4JXmlWriter extends AbstractXmlWriter { + + private final XMLWriter writer; + private final FastStack elementStack; + private final AttributesImpl attributes; + private boolean started; + private boolean children; + + public Dom4JXmlWriter(final XMLWriter writer) { + this(writer, new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4 + */ + public Dom4JXmlWriter(final XMLWriter writer, final NameCoder nameCoder) { + super(nameCoder); + this.writer = writer; + elementStack = new FastStack(16); + attributes = new AttributesImpl(); + try { + writer.startDocument(); + } catch (final SAXException e) { + throw new StreamException(e); + } + } + + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link Dom4JXmlWriter#Dom4JXmlWriter(XMLWriter, NameCoder)} instead. + */ + @Deprecated + public Dom4JXmlWriter(final XMLWriter writer, final XmlFriendlyReplacer replacer) { + this(writer, (NameCoder)replacer); + } + + @Override + public void startNode(final String name) { + if (elementStack.size() > 0) { + try { + startElement(); + } catch (final SAXException e) { + throw new StreamException(e); + } + started = false; + } + elementStack.push(encodeNode(name)); + children = false; + } + + @Override + public void setValue(final String text) { + final char[] value = text.toCharArray(); + if (value.length > 0) { + try { + startElement(); + writer.characters(value, 0, value.length); + } catch (final SAXException e) { + throw new StreamException(e); + } + children = true; + } + } + + @Override + public void addAttribute(final String key, final String value) { + attributes.addAttribute("", "", encodeAttribute(key), "string", value); + } + + @Override + public void endNode() { + try { + if (!children) { + final Element element = new DefaultElement(elementStack.pop()); + for (int i = 0; i < attributes.getLength(); ++i) { + element.addAttribute(attributes.getQName(i), attributes.getValue(i)); + } + writer.write(element); + attributes.clear(); + children = true; // node just closed is child of node on top of stack + started = true; + } else { + startElement(); + writer.endElement("", "", elementStack.pop()); + } + } catch (final SAXException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public void flush() { + try { + writer.flush(); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public void close() { + try { + writer.endDocument(); + } catch (final SAXException e) { + throw new StreamException(e); + } + } + + private void startElement() throws SAXException { + if (!started) { + writer.startElement("", "", elementStack.peek(), attributes); + attributes.clear(); + started = true; + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomDriver.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomDriver.java (.../DomDriver.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomDriver.java (.../DomDriver.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,60 +1,129 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.*; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.net.URL; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; -import java.io.*; -public class DomDriver implements HierarchicalStreamDriver { +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +public class DomDriver extends AbstractXmlDriver { + private final String encoding; private final DocumentBuilderFactory documentBuilderFactory; - public DomDriver(String encoding) { + /** + * Construct a DomDriver. + */ + public DomDriver() { + this(null); + } + + /** + * Construct a DomDriver with a specified encoding. The created DomReader will ignore any encoding attribute of the + * XML header though. + */ + public DomDriver(final String encoding) { + this(encoding, new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4 + */ + public DomDriver(final String encoding, final NameCoder nameCoder) { + super(nameCoder); documentBuilderFactory = DocumentBuilderFactory.newInstance(); this.encoding = encoding; } - public DomDriver() { - this("UTF-8"); + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link #DomDriver(String, NameCoder)} instead. + */ + @Deprecated + public DomDriver(final String encoding, final XmlFriendlyReplacer replacer) { + this(encoding, (NameCoder)replacer); } - public HierarchicalStreamReader createReader(Reader xml) { - return createReader(new InputSource(xml)); + @Override + public HierarchicalStreamReader createReader(final Reader in) { + return createReader(new InputSource(in)); } - public HierarchicalStreamReader createReader(InputStream xml) { - return createReader(new InputSource(xml)); + @Override + public HierarchicalStreamReader createReader(final InputStream in) { + return createReader(new InputSource(in)); } - private HierarchicalStreamReader createReader(InputSource source) { + @Override + public HierarchicalStreamReader createReader(final URL in) { + return createReader(new InputSource(in.toExternalForm())); + } + + @Override + public HierarchicalStreamReader createReader(final File in) { + return createReader(new InputSource(in.toURI().toASCIIString())); + } + + private HierarchicalStreamReader createReader(final InputSource source) { try { - DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); - source.setEncoding(encoding); - Document document = documentBuilder.parse(source); - return new DomReader(document); - } catch (FactoryConfigurationError e) { + final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + if (encoding != null) { + source.setEncoding(encoding); + } + final Document document = documentBuilder.parse(source); + return new DomReader(document, getNameCoder()); + } catch (final FactoryConfigurationError e) { throw new StreamException(e); - } catch (ParserConfigurationException e) { + } catch (final ParserConfigurationException e) { throw new StreamException(e); - } catch (SAXException e) { + } catch (final SAXException e) { throw new StreamException(e); - } catch (IOException e) { + } catch (final IOException e) { throw new StreamException(e); } } - public HierarchicalStreamWriter createWriter(Writer out) { - return new PrettyPrintWriter(out); + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { + return new PrettyPrintWriter(out, getNameCoder()); } - public HierarchicalStreamWriter createWriter(OutputStream out) { - return createWriter(new OutputStreamWriter(out)); + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { + try { + return createWriter(encoding != null ? new OutputStreamWriter(out, encoding) : new OutputStreamWriter(out)); + } catch (final UnsupportedEncodingException e) { + throw new StreamException(e); + } } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomReader.java (.../DomReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomReader.java (.../DomReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,89 +1,154 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; +import java.util.ArrayList; +import java.util.List; + import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; -import java.util.ArrayList; -import java.util.List; +import com.thoughtworks.xstream.io.naming.NameCoder; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; public class DomReader extends AbstractDocumentReader { private Element currentElement; - private StringBuffer textBuffer; - private List childElements; + private final StringBuilder textBuffer; + private List childElements; - public DomReader(Element rootElement) { - super(rootElement); - textBuffer = new StringBuffer(); + public DomReader(final Element rootElement) { + this(rootElement, new XmlFriendlyNameCoder()); } - public DomReader(Document document) { + public DomReader(final Document document) { this(document.getDocumentElement()); } + /** + * @since 1.4 + */ + public DomReader(final Element rootElement, final NameCoder nameCoder) { + super(rootElement, nameCoder); + textBuffer = new StringBuilder(); + } + + /** + * @since 1.4 + */ + public DomReader(final Document document, final NameCoder nameCoder) { + this(document.getDocumentElement(), nameCoder); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link DomReader#DomReader(Element, NameCoder)} instead. + */ + @Deprecated + public DomReader(final Element rootElement, final XmlFriendlyReplacer replacer) { + this(rootElement, (NameCoder)replacer); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link DomReader#DomReader(Document, NameCoder)} instead. + */ + @Deprecated + public DomReader(final Document document, final XmlFriendlyReplacer replacer) { + this(document.getDocumentElement(), (NameCoder)replacer); + } + + @Override public String getNodeName() { - return currentElement.getTagName(); + return decodeNode(currentElement.getTagName()); } + @Override public String getValue() { - NodeList childNodes = currentElement.getChildNodes(); + final NodeList childNodes = currentElement.getChildNodes(); textBuffer.setLength(0); - int length = childNodes.getLength(); + final int length = childNodes.getLength(); for (int i = 0; i < length; i++) { - Node childNode = childNodes.item(i); + final Node childNode = childNodes.item(i); if (childNode instanceof Text) { - Text text = (Text) childNode; + final Text text = (Text)childNode; textBuffer.append(text.getData()); } } return textBuffer.toString(); } - public String getAttribute(String name) { - Attr attribute = currentElement.getAttributeNode(name); + @Override + public String getAttribute(final String name) { + final Attr attribute = currentElement.getAttributeNode(encodeAttribute(name)); return attribute == null ? null : attribute.getValue(); } - public String getAttribute(int index) { - return ((Attr) currentElement.getAttributes().item(index)).getValue(); + @Override + public String getAttribute(final int index) { + return ((Attr)currentElement.getAttributes().item(index)).getValue(); } + @Override public int getAttributeCount() { return currentElement.getAttributes().getLength(); } - public String getAttributeName(int index) { - return ((Attr) currentElement.getAttributes().item(index)).getName(); + @Override + public String getAttributeName(final int index) { + return decodeAttribute(((Attr)currentElement.getAttributes().item(index)).getName()); } + @Override protected Object getParent() { return currentElement.getParentNode(); } - protected Object getChild(int index) { + @Override + protected Object getChild(final int index) { return childElements.get(index); } + @Override protected int getChildCount() { return childElements.size(); } - protected void reassignCurrentElement(Object current) { - currentElement = (Element) current; - NodeList childNodes = currentElement.getChildNodes(); - childElements = new ArrayList(); + @Override + protected void reassignCurrentElement(final Object current) { + currentElement = (Element)current; + final NodeList childNodes = currentElement.getChildNodes(); + childElements = new ArrayList(); for (int i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); + final Node node = childNodes.item(i); if (node instanceof Element) { - childElements.add(node); + childElements.add((Element)node); } } } + @Override + public String peekNextChild() { + final NodeList childNodes = currentElement.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + final Node node = childNodes.item(i); + if (node instanceof Element) { + return decodeNode(((Element)node).getTagName()); + } + } + return null; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomWriter.java (.../DomWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/DomWriter.java (.../DomWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,59 +1,112 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 02. September 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.Node; +import com.thoughtworks.xstream.io.naming.NameCoder; + + /** * @author Michael Kopp */ -public class DomWriter implements HierarchicalStreamWriter { +public class DomWriter extends AbstractDocumentWriter { + private final Document document; - private Element current; + private boolean hasRootElement; - public DomWriter(Document document) { + public DomWriter(final Document document) { + this(document, new XmlFriendlyNameCoder()); + } + + public DomWriter(final Element rootElement) { + this(rootElement, new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4 + */ + public DomWriter(final Document document, final NameCoder nameCoder) { + this(document.getDocumentElement(), document, nameCoder); + } + + /** + * @since 1.4 + */ + public DomWriter(final Element element, final Document document, final NameCoder nameCoder) { + super(element, nameCoder); this.document = document; - this.current = document.getDocumentElement(); + hasRootElement = document.getDocumentElement() != null; } - public DomWriter(Element rootElement) { - document = rootElement.getOwnerDocument(); - current = rootElement; + /** + * @since 1.4 + */ + public DomWriter(final Element rootElement, final NameCoder nameCoder) { + this(rootElement, rootElement.getOwnerDocument(), nameCoder); } - public void startNode(String name) { - final Element child = document.createElement(name); - if (current == null) { - document.appendChild(child); - } else { - current.appendChild(child); - } - current = child; + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link DomWriter#DomWriter(Document, NameCoder)} instead. + */ + @Deprecated + public DomWriter(final Document document, final XmlFriendlyReplacer replacer) { + this(document.getDocumentElement(), document, (NameCoder)replacer); } - public void addAttribute(String name, String value) { - current.setAttribute(name, value); + /** + * @since 1.2.1 + * @deprecated As of 1.4 use {@link DomWriter#DomWriter(Element, Document, NameCoder)} instead. + */ + @Deprecated + public DomWriter(final Element element, final Document document, final XmlFriendlyReplacer replacer) { + this(element, document, (NameCoder)replacer); } - public void setValue(String text) { - current.appendChild(document.createTextNode(text)); + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link DomWriter#DomWriter(Element, NameCoder)} instead. + */ + @Deprecated + public DomWriter(final Element rootElement, final XmlFriendlyReplacer replacer) { + this(rootElement, rootElement.getOwnerDocument(), (NameCoder)replacer); } - public void endNode() { - Node parent = current.getParentNode(); - current = parent instanceof Element ? (Element)parent : null; + @Override + protected Object createNode(final String name) { + final Element child = document.createElement(encodeNode(name)); + final Element top = top(); + if (top != null) { + top().appendChild(child); + } else if (!hasRootElement) { + document.appendChild(child); + hasRootElement = true; + } + return child; } - public void flush() { - // don't need to do anything + @Override + public void addAttribute(final String name, final String value) { + top().setAttribute(encodeAttribute(name), value); } - public void close() { - // don't need to do anything + @Override + public void setValue(final String text) { + top().appendChild(document.createTextNode(text)); } - public HierarchicalStreamWriter underlyingWriter() { - return this; + private Element top() { + return (Element)getCurrent(); } -} \ No newline at end of file +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDom2Driver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDom2Driver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDom2Driver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2013, 2014 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 24. June 2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; + +import org.jdom2.Document; +import org.jdom2.JDOMException; +import org.jdom2.input.SAXBuilder; + +import com.thoughtworks.xstream.io.AbstractDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * @since 1.4.5 + */ +public class JDom2Driver extends AbstractDriver { + + public JDom2Driver() { + super(new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4.5 + */ + public JDom2Driver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + public HierarchicalStreamReader createReader(final Reader reader) { + try { + final SAXBuilder builder = new SAXBuilder(); + final Document document = builder.build(reader); + return new JDom2Reader(document, getNameCoder()); + } catch (final IOException e) { + throw new StreamException(e); + } catch (final JDOMException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamReader createReader(final InputStream in) { + try { + final SAXBuilder builder = new SAXBuilder(); + final Document document = builder.build(in); + return new JDom2Reader(document, getNameCoder()); + } catch (final IOException e) { + throw new StreamException(e); + } catch (final JDOMException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamReader createReader(final URL in) { + try { + final SAXBuilder builder = new SAXBuilder(); + final Document document = builder.build(in); + return new JDom2Reader(document, getNameCoder()); + } catch (final IOException e) { + throw new StreamException(e); + } catch (final JDOMException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamReader createReader(final File in) { + try { + final SAXBuilder builder = new SAXBuilder(); + final Document document = builder.build(in); + return new JDom2Reader(document, getNameCoder()); + } catch (final IOException e) { + throw new StreamException(e); + } catch (final JDOMException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { + return new PrettyPrintWriter(out, getNameCoder()); + } + + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { + return new PrettyPrintWriter(new OutputStreamWriter(out)); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDom2Reader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDom2Reader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDom2Reader.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2013, 2014 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 24. June 2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import java.util.List; + +import org.jdom2.Document; +import org.jdom2.Element; + +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * @since 1.4.5 + */ +public class JDom2Reader extends AbstractDocumentReader { + + private Element currentElement; + + /** + * @since 1.4.5 + */ + public JDom2Reader(final Element root) { + super(root); + } + + /** + * @since 1.4.5 + */ + public JDom2Reader(final Document document) { + super(document.getRootElement()); + } + + /** + * @since 1.4.5 + */ + public JDom2Reader(final Element root, final NameCoder nameCoder) { + super(root, nameCoder); + } + + /** + * @since 1.4.5 + */ + public JDom2Reader(final Document document, final NameCoder nameCoder) { + super(document.getRootElement(), nameCoder); + } + + @Override + protected void reassignCurrentElement(final Object current) { + currentElement = (Element)current; + } + + @Override + protected Object getParent() { + return currentElement.getParentElement(); + } + + @Override + protected Object getChild(final int index) { + return currentElement.getChildren().get(index); + } + + @Override + protected int getChildCount() { + return currentElement.getChildren().size(); + } + + @Override + public String getNodeName() { + return decodeNode(currentElement.getName()); + } + + @Override + public String getValue() { + return currentElement.getText(); + } + + @Override + public String getAttribute(final String name) { + return currentElement.getAttributeValue(encodeAttribute(name)); + } + + @Override + public String getAttribute(final int index) { + return currentElement.getAttributes().get(index).getValue(); + } + + @Override + public int getAttributeCount() { + return currentElement.getAttributes().size(); + } + + @Override + public String getAttributeName(final int index) { + return decodeAttribute(currentElement.getAttributes().get(index).getQualifiedName()); + } + + @Override + public String peekNextChild() { + final List list = currentElement.getChildren(); + if (null == list || list.isEmpty()) { + return null; + } + return decodeNode(list.get(0).getName()); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDom2Writer.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDom2Writer.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDom2Writer.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2013, 2014 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 24. June 2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import org.jdom2.DefaultJDOMFactory; +import org.jdom2.Element; +import org.jdom2.JDOMFactory; + +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * @since 1.4.5 + */ +public class JDom2Writer extends AbstractDocumentWriter { + + private final JDOMFactory documentFactory; + + /** + * @since 1.4.5 + */ + public JDom2Writer(final Element container, final JDOMFactory factory, final NameCoder nameCoder) { + super(container, nameCoder); + documentFactory = factory; + } + + /** + * @since 1.4.5 + */ + public JDom2Writer(final Element container, final JDOMFactory factory) { + this(container, factory, new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4.5 + */ + public JDom2Writer(final JDOMFactory factory, final NameCoder nameCoder) { + this(null, factory, nameCoder); + } + + /** + * @since 1.4.5 + */ + public JDom2Writer(final JDOMFactory factory) { + this(null, factory); + } + + /** + * @since 1.4.5 + */ + public JDom2Writer(final Element container, final NameCoder nameCoder) { + this(container, new DefaultJDOMFactory(), nameCoder); + } + + /** + * @since 1.4.5 + */ + public JDom2Writer(final Element container) { + this(container, new DefaultJDOMFactory()); + } + + /** + * @since 1.4.5 + */ + public JDom2Writer() { + this(new DefaultJDOMFactory()); + } + + @Override + protected Object createNode(final String name) { + final Element element = documentFactory.element(encodeNode(name)); + final Element parent = top(); + if (parent != null) { + parent.addContent(element); + } + return element; + } + + @Override + public void setValue(final String text) { + top().addContent(documentFactory.text(text)); + } + + @Override + public void addAttribute(final String key, final String value) { + top().setAttribute(documentFactory.attribute(encodeAttribute(key), value)); + } + + /** + * @since 1.4.5 + */ + private Element top() { + return (Element)getCurrent(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomDriver.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomDriver.java (.../JDomDriver.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomDriver.java (.../JDomDriver.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,52 +1,120 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 03. September 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import java.io.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; import org.jdom.Document; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; -import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import com.thoughtworks.xstream.io.StreamException; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + /** * @author Laurent Bihanic */ -public class JDomDriver implements HierarchicalStreamDriver { +public class JDomDriver extends AbstractXmlDriver { - public HierarchicalStreamReader createReader(Reader reader) { + public JDomDriver() { + super(new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4 + */ + public JDomDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link JDomDriver#JDomDriver(NameCoder)} instead. + */ + @Deprecated + public JDomDriver(final XmlFriendlyReplacer replacer) { + this((NameCoder)replacer); + } + + @Override + public HierarchicalStreamReader createReader(final Reader reader) { try { - SAXBuilder builder = new SAXBuilder(); - Document document = builder.build(reader); - return new JDomReader(document); - } catch (IOException e) { + final SAXBuilder builder = new SAXBuilder(); + final Document document = builder.build(reader); + return new JDomReader(document, getNameCoder()); + } catch (final IOException e) { throw new StreamException(e); - } catch (JDOMException e) { + } catch (final JDOMException e) { throw new StreamException(e); } } - public HierarchicalStreamReader createReader(InputStream in) { + @Override + public HierarchicalStreamReader createReader(final InputStream in) { try { - SAXBuilder builder = new SAXBuilder(); - Document document = builder.build(in); - return new JDomReader(document); - } catch (IOException e) { + final SAXBuilder builder = new SAXBuilder(); + final Document document = builder.build(in); + return new JDomReader(document, getNameCoder()); + } catch (final IOException e) { throw new StreamException(e); - } catch (JDOMException e) { + } catch (final JDOMException e) { throw new StreamException(e); } } - public HierarchicalStreamWriter createWriter(Writer out) { - return new PrettyPrintWriter(out); + @Override + public HierarchicalStreamReader createReader(final URL in) { + try { + final SAXBuilder builder = new SAXBuilder(); + final Document document = builder.build(in); + return new JDomReader(document, getNameCoder()); + } catch (final IOException e) { + throw new StreamException(e); + } catch (final JDOMException e) { + throw new StreamException(e); + } } - public HierarchicalStreamWriter createWriter(OutputStream out) { + @Override + public HierarchicalStreamReader createReader(final File in) { + try { + final SAXBuilder builder = new SAXBuilder(); + final Document document = builder.build(in); + return new JDomReader(document, getNameCoder()); + } catch (final IOException e) { + throw new StreamException(e); + } catch (final JDOMException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { + return new PrettyPrintWriter(out, getNameCoder()); + } + + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { return new PrettyPrintWriter(new OutputStreamWriter(out)); } } - Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomReader.java (.../JDomReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomReader.java (.../JDomReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,29 +1,78 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 03. September 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; +import java.util.List; + +import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; -import org.jdom.Parent; -import org.jdom.Attribute; +import com.thoughtworks.xstream.io.naming.NameCoder; + + /** * @author Laurent Bihanic */ public class JDomReader extends AbstractDocumentReader { private Element currentElement; - public JDomReader(Element root) { + public JDomReader(final Element root) { super(root); } - public JDomReader(Document document) { + public JDomReader(final Document document) { super(document.getRootElement()); } - protected void reassignCurrentElement(Object current) { - currentElement = (Element) current; + /** + * @since 1.4 + */ + public JDomReader(final Element root, final NameCoder nameCoder) { + super(root, nameCoder); } + /** + * @since 1.4 + */ + public JDomReader(final Document document, final NameCoder nameCoder) { + super(document.getRootElement(), nameCoder); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link JDomReader#JDomReader(Element, NameCoder)} instead. + */ + @Deprecated + public JDomReader(final Element root, final XmlFriendlyReplacer replacer) { + this(root, (NameCoder)replacer); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link JDomReader#JDomReader(Document, NameCoder)} instead. + */ + @Deprecated + public JDomReader(final Document document, final XmlFriendlyReplacer replacer) { + this(document.getRootElement(), (NameCoder)replacer); + } + + @Override + protected void reassignCurrentElement(final Object current) { + currentElement = (Element)current; + } + + @Override protected Object getParent() { // JDOM 1.0: return currentElement.getParentElement(); @@ -36,36 +85,54 @@ // return currentElement.getParent(); } - protected Object getChild(int index) { + @Override + protected Object getChild(final int index) { return currentElement.getChildren().get(index); } + @Override protected int getChildCount() { return currentElement.getChildren().size(); } + @Override public String getNodeName() { - return currentElement.getName(); + return decodeNode(currentElement.getName()); } + @Override public String getValue() { return currentElement.getText(); } - public String getAttribute(String name) { - return currentElement.getAttributeValue(name); + @Override + public String getAttribute(final String name) { + return currentElement.getAttributeValue(encodeAttribute(name)); } - public String getAttribute(int index) { - return ((Attribute) currentElement.getAttributes().get(index)).getValue(); + @Override + public String getAttribute(final int index) { + return ((Attribute)currentElement.getAttributes().get(index)).getValue(); } + @Override public int getAttributeCount() { return currentElement.getAttributes().size(); } - public String getAttributeName(int index) { - return ((Attribute) currentElement.getAttributes().get(index)).getQualifiedName(); + @Override + public String getAttributeName(final int index) { + return decodeAttribute(((Attribute)currentElement.getAttributes().get(index)).getQualifiedName()); } -} + @Override + public String peekNextChild() { + @SuppressWarnings("unchecked") + final List list = currentElement.getChildren(); + if (null == list || list.isEmpty()) { + return null; + } + return decodeNode(list.get(0).getName()); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomWriter.java (.../JDomWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/JDomWriter.java (.../JDomWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,89 +1,116 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 03. September 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import java.util.List; -import java.util.LinkedList; - +import org.jdom.DefaultJDOMFactory; import org.jdom.Element; import org.jdom.JDOMFactory; -import org.jdom.DefaultJDOMFactory; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.naming.NameCoder; + /** * @author Laurent Bihanic */ -public class JDomWriter implements HierarchicalStreamWriter { +public class JDomWriter extends AbstractDocumentWriter { - private List result = new LinkedList(); - private List elementStack = new LinkedList(); private final JDOMFactory documentFactory; - public JDomWriter(Element container, JDOMFactory factory) { - elementStack.add(0, container); - result.add(container); - this.documentFactory = factory; + /** + * @since 1.4 + */ + public JDomWriter(final Element container, final JDOMFactory factory, final NameCoder nameCoder) { + super(container, nameCoder); + documentFactory = factory; } - public JDomWriter(JDOMFactory documentFactory) { - this.documentFactory = documentFactory; + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link JDomWriter#JDomWriter(Element, JDOMFactory, NameCoder)} instead. + */ + @Deprecated + public JDomWriter(final Element container, final JDOMFactory factory, final XmlFriendlyReplacer replacer) { + this(container, factory, (NameCoder)replacer); } - public JDomWriter(Element container) { - this(container, new DefaultJDOMFactory()); + public JDomWriter(final Element container, final JDOMFactory factory) { + this(container, factory, new XmlFriendlyNameCoder()); } - public JDomWriter() { - this(new DefaultJDOMFactory()); + /** + * @since 1.4 + */ + public JDomWriter(final JDOMFactory factory, final NameCoder nameCoder) { + this(null, factory, nameCoder); } - public void startNode(String name) { - Element element = this.documentFactory.element(name); + /** + * @since 1.2.1 + * @deprecated As of 1.4 use {@link JDomWriter#JDomWriter(JDOMFactory, NameCoder)} instead. + */ + @Deprecated + public JDomWriter(final JDOMFactory factory, final XmlFriendlyReplacer replacer) { + this(null, factory, (NameCoder)replacer); + } - Element parent = this.top(); - if (parent != null) { - parent.addContent(element); - } - else { - result.add(element); - } - elementStack.add(0, element); + public JDomWriter(final JDOMFactory factory) { + this(null, factory); } - public void setValue(String text) { - top().addContent(this.documentFactory.text(text)); + /** + * @since 1.4 + */ + public JDomWriter(final Element container, final NameCoder nameCoder) { + this(container, new DefaultJDOMFactory(), nameCoder); } - public void addAttribute(String key, String value) { - top().setAttribute( - this.documentFactory.attribute(key, value)); + /** + * @since 1.2.1 + * @deprecated As of 1.4 use {@link JDomWriter#JDomWriter(Element, NameCoder)} instead. + */ + @Deprecated + public JDomWriter(final Element container, final XmlFriendlyReplacer replacer) { + this(container, new DefaultJDOMFactory(), (NameCoder)replacer); } - public void endNode() { - this.elementStack.remove(0); + public JDomWriter(final Element container) { + this(container, new DefaultJDOMFactory()); } - private Element top() { - Element top = null; + public JDomWriter() { + this(new DefaultJDOMFactory()); + } - if (this.elementStack.isEmpty() == false) { - top = (Element) this.elementStack.get(0); + @Override + protected Object createNode(final String name) { + final Element element = documentFactory.element(encodeNode(name)); + final Element parent = top(); + if (parent != null) { + parent.addContent(element); } - return top; + return element; } - public List getResult() { - return this.result; + @Override + public void setValue(final String text) { + top().addContent(documentFactory.text(text)); } - public void flush() { - // don't need to do anything + @Override + public void addAttribute(final String key, final String value) { + top().setAttribute(documentFactory.attribute(encodeAttribute(key), value)); } - public void close() { - // don't need to do anything + private Element top() { + return (Element)getCurrent(); } - - public HierarchicalStreamWriter underlyingWriter() { - return this; - } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/KXml2DomDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/KXml2DomDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/KXml2DomDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 03. May 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import org.kxml2.io.KXmlParser; +import org.xmlpull.v1.XmlPullParser; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * A {@link HierarchicalStreamDriver} for XPP DOM using the kXML2 parser. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class KXml2DomDriver extends AbstractXppDomDriver { + + /** + * Construct an KXml2DomDriver. + * + * @since 1.4 + */ + public KXml2DomDriver() { + super(new XmlFriendlyNameCoder()); + } + + /** + * Construct a KXml2DomDriver. + * + * @param nameCoder the replacer for XML friendly names + * @since 1.4 + */ + public KXml2DomDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + /** + * {@inheritDoc} + */ + @Override + protected XmlPullParser createParser() { + return new KXmlParser(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/KXml2Driver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/KXml2Driver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/KXml2Driver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 29. April 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import org.kxml2.io.KXmlParser; +import org.xmlpull.v1.XmlPullParser; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * A {@link HierarchicalStreamDriver} using the kXML2 parser. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class KXml2Driver extends AbstractXppDriver { + + /** + * Construct a KXml2Driver. + * + * @since 1.4 + */ + public KXml2Driver() { + super(new XmlFriendlyNameCoder()); + } + + /** + * Construct a KXml2Driver. + * + * @param nameCoder the replacer for XML friendly names + * @since 1.4 + */ + public KXml2Driver(final NameCoder nameCoder) { + super(nameCoder); + } + + /** + * {@inheritDoc} + */ + @Override + protected XmlPullParser createParser() { + return new KXmlParser(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java (.../PrettyPrintWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java (.../PrettyPrintWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,122 +1,281 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; +import java.io.Writer; + import com.thoughtworks.xstream.core.util.FastStack; import com.thoughtworks.xstream.core.util.QuickWriter; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; -import java.io.Writer; /** * A simple writer that outputs XML in a pretty-printed indented stream. - * - *

    By default, the chars

    & < > " ' \r are escaped and replaced with a suitable XML entity. - * To alter this behavior, override the the {@link #writeText(com.thoughtworks.xstream.core.util.QuickWriter, String)} - * and {@link #writeAttributeValue(com.thoughtworks.xstream.core.util.QuickWriter, String)} methods.

    - * + *

    + * By default, the chars
    + * & < > " ' \r
    + * are escaped and replaced with a suitable XML entity. To alter this behavior, override the + * {@link #writeText(com.thoughtworks.xstream.core.util.QuickWriter, String)} and + * {@link #writeAttributeValue(com.thoughtworks.xstream.core.util.QuickWriter, String)} methods. + *

    + *

    + * The XML specification requires XML parsers to drop CR characters completely. This implementation will therefore use + * only a LF for line endings, never the platform encoding. You can overwrite the {@link #getNewLine()} method for a + * different behavior. + *

    + *

    + * Note: Depending on the XML version some characters cannot be written. Especially a 0 character is never valid in XML, + * neither directly nor as entity nor within CDATA. However, this writer works by default in a quirks mode, where it + * will write any character at least as character entity (even a null character). You may switch into XML_1_1 mode + * (which supports most characters) or XML_1_0 that does only support a very limited number of control characters. See + * XML specification for version 1.0 or 1.1. If a character is not supported, a + * {@link StreamException} is thrown. Select a proper parser implementation that respects the version in the XML header + * (the Xpp3 parser will also read character entities of normally invalid characters). + *

    + * * @author Joe Walnes + * @author Jörg Schaible */ -public class PrettyPrintWriter implements HierarchicalStreamWriter { +public class PrettyPrintWriter extends AbstractXmlWriter { + public static int XML_QUIRKS = -1; + public static int XML_1_0 = 0; + public static int XML_1_1 = 1; + private final QuickWriter writer; - private final FastStack elementStack = new FastStack(16); + private final FastStack elementStack = new FastStack(16); private final char[] lineIndenter; + private final int mode; private boolean tagInProgress; - private int depth; + protected int depth; private boolean readyForNewLine; private boolean tagIsEmpty; private static final char[] NULL = "�".toCharArray(); private static final char[] AMP = "&".toCharArray(); private static final char[] LT = "<".toCharArray(); private static final char[] GT = ">".toCharArray(); - private static final char[] SLASH_R = " ".toCharArray(); + private static final char[] CR = " ".toCharArray(); private static final char[] QUOT = """.toCharArray(); private static final char[] APOS = "'".toCharArray(); private static final char[] CLOSE = " XML_1_1) { + throw new IllegalArgumentException("Not a valid XML mode"); + } } - public PrettyPrintWriter(Writer writer, String lineIndenter) { + /** + * @since 1.3 + * @deprecated As of 1.4 use {@link PrettyPrintWriter#PrettyPrintWriter(Writer, int, char[], NameCoder)} instead + */ + @Deprecated + public PrettyPrintWriter( + final Writer writer, final int mode, final char[] lineIndenter, final XmlFriendlyReplacer replacer) { + this(writer, mode, lineIndenter, (NameCoder)replacer); + } + + /** + * @since 1.3 + */ + public PrettyPrintWriter(final Writer writer, final int mode, final char[] lineIndenter) { + this(writer, mode, lineIndenter, new XmlFriendlyNameCoder()); + } + + public PrettyPrintWriter(final Writer writer, final char[] lineIndenter) { + this(writer, XML_QUIRKS, lineIndenter); + } + + /** + * @since 1.3 + */ + public PrettyPrintWriter(final Writer writer, final int mode, final String lineIndenter) { + this(writer, mode, lineIndenter.toCharArray()); + } + + public PrettyPrintWriter(final Writer writer, final String lineIndenter) { this(writer, lineIndenter.toCharArray()); } - public PrettyPrintWriter(Writer writer) { + /** + * @since 1.4 + */ + public PrettyPrintWriter(final Writer writer, final int mode, final NameCoder nameCoder) { + this(writer, mode, new char[]{' ', ' '}, nameCoder); + } + + /** + * @since 1.3 + * @deprecated As of 1.4 use {@link PrettyPrintWriter#PrettyPrintWriter(Writer, int, NameCoder)} instead + */ + @Deprecated + public PrettyPrintWriter(final Writer writer, final int mode, final XmlFriendlyReplacer replacer) { + this(writer, mode, new char[]{' ', ' '}, replacer); + } + + /** + * @since 1.4 + */ + public PrettyPrintWriter(final Writer writer, final NameCoder nameCoder) { + this(writer, XML_QUIRKS, new char[]{' ', ' '}, nameCoder); + } + + /** + * @deprecated As of 1.4 use {@link PrettyPrintWriter#PrettyPrintWriter(Writer, NameCoder)} instead. + */ + @Deprecated + public PrettyPrintWriter(final Writer writer, final XmlFriendlyReplacer replacer) { + this(writer, XML_QUIRKS, new char[]{' ', ' '}, replacer); + } + + /** + * @since 1.3 + */ + public PrettyPrintWriter(final Writer writer, final int mode) { + this(writer, mode, new char[]{' ', ' '}); + } + + public PrettyPrintWriter(final Writer writer) { this(writer, new char[]{' ', ' '}); } - public void startNode(String name) { + @Override + public void startNode(final String name) { + final String escapedName = encodeNode(name); tagIsEmpty = false; finishTag(); writer.write('<'); - writer.write(name); - elementStack.push(name); + writer.write(escapedName); + elementStack.push(escapedName); tagInProgress = true; depth++; readyForNewLine = true; tagIsEmpty = true; } - public void setValue(String text) { + @Override + public void startNode(final String name, final Class clazz) { + startNode(name); + } + + @Override + public void setValue(final String text) { readyForNewLine = false; tagIsEmpty = false; finishTag(); writeText(writer, text); } - public void addAttribute(String key, String value) { + @Override + public void addAttribute(final String key, final String value) { writer.write(' '); - writer.write(key); + writer.write(encodeAttribute(key)); writer.write('='); writer.write('\"'); writeAttributeValue(writer, value); writer.write('\"'); } - protected void writeAttributeValue(QuickWriter writer, String text) { - writeText(text); + protected void writeAttributeValue(final QuickWriter writer, final String text) { + writeText(text, true); } - protected void writeText(QuickWriter writer, String text) { - writeText(text); + protected void writeText(final QuickWriter writer, final String text) { + writeText(text, false); } - private void writeText(String text) { - int length = text.length(); + private void writeText(final String text, final boolean isAttribute) { + final int length = text.length(); for (int i = 0; i < length; i++) { - char c = text.charAt(i); + final char c = text.charAt(i); switch (c) { - case '\0': - this.writer.write(NULL); + case '\0': + if (mode == XML_QUIRKS) { + writer.write(NULL); + } else { + throw new StreamException("Invalid character 0x0 in XML stream"); + } + break; + case '&': + writer.write(AMP); + break; + case '<': + writer.write(LT); + break; + case '>': + writer.write(GT); + break; + case '"': + writer.write(QUOT); + break; + case '\'': + writer.write(APOS); + break; + case '\r': + writer.write(CR); + break; + case '\t': + case '\n': + if (!isAttribute) { + writer.write(c); break; - case '&': - this.writer.write(AMP); - break; - case '<': - this.writer.write(LT); - break; - case '>': - this.writer.write(GT); - break; - case '"': - this.writer.write(QUOT); - break; - case '\'': - this.writer.write(APOS); - break; - case '\r': - this.writer.write(SLASH_R); - break; - default: - this.writer.write(c); + } + //$FALL-THROUGH$ + default: + if (Character.isDefined(c) && !Character.isISOControl(c)) { + if (mode != XML_QUIRKS) { + if (c > '\ud7ff' && c < '\ue000') { + throw new StreamException("Invalid character 0x" + + Integer.toHexString(c) + + " in XML stream"); + } + } + writer.write(c); + } else { + if (mode == XML_1_0) { + if (c < 9 || c == '\u000b' || c == '\u000c' || c == '\u000e' || c >= '\u000f' && c <= '\u001f') { + throw new StreamException("Invalid character 0x" + + Integer.toHexString(c) + + " in XML 1.0 stream"); + } + } + if (mode != XML_QUIRKS) { + if (c == '\ufffe' || c == '\uffff') { + throw new StreamException("Invalid character 0x" + + Integer.toHexString(c) + + " in XML stream"); + } + } + writer.write("&#x"); + writer.write(Integer.toHexString(c)); + writer.write(';'); + } } } } + @Override public void endNode() { depth--; if (tagIsEmpty) { @@ -127,11 +286,11 @@ } else { finishTag(); writer.write(CLOSE); - writer.write((String)elementStack.pop()); + writer.write(elementStack.pop()); writer.write('>'); } readyForNewLine = true; - if (depth == 0 ) { + if (depth == 0) { writer.flush(); } } @@ -149,21 +308,30 @@ } protected void endOfLine() { - writer.write('\n'); + writer.write(getNewLine()); for (int i = 0; i < depth; i++) { writer.write(lineIndenter); } } + @Override public void flush() { writer.flush(); } + @Override public void close() { writer.close(); } - public HierarchicalStreamWriter underlyingWriter() { - return this; + /** + * Retrieve the line terminator. This method returns always a line feed, since according the XML specification any + * parser must ignore a carriage return. Overload this method, if you need different behavior. + * + * @return the line terminator + * @since 1.3 + */ + protected String getNewLine() { + return "\n"; } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/QNameMap.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/QNameMap.java (.../QNameMap.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/QNameMap.java (.../QNameMap.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,33 +1,45 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2014 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 01. October 2004 by James Strachan + */ package com.thoughtworks.xstream.io.xml; -import javax.xml.namespace.QName; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import javax.xml.namespace.QName; + + /** - * Represents a mapping of {@link QName} intsnaces to Java class names - * allowing class aliases and namespace aware mappings of QNames to class names. - * + * Represents a mapping of {@link QName} instances to Java class names allowing class aliases and namespace aware + * mappings of QNames to class names. + * * @author James Strachan * @version $Revision$ */ public class QNameMap { // lets make the mapping a no-op unless we specify some mapping - private Map qnameToJava; - private Map javaToQName; + private Map qnameToJava; + private Map javaToQName; private String defaultPrefix = ""; private String defaultNamespace = ""; /** - * Returns the Java class name that should be used for the given QName. - * If no explicit mapping has been made then the localPart of the QName is used - * which is the normal default in XStream. + * Returns the Java class name that should be used for the given QName. If no explicit mapping has been made then + * the localPart of the QName is used which is the normal default in XStream. */ - public String getJavaClassName(QName qname) { + public String getJavaClassName(final QName qname) { if (qnameToJava != null) { - String answer = (String) qnameToJava.get(qname); + final String answer = qnameToJava.get(qname); if (answer != null) { return answer; } @@ -36,13 +48,12 @@ } /** - * Returns the Java class name that should be used for the given QName. - * If no explicit mapping has been made then the localPart of the QName is used - * which is the normal default in XStream. + * Returns the Java class name that should be used for the given QName. If no explicit mapping has been made then + * the localPart of the QName is used which is the normal default in XStream. */ - public QName getQName(String javaClassName) { + public QName getQName(final String javaClassName) { if (javaToQName != null) { - QName answer = (QName) javaToQName.get(javaClassName); + final QName answer = javaToQName.get(javaClassName); if (answer != null) { return answer; } @@ -53,12 +64,12 @@ /** * Registers the mapping of the Java class name to the QName */ - public synchronized void registerMapping(QName qname, String javaClassName) { + public synchronized void registerMapping(final QName qname, final String javaClassName) { if (javaToQName == null) { - javaToQName = Collections.synchronizedMap(new HashMap()); + javaToQName = Collections.synchronizedMap(new HashMap()); } if (qnameToJava == null) { - qnameToJava = Collections.synchronizedMap(new HashMap()); + qnameToJava = Collections.synchronizedMap(new HashMap()); } javaToQName.put(javaClassName, qname); qnameToJava.put(qname, javaClassName); @@ -67,23 +78,23 @@ /** * Registers the mapping of the type to the QName */ - public synchronized void registerMapping(QName qname, Class type) { + public synchronized void registerMapping(final QName qname, final Class type) { registerMapping(qname, type.getName()); } public String getDefaultNamespace() { return defaultNamespace; } - public void setDefaultNamespace(String defaultNamespace) { + public void setDefaultNamespace(final String defaultNamespace) { this.defaultNamespace = defaultNamespace; } public String getDefaultPrefix() { return defaultPrefix; } - public void setDefaultPrefix(String defaultPrefix) { + public void setDefaultPrefix(final String defaultPrefix) { this.defaultPrefix = defaultPrefix; } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/SaxWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/SaxWriter.java (.../SaxWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/SaxWriter.java (.../SaxWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,8 +1,23 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2014 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 14. August 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.StreamException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; import org.xml.sax.EntityResolver; @@ -14,63 +29,51 @@ import org.xml.sax.XMLReader; import org.xml.sax.helpers.AttributesImpl; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + /** * A SAX {@link org.xml.sax.XMLReader parser} that acts as an XStream - * {@link HierarchicalStreamWriter} to enable direct generation of - * a SAX event flow from the XStream serialization of a list of - * list of Java objects. - *

    - * As a custom SAX parser, this class ignores the arguments of the - * two standard parse methods ({@link #parse(java.lang.String)} and - * {@link #parse(org.xml.sax.InputSource)}) but relies on a - * proprietary SAX property {@link #SOURCE_OBJECT_LIST_PROPERTY} to - * define the list of objects to serialize.

    - *

    - * Configuration of this SAX parser is achieved through the standard - * {@link #setProperty SAX property mecanism}. While specific setter - * methods require direct access to the parser instance, SAX - * properties support configuration settings to be propagated through - * a chain of {@link org.xml.sax.XMLFilter filters} down to the - * underlying parser object.

    - *

    - * This mecanism shall be used to configure the - * {@link #SOURCE_OBJECT_LIST_PROPERTY objects to be serialized} as - * well as the {@link #CONFIGURED_XSTREAM_PROPERTY XStream facade}.

    - * + * {@link com.thoughtworks.xstream.io.HierarchicalStreamWriter} to enable direct generation of a SAX event flow from the + * XStream serialization of a list of list of Java objects. + *

    + * As a custom SAX parser, this class ignores the arguments of the two standard parse methods ( + * {@link #parse(java.lang.String)} and {@link #parse(org.xml.sax.InputSource)}) but relies on a proprietary SAX + * property {@link #SOURCE_OBJECT_LIST_PROPERTY} to define the list of objects to serialize. + *

    + *

    + * Configuration of this SAX parser is achieved through the standard {@link #setProperty SAX property mechanism}. While + * specific setter methods require direct access to the parser instance, SAX properties support configuration settings + * to be propagated through a chain of {@link org.xml.sax.XMLFilter filters} down to the underlying parser object. + *

    + *

    + * This mechanism shall be used to configure the {@link #SOURCE_OBJECT_LIST_PROPERTY objects to be serialized} as well + * as the {@link #CONFIGURED_XSTREAM_PROPERTY XStream facade}. + *

    + * * @author Laurent Bihanic */ -public final class SaxWriter implements HierarchicalStreamWriter, XMLReader { +public final class SaxWriter extends AbstractXmlWriter implements XMLReader { /** - * The {@link #setProperty SAX property} to configure the XStream - * facade to be used for object serialization. If the property - * is not set, a new XStream facade will be allocated for each - * parse. + * The {@link #setProperty SAX property} to configure the XStream facade to be used for object serialization. If the + * property is not set, a new XStream facade will be allocated for each parse. */ - public final static String CONFIGURED_XSTREAM_PROPERTY = - "http://com.thoughtworks.xstream/sax/property/configured-xstream"; + public final static String CONFIGURED_XSTREAM_PROPERTY = "http://com.thoughtworks.xstream/sax/property/configured-xstream"; /** - * The {@link #setProperty SAX property} to configure the list of - * Java objects to serialize. Setting this property prior - * invoking one of the parse() methods is mandatory. - * + * The {@link #setProperty SAX property} to configure the list of Java objects to serialize. Setting this property + * prior invoking one of the parse() methods is mandatory. + * * @see #parse(java.lang.String) * @see #parse(org.xml.sax.InputSource) */ - public final static String SOURCE_OBJECT_LIST_PROPERTY = - "http://com.thoughtworks.xstream/sax/property/source-object-list"; + public final static String SOURCE_OBJECT_LIST_PROPERTY = "http://com.thoughtworks.xstream/sax/property/source-object-list"; - //========================================================================= + // ========================================================================= // SAX XMLReader interface support - //========================================================================= + // ========================================================================= /** * The SAX EntityResolver associated to this XMLReader. @@ -94,99 +97,123 @@ /** * The SAX features defined for this XMLReader. - *

    - * This class does not define any feature (yet) and ignores - * the SAX mandatory feature. Thus, this member is present - * only to support the mandatory feature setting and retrieval - * logic defined by SAX.

    + *

    + * This class does not define any feature (yet) and ignores the SAX mandatory feature. Thus, this member is present + * only to support the mandatory feature setting and retrieval logic defined by SAX. + *

    */ - private Map features = new HashMap(); + private final Map features = new HashMap(); /** * The SAX properties defined for this XMLReader. */ - private final Map properties = new HashMap(); + private final Map properties = new HashMap(); private final boolean includeEnclosingDocument; - public SaxWriter(boolean includeEnclosingDocument) { + /** + * @since 1.4 + */ + public SaxWriter(final NameCoder nameCoder) { + this(true, nameCoder); + } + + /** + * @since 1.4 + */ + public SaxWriter(final boolean includeEnclosingDocument, final NameCoder nameCoder) { + super(nameCoder); this.includeEnclosingDocument = includeEnclosingDocument; } + /** + * @deprecated As of 1.4 use {@link SaxWriter#SaxWriter(NameCoder)} instead. + */ + @Deprecated + public SaxWriter(final XmlFriendlyReplacer replacer) { + this(true, replacer); + } + + /** + * @deprecated As of 1.4 use {@link SaxWriter#SaxWriter(boolean, NameCoder)} instead. + */ + @Deprecated + public SaxWriter(final boolean includeEnclosingDocument, final XmlFriendlyReplacer replacer) { + this(includeEnclosingDocument, (NameCoder)replacer); + } + + public SaxWriter(final boolean includeEnclosingDocument) { + this(includeEnclosingDocument, new XmlFriendlyNameCoder()); + } + public SaxWriter() { this(true); } - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- // Configuration - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- /** * Sets the state of a feature. - *

    - * The feature name is any fully-qualified URI.

    - *

    - * All XMLReaders are required to support setting - * http://xml.org/sax/features/namespaces to - * true and - * http://xml.org/sax/features/namespace-prefixes to - * false.

    - *

    - * Some feature values may be immutable or mutable only - * in specific contexts, such as before, during, or after - * a parse.

    - *

    - * Note: This implemention only supports the two - * mandatory SAX features.

    - * - * @param name the feature name, which is a fully-qualified URI. + *

    + * The feature name is any fully-qualified URI. + *

    + *

    + * All XMLReaders are required to support setting http://xml.org/sax/features/namespaces to + * true and http://xml.org/sax/features/namespace-prefixes to false. + *

    + *

    + * Some feature values may be immutable or mutable only in specific contexts, such as before, during, or after a + * parse. + *

    + *

    + * Note: This implementation only supports the two mandatory SAX features. + *

    + * + * @param name the feature name, which is a fully-qualified URI. * @param value the requested state of the feature (true or false). - * @throws SAXNotRecognizedException when the XMLReader does not - * recognize the feature name. + * @throws SAXNotRecognizedException when the XMLReader does not recognize the feature name. * @see #getFeature */ - public void setFeature(String name, boolean value) - throws SAXNotRecognizedException { - if ((name.equals("http://xml.org/sax/features/namespaces")) || - (name.equals("http://xml.org/sax/features/namespace-prefixes"))) { - this.features.put(name, value ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly + @Override + public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException { + if (name.equals("http://xml.org/sax/features/namespaces") + || name.equals("http://xml.org/sax/features/namespace-prefixes")) { + features.put(name, value ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly } else { throw new SAXNotRecognizedException(name); } } /** * Looks up the value of a feature. - *

    - * The feature name is any fully-qualified URI. It is - * possible for an XMLReader to recognize a feature name but - * to be unable to return its value; this is especially true - * in the case of an adapter for a SAX1 Parser, which has - * no way of knowing whether the underlying parser is - * performing validation or expanding external entities.

    - *

    - * All XMLReaders are required to recognize the - * http://xml.org/sax/features/namespaces and the - * http://xml.org/sax/features/namespace-prefixes feature - * names.

    - *

    - * Some feature values may be available only in specific - * contexts, such as before, during, or after a parse.

    - *

    - * Implementors are free (and encouraged) to invent their own - * features, using names built on their own URIs.

    - * + *

    + * The feature name is any fully-qualified URI. It is possible for an XMLReader to recognize a feature name but to + * be unable to return its value; this is especially true in the case of an adapter for a SAX1 Parser, which has no + * way of knowing whether the underlying parser is performing validation or expanding external entities. + *

    + *

    + * All XMLReaders are required to recognize the http://xml.org/sax/features/namespaces and the + * http://xml.org/sax/features/namespace-prefixes feature names. + *

    + *

    + * Some feature values may be available only in specific contexts, such as before, during, or after a parse. + *

    + *

    + * Implementors are free (and encouraged) to invent their own features, using names built on their own URIs. + *

    + * * @param name the feature name, which is a fully-qualified URI. * @return the current state of the feature (true or false). - * @throws SAXNotRecognizedException when the XMLReader does not - * recognize the feature name. + * @throws SAXNotRecognizedException when the XMLReader does not recognize the feature name. * @see #setFeature */ - public boolean getFeature(String name) - throws SAXNotRecognizedException { - if ((name.equals("http://xml.org/sax/features/namespaces")) || - (name.equals("http://xml.org/sax/features/namespace-prefixes"))) { - Boolean value = (Boolean) (this.features.get(name)); + @Override + public boolean getFeature(final String name) throws SAXNotRecognizedException { + if (name.equals("http://xml.org/sax/features/namespaces") + || name.equals("http://xml.org/sax/features/namespace-prefixes")) { + Boolean value = features.get(name); if (value == null) { value = Boolean.FALSE; @@ -199,488 +226,474 @@ /** * Sets the value of a property. - *

    - * The property name is any fully-qualified URI. It is - * possible for an XMLReader to recognize a property name but - * to be unable to set its value.

    - *

    - * XMLReaders are not required to recognize setting any - * specific property names, though a core set is provided with - * SAX2.

    - *

    - * Some property values may be immutable or mutable only - * in specific contexts, such as before, during, or after - * a parse.

    - *

    - * This method is also the standard mechanism for setting - * extended handlers.

    - *

    - * Note: This implemention only supports two - * (proprietary) properties: {@link #CONFIGURED_XSTREAM_PROPERTY} - * and {@link #SOURCE_OBJECT_LIST_PROPERTY}.

    - * - * @param name the property name, which is a fully-qualified URI. + *

    + * The property name is any fully-qualified URI. It is possible for an XMLReader to recognize a property name but to + * be unable to set its value. + *

    + *

    + * XMLReaders are not required to recognize setting any specific property names, though a core set is provided with + * SAX2. + *

    + *

    + * Some property values may be immutable or mutable only in specific contexts, such as before, during, or after a + * parse. + *

    + *

    + * This method is also the standard mechanism for setting extended handlers. + *

    + *

    + * Note: This implementation only supports two (proprietary) properties: + * {@link #CONFIGURED_XSTREAM_PROPERTY} and {@link #SOURCE_OBJECT_LIST_PROPERTY}. + *

    + * + * @param name the property name, which is a fully-qualified URI. * @param value the requested value for the property. - * @throws SAXNotRecognizedException when the XMLReader does not - * recognize the property name. - * @throws SAXNotSupportedException when the XMLReader recognizes - * the property name but cannot set - * the requested value. + * @throws SAXNotRecognizedException when the XMLReader does not recognize the property name. + * @throws SAXNotSupportedException when the XMLReader recognizes the property name but cannot set the requested + * value. * @see #getProperty */ - public void setProperty(String name, Object value) - throws SAXNotRecognizedException, - SAXNotSupportedException { + @Override + public void setProperty(final String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { if (name.equals(CONFIGURED_XSTREAM_PROPERTY)) { if (!(value instanceof XStream)) { - throw new SAXNotSupportedException("Value for property \"" + - CONFIGURED_XSTREAM_PROPERTY + - "\" must be a non-null XStream object"); + throw new SAXNotSupportedException("Value for property \"" + + CONFIGURED_XSTREAM_PROPERTY + + "\" must be a non-null XStream object"); } } else if (name.equals(SOURCE_OBJECT_LIST_PROPERTY)) { if (value instanceof List) { - List list = (List) value; + final List list = (List)value; if (list.isEmpty()) { - throw new SAXNotSupportedException("Value for property \"" + - SOURCE_OBJECT_LIST_PROPERTY + - "\" shall not be an empty list"); + throw new SAXNotSupportedException("Value for property \"" + + SOURCE_OBJECT_LIST_PROPERTY + + "\" shall not be an empty list"); } else { // Perform a copy of the list to prevent the application to // modify its content while the parse is being performed. - value = Collections.unmodifiableList(new ArrayList(list)); + value = Collections.unmodifiableList(new ArrayList(list)); } } else { - throw new SAXNotSupportedException("Value for property \"" + - SOURCE_OBJECT_LIST_PROPERTY + - "\" must be a non-null List object"); + throw new SAXNotSupportedException("Value for property \"" + + SOURCE_OBJECT_LIST_PROPERTY + + "\" must be a non-null List object"); } } else { throw new SAXNotRecognizedException(name); } - this.properties.put(name, value); + properties.put(name, value); } /** * Looks up the value of a property. - *

    - * The property name is any fully-qualified URI. It is - * possible for an XMLReader to recognize a property name but - * to be unable to return its state.

    - *

    - * XMLReaders are not required to recognize any specific - * property names, though an initial core set is documented for - * SAX2.

    - *

    - * Some property values may be available only in specific - * contexts, such as before, during, or after a parse.

    - *

    - * Implementors are free (and encouraged) to invent their own properties, - * using names built on their own URIs.

    - * + *

    + * The property name is any fully-qualified URI. It is possible for an XMLReader to recognize a property name but to + * be unable to return its state. + *

    + *

    + * XMLReaders are not required to recognize any specific property names, though an initial core set is documented + * for SAX2. + *

    + *

    + * Some property values may be available only in specific contexts, such as before, during, or after a parse. + *

    + *

    + * Implementors are free (and encouraged) to invent their own properties, using names built on their own URIs. + *

    + * * @param name the property name, which is a fully-qualified URI. * @return the current value of the property. - * @throws SAXNotRecognizedException when the XMLReader does not - * recognize the property name. + * @throws SAXNotRecognizedException when the XMLReader does not recognize the property name. * @see #getProperty */ - public Object getProperty(String name) - throws SAXNotRecognizedException { - if ((name.equals(CONFIGURED_XSTREAM_PROPERTY)) || - (name.equals(SOURCE_OBJECT_LIST_PROPERTY))) { - return this.properties.get(name); + @Override + public Object getProperty(final String name) throws SAXNotRecognizedException { + if (name.equals(CONFIGURED_XSTREAM_PROPERTY) || name.equals(SOURCE_OBJECT_LIST_PROPERTY)) { + return properties.get(name); } else { throw new SAXNotRecognizedException(name); } } - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- // Event handlers - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- /** * Allows an application to register an entity resolver. - *

    - * If the application does not register an entity resolver, - * the XMLReader will perform its own default resolution.

    - *

    - * Applications may register a new or different resolver in the - * middle of a parse, and the SAX parser must begin using the new - * resolver immediately.

    - * + *

    + * If the application does not register an entity resolver, the XMLReader will perform its own default resolution. + *

    + *

    + * Applications may register a new or different resolver in the middle of a parse, and the SAX parser must begin + * using the new resolver immediately. + *

    + * * @param resolver the entity resolver. - * @throws NullPointerException if the resolver argument is - * null. + * @throws NullPointerException if the resolver argument is null. * @see #getEntityResolver */ - public void setEntityResolver(EntityResolver resolver) { + @Override + public void setEntityResolver(final EntityResolver resolver) { if (resolver == null) { throw new NullPointerException("resolver"); } - this.entityResolver = resolver; + entityResolver = resolver; return; } /** * Returns the current entity resolver. - * - * @return the current entity resolver, or null if none - * has been registered. + * + * @return the current entity resolver, or null if none has been registered. * @see #setEntityResolver */ + @Override public EntityResolver getEntityResolver() { - return this.entityResolver; + return entityResolver; } /** * Allows an application to register a DTD event handler. - *

    - * If the application does not register a DTD handler, all DTD - * events reported by the SAX parser will be silently ignored.

    - *

    - * Applications may register a new or different handler in the - * middle of a parse, and the SAX parser must begin using the new - * handler immediately.

    - * + *

    + * If the application does not register a DTD handler, all DTD events reported by the SAX parser will be silently + * ignored. + *

    + *

    + * Applications may register a new or different handler in the middle of a parse, and the SAX parser must begin + * using the new handler immediately. + *

    + * * @param handler the DTD handler. - * @throws NullPointerException if the handler argument is - * null. + * @throws NullPointerException if the handler argument is null. * @see #getDTDHandler */ - public void setDTDHandler(DTDHandler handler) { + @Override + public void setDTDHandler(final DTDHandler handler) { if (handler == null) { throw new NullPointerException("handler"); } - this.dtdHandler = handler; + dtdHandler = handler; return; } /** * Returns the current DTD handler. - * - * @return the current DTD handler, or null if none - * has been registered. + * + * @return the current DTD handler, or null if none has been registered. * @see #setDTDHandler */ + @Override public DTDHandler getDTDHandler() { - return this.dtdHandler; + return dtdHandler; } /** * Allows an application to register a content event handler. - *

    - * If the application does not register a content handler, all - * content events reported by the SAX parser will be silently - * ignored.

    - *

    - * Applications may register a new or different handler in the - * middle of a parse, and the SAX parser must begin using the new - * handler immediately.

    - * + *

    + * If the application does not register a content handler, all content events reported by the SAX parser will be + * silently ignored. + *

    + *

    + * Applications may register a new or different handler in the middle of a parse, and the SAX parser must begin + * using the new handler immediately. + *

    + * * @param handler the content handler. - * @throws NullPointerException if the handler argument is - * null. + * @throws NullPointerException if the handler argument is null. * @see #getContentHandler */ - public void setContentHandler(ContentHandler handler) { + @Override + public void setContentHandler(final ContentHandler handler) { if (handler == null) { throw new NullPointerException("handler"); } - this.contentHandler = handler; + contentHandler = handler; return; } /** * Returns the current content handler. - * - * @return the current content handler, or null if none - * has been registered. + * + * @return the current content handler, or null if none has been registered. * @see #setContentHandler */ + @Override public ContentHandler getContentHandler() { - return this.contentHandler; + return contentHandler; } /** * Allows an application to register an error event handler. - *

    - * If the application does not register an error handler, all - * error events reported by the SAX parser will be silently - * ignored; however, normal processing may not continue. It is - * highly recommended that all SAX applications implement an - * error handler to avoid unexpected bugs.

    - *

    - * Applications may register a new or different handler in the - * middle of a parse, and the SAX parser must begin using the new - * handler immediately.

    - * + *

    + * If the application does not register an error handler, all error events reported by the SAX parser will be + * silently ignored; however, normal processing may not continue. It is highly recommended that all SAX applications + * implement an error handler to avoid unexpected bugs. + *

    + *

    + * Applications may register a new or different handler in the middle of a parse, and the SAX parser must begin + * using the new handler immediately. + *

    + * * @param handler the error handler. - * @throws NullPointerException if the handler argument is - * null. + * @throws NullPointerException if the handler argument is null. * @see #getErrorHandler */ - public void setErrorHandler(ErrorHandler handler) { + @Override + public void setErrorHandler(final ErrorHandler handler) { if (handler == null) { throw new NullPointerException("handler"); } - this.errorHandler = handler; + errorHandler = handler; return; } /** * Returns the current error handler. - * - * @return the current error handler, or null if none - * has been registered. + * + * @return the current error handler, or null if none has been registered. * @see #setErrorHandler */ + @Override public ErrorHandler getErrorHandler() { - return this.errorHandler; + return errorHandler; } - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- // Parsing - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- /** * Parses an XML document from a system identifier (URI). - *

    - * This method is a shortcut for the common case of reading a - * document from a system identifier. It is the exact - * equivalent of the following:

    + *

    + * This method is a shortcut for the common case of reading a document from a system identifier. It is the exact + * equivalent of the following: + *

    *
    + * *
    -     *    parse(new InputSource(systemId));
    -     *  
    + * parse(new InputSource(systemId)); + * + * *
    - *

    - * If the system identifier is a URL, it must be fully resolved - * by the application before it is passed to the parser.

    - *

    - * Note: As a custom SAX parser, this class - * ignores the systemId argument of this method - * and relies on the proprietary SAX property - * {@link #SOURCE_OBJECT_LIST_PROPERTY}) to define the list of - * objects to serialize.

    - * + *

    + * If the system identifier is a URL, it must be fully resolved by the application before it is passed to the + * parser. + *

    + *

    + * Note: As a custom SAX parser, this class ignores the systemId argument of this + * method and relies on the proprietary SAX property {@link #SOURCE_OBJECT_LIST_PROPERTY}) to define the list of + * objects to serialize. + *

    + * * @param systemId the system identifier (URI). - * @throws SAXException Any SAX exception, possibly wrapping - * another exception. + * @throws SAXException Any SAX exception, possibly wrapping another exception. * @see #parse(org.xml.sax.InputSource) */ - public void parse(String systemId) throws SAXException { + @Override + public void parse(final String systemId) throws SAXException { this.parse(); } /** * Parse an XML document. - *

    - * The application can use this method to instruct the XML - * reader to begin parsing an XML document from any valid input - * source (a character stream, a byte stream, or a URI).

    - *

    - * Applications may not invoke this method while a parse is in - * progress (they should create a new XMLReader instead for each - * nested XML document). Once a parse is complete, an - * application may reuse the same XMLReader object, possibly - * with a different input source.

    - *

    - * During the parse, the XMLReader will provide information - * about the XML document through the registered event - * handlers.

    - *

    - * This method is synchronous: it will not return until parsing - * has ended. If a client application wants to terminate - * parsing early, it should throw an exception.

    - *

    - * Note: As a custom SAX parser, this class - * ignores the source argument of this method - * and relies on the proprietary SAX property - * {@link #SOURCE_OBJECT_LIST_PROPERTY}) to define the list of - * objects to serialize.

    - * - * @param input The input source for the top-level of the - * XML document. - * @throws SAXException Any SAX exception, possibly wrapping - * another exception. + *

    + * The application can use this method to instruct the XML reader to begin parsing an XML document from any valid + * input source (a character stream, a byte stream, or a URI). + *

    + *

    + * Applications may not invoke this method while a parse is in progress (they should create a new XMLReader instead + * for each nested XML document). Once a parse is complete, an application may reuse the same XMLReader object, + * possibly with a different input source. + *

    + *

    + * During the parse, the XMLReader will provide information about the XML document through the registered event + * handlers. + *

    + *

    + * This method is synchronous: it will not return until parsing has ended. If a client application wants to + * terminate parsing early, it should throw an exception. + *

    + *

    + * Note: As a custom SAX parser, this class ignores the source argument of this method + * and relies on the proprietary SAX property {@link #SOURCE_OBJECT_LIST_PROPERTY}) to define the list of objects to + * serialize. + *

    + * + * @param input The input source for the top-level of the XML document. + * @throws SAXException Any SAX exception, possibly wrapping another exception. * @see org.xml.sax.InputSource * @see #parse(java.lang.String) * @see #setEntityResolver * @see #setDTDHandler * @see #setContentHandler * @see #setErrorHandler */ - public void parse(InputSource input) throws SAXException { + @Override + public void parse(final InputSource input) throws SAXException { this.parse(); } /** - * Serializes the Java objects of the configured list into a flow - * of SAX events. - * - * @throws SAXException if the configured object list is invalid - * or object serialization failed. + * Serializes the Java objects of the configured list into a flow of SAX events. + * + * @throws SAXException if the configured object list is invalid or object serialization failed. */ private void parse() throws SAXException { - XStream xstream = (XStream) (this.properties.get(CONFIGURED_XSTREAM_PROPERTY)); + XStream xstream = (XStream)properties.get(CONFIGURED_XSTREAM_PROPERTY); if (xstream == null) { xstream = new XStream(); } - List source = (List) (this.properties.get(SOURCE_OBJECT_LIST_PROPERTY)); - if ((source == null) || (source.isEmpty())) { - throw new SAXException("Missing or empty source object list. Setting property \"" + - SOURCE_OBJECT_LIST_PROPERTY + "\" is mandatory"); + final List source = (List)properties.get(SOURCE_OBJECT_LIST_PROPERTY); + if (source == null || source.isEmpty()) { + throw new SAXException("Missing or empty source object list. Setting property \"" + + SOURCE_OBJECT_LIST_PROPERTY + + "\" is mandatory"); } try { - this.startDocument(true); - for (Iterator i = source.iterator(); i.hasNext();) { - xstream.marshal(i.next(), this); + startDocument(true); + for (final Object name : source) { + xstream.marshal(name, this); } - this.endDocument(true); - } catch (StreamException e) { + endDocument(true); + } catch (final StreamException e) { if (e.getCause() instanceof SAXException) { - throw (SAXException) (e.getCause()); + throw (SAXException)e.getCause(); } else { throw new SAXException(e); } } } - - //========================================================================= + // ========================================================================= // XStream HierarchicalStreamWriter interface support - //========================================================================= + // ========================================================================= private int depth = 0; - private List elementStack = new LinkedList(); + private final List elementStack = new LinkedList(); private char[] buffer = new char[128]; private boolean startTagInProgress = false; private final AttributesImpl attributeList = new AttributesImpl(); - public void startNode(String name) { + @Override + public void startNode(final String name) { try { - if (this.depth != 0) { - this.flushStartTag(); + if (depth != 0) { + flushStartTag(); } else if (includeEnclosingDocument) { - this.startDocument(false); + startDocument(false); } - this.elementStack.add(0, name); + elementStack.add(0, escapeXmlName(name)); - this.startTagInProgress = true; - this.depth++; - } catch (SAXException e) { + startTagInProgress = true; + depth++; + } catch (final SAXException e) { throw new StreamException(e); } } - public void addAttribute(String name, String value) { - if (this.startTagInProgress) { - this.attributeList.addAttribute("", name, name, "CDATA", value); + @Override + public void addAttribute(final String name, final String value) { + if (startTagInProgress) { + final String escapedName = escapeXmlName(name); + attributeList.addAttribute("", escapedName, escapedName, "CDATA", value); } else { throw new StreamException(new IllegalStateException("No startElement being processed")); } } - public void setValue(String text) { + @Override + public void setValue(final String text) { try { - this.flushStartTag(); + flushStartTag(); - int lg = text.length(); + final int lg = text.length(); if (lg > buffer.length) { buffer = new char[lg]; } text.getChars(0, lg, buffer, 0); - this.contentHandler.characters(buffer, 0, lg); - } catch (SAXException e) { + contentHandler.characters(buffer, 0, lg); + } catch (final SAXException e) { throw new StreamException(e); } } + @Override public void endNode() { try { - this.flushStartTag(); + flushStartTag(); - String tagName = (String) (this.elementStack.remove(0)); + final String tagName = elementStack.remove(0); - this.contentHandler.endElement("", tagName, tagName); + contentHandler.endElement("", tagName, tagName); - this.depth--; - if (this.depth == 0 && includeEnclosingDocument) { - this.endDocument(false); + depth--; + if (depth == 0 && includeEnclosingDocument) { + endDocument(false); } - } catch (SAXException e) { + } catch (final SAXException e) { throw new StreamException(e); } } /** - * Fires the SAX startDocument event towards the configured - * ContentHandler. - * - * @param multiObjectMode whether serialization of several - * object will be merge into a single - * SAX document. + * Fires the SAX startDocument event towards the configured ContentHandler. + * + * @param multiObjectMode whether serialization of several object will be merge into a single SAX document. * @throws SAXException if thrown by the ContentHandler. */ - private void startDocument(boolean multiObjectMode) throws SAXException { - if (this.depth == 0) { + private void startDocument(final boolean multiObjectMode) throws SAXException { + if (depth == 0) { // Notify contentHandler of document start. - this.contentHandler.startDocument(); + contentHandler.startDocument(); if (multiObjectMode) { // Prevent marshalling of each object to fire its own // start/endDocument events. - this.depth++; + depth++; } } } /** - * Fires the SAX endDocument event towards the configured - * ContentHandler. - * - * @param multiObjectMode whether serialization of several - * object will be merge into a single - * SAX document. + * Fires the SAX endDocument event towards the configured ContentHandler. + * + * @param multiObjectMode whether serialization of several object will be merge into a single SAX document. * @throws SAXException if thrown by the ContentHandler. */ - private void endDocument(boolean multiObjectMode) throws SAXException { - if ((this.depth == 0) || ((this.depth == 1) && (multiObjectMode))) { - this.contentHandler.endDocument(); - this.depth = 0; + private void endDocument(final boolean multiObjectMode) throws SAXException { + if (depth == 0 || depth == 1 && multiObjectMode) { + contentHandler.endDocument(); + depth = 0; } } /** - * Fires any pending SAX startElement event towards the - * configured ContentHandler. - * + * Fires any pending SAX startElement event towards the configured ContentHandler. + * * @throws SAXException if thrown by the ContentHandler. */ private void flushStartTag() throws SAXException { - if (this.startTagInProgress) { - String tagName = (String) (this.elementStack.get(0)); + if (startTagInProgress) { + final String tagName = elementStack.get(0); - this.contentHandler.startElement("", tagName, - tagName, this.attributeList); - this.attributeList.clear(); - this.startTagInProgress = false; + contentHandler.startElement("", tagName, tagName, attributeList); + attributeList.clear(); + startTagInProgress = false; } } + @Override public void flush() { // don't need to do anything } + @Override public void close() { // don't need to do anything } - - public HierarchicalStreamWriter underlyingWriter() { - return this; - } } - Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/SjsxpDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/SjsxpDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/SjsxpDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2009, 2011, 2013, 2014 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 29. April 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; + +import com.thoughtworks.xstream.io.StreamException; + + +/** + * A driver using the JDK 6 StAX implementation of Sun. + * + * @author Jörg Schaible + * @since 1.4 + * @deprecated As of 1.4.5 use {@link StandardStaxDriver} + */ +@Deprecated +public class SjsxpDriver extends StaxDriver { + + /** + * @deprecated As of 1.4.5 use {@link StandardStaxDriver#StandardStaxDriver()} + */ + @Deprecated + public SjsxpDriver() { + super(); + } + + /** + * @deprecated As of 1.4.5 use {@link StandardStaxDriver#StandardStaxDriver(QNameMap, XmlFriendlyNameCoder)} + */ + @Deprecated + public SjsxpDriver(final QNameMap qnameMap, final XmlFriendlyNameCoder nameCoder) { + super(qnameMap, nameCoder); + } + + /** + * @deprecated As of 1.4.5 use {@link StandardStaxDriver#StandardStaxDriver(QNameMap)} + */ + @Deprecated + public SjsxpDriver(final QNameMap qnameMap) { + super(qnameMap); + } + + /** + * @deprecated As of 1.4.5 use {@link StandardStaxDriver#StandardStaxDriver(XmlFriendlyNameCoder)} + */ + @Deprecated + public SjsxpDriver(final XmlFriendlyNameCoder nameCoder) { + super(nameCoder); + } + + /** + * @deprecated As of 1.4.5 use {@link StandardStaxDriver#createInputFactory()} + */ + @Deprecated + @Override + protected XMLInputFactory createInputFactory() { + Exception exception = null; + try { + return (XMLInputFactory)Class.forName("com.sun.xml.internal.stream.XMLInputFactoryImpl").newInstance(); + } catch (final InstantiationException e) { + exception = e; + } catch (final IllegalAccessException e) { + exception = e; + } catch (final ClassNotFoundException e) { + exception = e; + } + throw new StreamException("Cannot create SJSXP (Sun JDK 6 StAX) XMLInputFaqctory instance.", exception); + } + + /** + * @deprecated As of 1.4.5 use {@link StandardStaxDriver#createOutputFactory()} + */ + @Deprecated + @Override + protected XMLOutputFactory createOutputFactory() { + Exception exception = null; + try { + return (XMLOutputFactory)Class.forName("com.sun.xml.internal.stream.XMLOutputFactoryImpl").newInstance(); + } catch (final InstantiationException e) { + exception = e; + } catch (final IllegalAccessException e) { + exception = e; + } catch (final ClassNotFoundException e) { + exception = e; + } + throw new StreamException("Cannot create SJSXP (Sun JDK 6 StAX) XMLOutputFaqctory instance.", exception); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StandardStaxDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StandardStaxDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StandardStaxDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2013, 2014 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 27. July 2013 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; + +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * A driver using the standard JDK StAX implementation provided by the Java runtime. + *

    + * In contrast to XMLInputFactory.newFactory() or XMLOutputFactory.newFactory() this implementation will ignore any + * implementations provided with the system properties javax.xml.stream.XMLInputFactory and + * javax.xml.stream.XMLOutputFactory, all implementations configured in lib/stax.properties or + * registered with the Service API. + *

    + * + * @author Jörg Schaible + * @since 1.4.5 + */ +public class StandardStaxDriver extends StaxDriver { + + public StandardStaxDriver() { + super(); + } + + /** + * @deprecated As of 1.4.6 use {@link #StandardStaxDriver(QNameMap, NameCoder)} + */ + @Deprecated + public StandardStaxDriver(final QNameMap qnameMap, final XmlFriendlyNameCoder nameCoder) { + super(qnameMap, nameCoder); + } + + /** + * @since 1.4.6 + */ + public StandardStaxDriver(final QNameMap qnameMap, final NameCoder nameCoder) { + super(qnameMap, nameCoder); + } + + public StandardStaxDriver(final QNameMap qnameMap) { + super(qnameMap); + } + + /** + * @deprecated As of 1.4.6 use {@link #StandardStaxDriver(NameCoder)} + */ + @Deprecated + public StandardStaxDriver(final XmlFriendlyNameCoder nameCoder) { + super(nameCoder); + } + + /** + * @since 1.4.6 + */ + public StandardStaxDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + protected XMLInputFactory createInputFactory() { + Exception exception = null; + try { + final Class staxInputFactory = JVM.getStaxInputFactory(); + if (staxInputFactory != null) { + return staxInputFactory.newInstance(); + } else { + throw new StreamException("Java runtime has no standard XMLInputFactory implementation.", exception); + } + } catch (final InstantiationException e) { + exception = e; + } catch (final IllegalAccessException e) { + exception = e; + } catch (final ClassNotFoundException e) { + exception = e; + } + throw new StreamException("Cannot create standard XMLInputFactory instance of Java runtime.", exception); + } + + @Override + protected XMLOutputFactory createOutputFactory() { + Exception exception = null; + try { + final Class staxOutputFactory = JVM.getStaxOutputFactory(); + if (staxOutputFactory != null) { + return staxOutputFactory.newInstance(); + } else { + throw new StreamException("Java runtime has no standard XMLOutputFactory implementation.", exception); + } + } catch (final InstantiationException e) { + exception = e; + } catch (final IllegalAccessException e) { + exception = e; + } catch (final ClassNotFoundException e) { + exception = e; + } + throw new StreamException("Cannot create standard XMLOutputFactory instance of Java runtime.", exception); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxDriver.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxDriver.java (.../StaxDriver.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxDriver.java (.../StaxDriver.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,145 +1,260 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2014 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 29. September 2004 by James Strachan + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.HierarchicalStreamDriver; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.StreamException; - -import javax.xml.stream.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; +import java.net.URL; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.ReaderWrapper; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + + /** - * A driver using the StAX API - * + * A driver using the StAX API to create XML reader and writer. + * * @author James Strachan + * @author Jörg Schaible * @version $Revision$ */ -public class StaxDriver implements HierarchicalStreamDriver { +public class StaxDriver extends AbstractXmlDriver { - private static boolean libraryPresent; - private QNameMap qnameMap; private XMLInputFactory inputFactory; private XMLOutputFactory outputFactory; - private boolean repairingNamespace = false; public StaxDriver() { - this.qnameMap = new QNameMap(); + this(new QNameMap()); } - public StaxDriver(QNameMap qnameMap) { - this.qnameMap = qnameMap; + public StaxDriver(final QNameMap qnameMap) { + this(qnameMap, new XmlFriendlyNameCoder()); } - public StaxDriver(QNameMap qnameMap, boolean repairingNamespace) { + /** + * @since 1.4 + */ + public StaxDriver(final QNameMap qnameMap, final NameCoder nameCoder) { + super(nameCoder); this.qnameMap = qnameMap; - this.repairingNamespace = repairingNamespace; } - public HierarchicalStreamReader createReader(Reader xml) { - loadLibrary(); + /** + * @since 1.4 + */ + public StaxDriver(final NameCoder nameCoder) { + this(new QNameMap(), nameCoder); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link StaxDriver#StaxDriver(QNameMap, NameCoder)} instead. + */ + @Deprecated + public StaxDriver(final QNameMap qnameMap, final XmlFriendlyReplacer replacer) { + this(qnameMap, (NameCoder)replacer); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link StaxDriver#StaxDriver(NameCoder)} instead. + */ + @Deprecated + public StaxDriver(final XmlFriendlyReplacer replacer) { + this(new QNameMap(), (NameCoder)replacer); + } + + @Override + public HierarchicalStreamReader createReader(final Reader xml) { try { - return new StaxReader(qnameMap, createParser(xml)); - } - catch (XMLStreamException e) { + return createStaxReader(createParser(xml)); + } catch (final XMLStreamException e) { throw new StreamException(e); } } - public HierarchicalStreamReader createReader(InputStream in) { - loadLibrary(); + @Override + public HierarchicalStreamReader createReader(final InputStream in) { try { - return new StaxReader(qnameMap, createParser(in)); - } - catch (XMLStreamException e) { + return createStaxReader(createParser(in)); + } catch (final XMLStreamException e) { throw new StreamException(e); } } - private void loadLibrary() { - if (!libraryPresent) { - try { - Class.forName("javax.xml.stream.XMLStreamReader"); - } - catch (ClassNotFoundException e) { - throw new IllegalArgumentException("StAX API is not present. Specify another driver." + - " For example: new XStream(new DomDriver())"); - } - libraryPresent = true; + @SuppressWarnings("resource") + @Override + public HierarchicalStreamReader createReader(final URL in) { + final InputStream stream; + try { + stream = in.openStream(); + final HierarchicalStreamReader reader = createStaxReader(createParser(new StreamSource(stream, in + .toExternalForm()))); + return new ReaderWrapper(reader) { + + @Override + public void close() { + super.close(); + try { + stream.close(); + } catch (final IOException e) { + // ignore + } + } + }; + } catch (final XMLStreamException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); } } - public HierarchicalStreamWriter createWriter(Writer out) { + @SuppressWarnings("resource") + @Override + public HierarchicalStreamReader createReader(final File in) { + final InputStream stream; try { - return new StaxWriter(qnameMap, getOutputFactory().createXMLStreamWriter(out), true, isRepairingNamespace()); - } - catch (XMLStreamException e) { + stream = new FileInputStream(in); + final HierarchicalStreamReader reader = createStaxReader(createParser(new StreamSource(stream, in + .toURI() + .toASCIIString()))); + return new ReaderWrapper(reader) { + + @Override + public void close() { + super.close(); + try { + stream.close(); + } catch (final IOException e) { + // ignore + } + } + }; + } catch (final XMLStreamException e) { throw new StreamException(e); + } catch (final FileNotFoundException e) { + throw new StreamException(e); } } - public HierarchicalStreamWriter createWriter(OutputStream out) { + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { try { - return new StaxWriter(qnameMap, getOutputFactory().createXMLStreamWriter(out), true, isRepairingNamespace()); + return createStaxWriter(getOutputFactory().createXMLStreamWriter(out)); + } catch (final XMLStreamException e) { + throw new StreamException(e); } - catch (XMLStreamException e) { + } + + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { + try { + return createStaxWriter(getOutputFactory().createXMLStreamWriter(out)); + } catch (final XMLStreamException e) { throw new StreamException(e); } } - public AbstractPullReader createStaxReader(XMLStreamReader in) { - return new StaxReader(qnameMap, in); + public AbstractPullReader createStaxReader(final XMLStreamReader in) { + return new StaxReader(qnameMap, in, getNameCoder()); } - public StaxWriter createStaxWriter(XMLStreamWriter out, boolean writeStartEndDocument) throws XMLStreamException { - return new StaxWriter(qnameMap, out, writeStartEndDocument, repairingNamespace); + public StaxWriter createStaxWriter(final XMLStreamWriter out, final boolean writeStartEndDocument) + throws XMLStreamException { + return new StaxWriter(qnameMap, out, writeStartEndDocument, isRepairingNamespace(), getNameCoder()); } - public StaxWriter createStaxWriter(XMLStreamWriter out) throws XMLStreamException { + public StaxWriter createStaxWriter(final XMLStreamWriter out) throws XMLStreamException { return createStaxWriter(out, true); } - // Properties - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- public QNameMap getQnameMap() { return qnameMap; } - public void setQnameMap(QNameMap qnameMap) { + public void setQnameMap(final QNameMap qnameMap) { this.qnameMap = qnameMap; } public XMLInputFactory getInputFactory() { if (inputFactory == null) { - inputFactory = XMLInputFactory.newInstance(); + inputFactory = createInputFactory(); } return inputFactory; } public XMLOutputFactory getOutputFactory() { if (outputFactory == null) { - outputFactory = XMLOutputFactory.newInstance(); - outputFactory.setProperty("javax.xml.stream.isRepairingNamespaces", isRepairingNamespace() ? Boolean.TRUE : Boolean.FALSE); + outputFactory = createOutputFactory(); } return outputFactory; } public boolean isRepairingNamespace() { - return repairingNamespace; + return Boolean.TRUE.equals(getOutputFactory().getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES)); } + /** + * @since 1.2 + */ + public void setRepairingNamespace(final boolean repairing) { + getOutputFactory().setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, + repairing ? Boolean.TRUE : Boolean.FALSE); + } // Implementation methods - //------------------------------------------------------------------------- - protected XMLStreamReader createParser(Reader xml) throws XMLStreamException { + // ------------------------------------------------------------------------- + protected XMLStreamReader createParser(final Reader xml) throws XMLStreamException { return getInputFactory().createXMLStreamReader(xml); } - protected XMLStreamReader createParser(InputStream xml) throws XMLStreamException { + protected XMLStreamReader createParser(final InputStream xml) throws XMLStreamException { return getInputFactory().createXMLStreamReader(xml); } + + protected XMLStreamReader createParser(final Source source) throws XMLStreamException { + return getInputFactory().createXMLStreamReader(source); + } + + /** + * @since 1.4 + */ + protected XMLInputFactory createInputFactory() { + return XMLInputFactory.newInstance(); + } + + /** + * @since 1.4 + */ + protected XMLOutputFactory createOutputFactory() { + return XMLOutputFactory.newInstance(); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxReader.java (.../StaxReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxReader.java (.../StaxReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,16 +1,29 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 29. September 2004 by James Strachan + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.converters.ErrorWriter; -import com.thoughtworks.xstream.io.StreamException; - import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + + /** * A reader using the StAX API. - * + * * @author James Strachan * @version $Revision$ */ @@ -19,69 +32,95 @@ private final QNameMap qnameMap; private final XMLStreamReader in; - public StaxReader(QNameMap qnameMap, XMLStreamReader in) { + public StaxReader(final QNameMap qnameMap, final XMLStreamReader in) { + this(qnameMap, in, new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4 + */ + public StaxReader(final QNameMap qnameMap, final XMLStreamReader in, final NameCoder replacer) { + super(replacer); this.qnameMap = qnameMap; this.in = in; moveDown(); } + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link StaxReader#StaxReader(QNameMap, XMLStreamReader, NameCoder)} instead. + */ + @Deprecated + public StaxReader(final QNameMap qnameMap, final XMLStreamReader in, final XmlFriendlyReplacer replacer) { + this(qnameMap, in, (NameCoder)replacer); + } + + @Override protected int pullNextEvent() { try { - switch(in.next()) { - case XMLStreamConstants.START_DOCUMENT: - case XMLStreamConstants.START_ELEMENT: - return START_NODE; - case XMLStreamConstants.END_DOCUMENT: - case XMLStreamConstants.END_ELEMENT: - return END_NODE; - case XMLStreamConstants.CHARACTERS: - return TEXT; - case XMLStreamConstants.COMMENT: - return COMMENT; - default: - return OTHER; + switch (in.next()) { + case XMLStreamConstants.START_DOCUMENT: + case XMLStreamConstants.START_ELEMENT: + return START_NODE; + case XMLStreamConstants.END_DOCUMENT: + case XMLStreamConstants.END_ELEMENT: + return END_NODE; + case XMLStreamConstants.CHARACTERS: + return TEXT; + case XMLStreamConstants.COMMENT: + return COMMENT; + default: + return OTHER; } - } catch (XMLStreamException e) { + } catch (final XMLStreamException e) { throw new StreamException(e); } } + @Override protected String pullElementName() { // let the QNameMap handle any mapping of QNames to Java class names - QName qname = in.getName(); + final QName qname = in.getName(); return qnameMap.getJavaClassName(qname); } + @Override protected String pullText() { return in.getText(); } - public String getAttribute(String name) { - return in.getAttributeValue(null, name); + @Override + public String getAttribute(final String name) { + return in.getAttributeValue(null, encodeAttribute(name)); } - public String getAttribute(int index) { + @Override + public String getAttribute(final int index) { return in.getAttributeValue(index); } + @Override public int getAttributeCount() { return in.getAttributeCount(); } - public String getAttributeName(int index) { - return in.getAttributeLocalName(index); + @Override + public String getAttributeName(final int index) { + return decodeAttribute(in.getAttributeLocalName(index)); } - public void appendErrors(ErrorWriter errorWriter) { + @Override + public void appendErrors(final ErrorWriter errorWriter) { errorWriter.add("line number", String.valueOf(in.getLocation().getLineNumber())); } + @Override public void close() { try { in.close(); - } catch (XMLStreamException e) { + } catch (final XMLStreamException e) { throw new StreamException(e); } } -} \ No newline at end of file +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxWriter.java (.../StaxWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/StaxWriter.java (.../StaxWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,39 +1,72 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2014 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 29. September 2004 by James Strachan + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.StreamException; - import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + + /** * A stream writing that outputs to a StAX stream writer - * + * * @author James Strachan * @version $Revision$ */ -public class StaxWriter implements HierarchicalStreamWriter { +public class StaxWriter extends AbstractXmlWriter { + private final QNameMap qnameMap; private final XMLStreamWriter out; private final boolean writeEnclosingDocument; - private boolean namespaceRepairingMode; + private final boolean namespaceRepairingMode; private int tagDepth; - public StaxWriter(QNameMap qnameMap, XMLStreamWriter out) throws XMLStreamException { + public StaxWriter(final QNameMap qnameMap, final XMLStreamWriter out) throws XMLStreamException { this(qnameMap, out, true, true); } /** * Allows a StaxWriter to be created for partial XML output - * - * @param qnameMap is the mapper of Java class names to QNames - * @param out the stream to output to + * + * @param qnameMap is the mapper of Java class names to QNames + * @param out the stream to output to + * @param nameCoder the xml-friendly replacer to escape Java names + * @throws XMLStreamException if the events could not be written to the output + * @since 1.4 + */ + public StaxWriter(final QNameMap qnameMap, final XMLStreamWriter out, final NameCoder nameCoder) + throws XMLStreamException { + this(qnameMap, out, true, true, nameCoder); + } + + /** + * Allows a StaxWriter to be created for partial XML output + * + * @param qnameMap is the mapper of Java class names to QNames + * @param out the stream to output to * @param writeEnclosingDocument a flag to indicate whether or not the start/end document events should be written + * @param namespaceRepairingMode a flag to enable StAX' namespace repairing mode + * @param nameCoder the xml-friendly replacer to escape Java names * @throws XMLStreamException if the events could not be written to the output + * @since 1.4 */ - public StaxWriter(QNameMap qnameMap, XMLStreamWriter out, boolean writeEnclosingDocument, boolean namespaceRepairingMode) throws XMLStreamException { + public StaxWriter( + final QNameMap qnameMap, final XMLStreamWriter out, final boolean writeEnclosingDocument, + final boolean namespaceRepairingMode, final NameCoder nameCoder) throws XMLStreamException { + super(nameCoder); this.qnameMap = qnameMap; this.out = out; this.writeEnclosingDocument = writeEnclosingDocument; @@ -43,121 +76,153 @@ } } + /** + * Allows a StaxWriter to be created for partial XML output + * + * @param qnameMap is the mapper of Java class names to QNames + * @param out the stream to output to + * @param writeEnclosingDocument a flag to indicate whether or not the start/end document events should be written + * @throws XMLStreamException if the events could not be written to the output + */ + public StaxWriter( + final QNameMap qnameMap, final XMLStreamWriter out, final boolean writeEnclosingDocument, + final boolean namespaceRepairingMode) throws XMLStreamException { + this(qnameMap, out, writeEnclosingDocument, namespaceRepairingMode, new XmlFriendlyNameCoder()); + } + + /** + * Allows a StaxWriter to be created for partial XML output + * + * @param qnameMap is the mapper of Java class names to QNames + * @param out the stream to output to + * @param writeEnclosingDocument a flag to indicate whether or not the start/end document events should be written + * @param replacer the xml-friendly replacer to escape Java names + * @throws XMLStreamException if the events could not be written to the output + * @since 1.2 + * @deprecated As of 1.4 use {@link StaxWriter#StaxWriter(QNameMap, XMLStreamWriter, boolean, boolean, NameCoder)} + * instead + */ + @Deprecated + public StaxWriter( + final QNameMap qnameMap, final XMLStreamWriter out, final boolean writeEnclosingDocument, + final boolean namespaceRepairingMode, final XmlFriendlyReplacer replacer) throws XMLStreamException { + this(qnameMap, out, writeEnclosingDocument, namespaceRepairingMode, (NameCoder)replacer); + } + + @Override public void flush() { try { - out.close(); - } - catch (XMLStreamException e) { + out.flush(); + } catch (final XMLStreamException e) { throw new StreamException(e); } } /** * Call this method when you're finished with me */ + @Override public void close() { try { out.close(); - } - catch (XMLStreamException e) { + } catch (final XMLStreamException e) { throw new StreamException(e); } } - public void addAttribute(String name, String value) { + @Override + public void addAttribute(final String name, final String value) { try { - out.writeAttribute(name, value); - } - catch (XMLStreamException e) { + out.writeAttribute(encodeAttribute(name), value); + } catch (final XMLStreamException e) { throw new StreamException(e); } } + @Override public void endNode() { try { tagDepth--; out.writeEndElement(); if (tagDepth == 0 && writeEnclosingDocument) { out.writeEndDocument(); } - } - catch (XMLStreamException e) { + } catch (final XMLStreamException e) { throw new StreamException(e); } } - public void setValue(String text) { + @Override + public void setValue(final String text) { try { out.writeCharacters(text); - } - catch (XMLStreamException e) { + } catch (final XMLStreamException e) { throw new StreamException(e); } } - public void startNode(String name) { + @Override + public void startNode(final String name) { try { - QName qname = qnameMap.getQName(name); - String prefix = qname.getPrefix(); - String uri = qname.getNamespaceURI(); + final QName qname = qnameMap.getQName(encodeNode(name)); + final String prefix = qname.getPrefix(); + final String uri = qname.getNamespaceURI(); // before you ask - yes it really is this complicated to output QNames to StAX // handling both repair namespace modes :) - boolean hasPrefix = prefix != null && prefix.length() > 0; - boolean hasURI = uri != null && uri.length() > 0; + final boolean hasPrefix = prefix != null && prefix.length() > 0; + final boolean hasURI = uri != null && uri.length() > 0; boolean writeNamespace = false; if (hasURI) { if (hasPrefix) { - String currentNamespace = out.getNamespaceContext().getNamespaceURI(prefix); + final String currentNamespace = out.getNamespaceContext().getNamespaceURI(prefix); if (currentNamespace == null || !currentNamespace.equals(uri)) { writeNamespace = true; } - } - else { - String defaultNamespace = out.getNamespaceContext().getNamespaceURI(""); + } else { + final String defaultNamespace = out.getNamespaceContext().getNamespaceURI(""); if (defaultNamespace == null || !defaultNamespace.equals(uri)) { writeNamespace = true; } } } + out.writeStartElement(prefix, qname.getLocalPart(), uri); if (hasPrefix) { out.setPrefix(prefix, uri); - } - else if (hasURI) { + } else if (hasURI) { if (writeNamespace) { out.setDefaultNamespace(uri); } } - out.writeStartElement(prefix, qname.getLocalPart(), uri); if (hasURI && writeNamespace && !isNamespaceRepairingMode()) { if (hasPrefix) { out.writeNamespace(prefix, uri); - } - else { + } else { out.writeDefaultNamespace(uri); } } tagDepth++; - } - catch (XMLStreamException e) { + } catch (final XMLStreamException e) { throw new StreamException(e); } } - public HierarchicalStreamWriter underlyingWriter() { - return this; - } - /** * Is StAX namespace repairing mode on or off? - * - * @return */ public boolean isNamespaceRepairingMode() { return namespaceRepairingMode; } + protected QNameMap getQNameMap() { + return qnameMap; + } + + protected XMLStreamWriter getXMLStreamWriter() { + return out; + } + } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/TraxSource.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/TraxSource.java (.../TraxSource.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/TraxSource.java (.../TraxSource.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,62 +1,72 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2013, 2014 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 14. August 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.XStream; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.transform.sax.SAXSource; + import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLFilter; import org.xml.sax.XMLReader; -import javax.xml.transform.sax.SAXSource; -import java.util.ArrayList; -import java.util.List; +import com.thoughtworks.xstream.XStream; + /** - * A {@link SAXSource JAXP TrAX Source} that enables using XStream - * object serialization as direct input for XSLT processors without - * resorting to an intermediate representation such as text XML, DOM - * or DOM4J. - *

    - * The following example shows how to apply an XSL Transformation - * to a set of Java objects gathered into a List - * (source):

    - *
    
    - *   public static String transform(List source, String stylesheet) {
    + * A {@link SAXSource JAXP TrAX Source} that enables using XStream object serialization as direct input for XSLT
    + * processors without resorting to an intermediate representation such as text XML, DOM or DOM4J.
    + * 

    + * The following example shows how to apply an XSL Transformation to a set of Java objects gathered into a List ( + * source): + *

    + * + *
    + * 
    + * public static String transform(List source, String stylesheet) {
      *     try {
    - *       Transformer transformer = TransformerFactory.newInstance()
    - *                             .newTransformer(new StreamSource(stylesheet));
    - *       XStreamSource in = new XStreamSource(source);
    - *       Writer out = new StringWriter();
    - *       transformer.transform(in, new StreamResult(out));
    - *       return out.toString();
    + *         Transformer transformer = TransformerFactory.newInstance().newTransformer(
    + *             new StreamSource(stylesheet));
    + *         TraxSource in = new TraxSource(source);
    + *         Writer out = new StringWriter();
    + *         transformer.transform(in, new StreamResult(out));
    + *         return out.toString();
    + *     } catch (TransformerException e) {
    + *         throw new RuntimeException("XSLT Transformation failed", e);
      *     }
    - *     catch (TransformerException e) {
    - *       throw new RuntimeException("XSLT Transformation failed", e);
    - *     }
    - *   }
    - * 
    - * + * } + *
    + *
    + * * @author Laurent Bihanic */ public class TraxSource extends SAXSource { /** - * If {@link javax.xml.transform.TransformerFactory#getFeature} - * returns true when passed this value as an - * argument, the Transformer natively supports XStream. - *

    - * Note: This implementation does not override - * the {@link SAXSource#FEATURE} value defined by its superclass - * to be considered as a SAXSource by Transformer implementations - * not natively supporting this XStream-specific source + * If {@link javax.xml.transform.TransformerFactory#getFeature} returns true when passed this value as + * an argument, the Transformer natively supports XStream. + *

    + * Note: This implementation does not override the {@link SAXSource#FEATURE} value defined by its + * superclass to be considered as a SAXSource by Transformer implementations not natively supporting this + * XStream-specific source *

    */ - public final static String XSTREAM_FEATURE = - "http://com.thoughtworks.xstream/XStreamSource/feature"; + public final static String XSTREAM_FEATURE = "http://com.thoughtworks.xstream/XStreamSource/feature"; /** - * The XMLReader object associated to this source or - * null if no XMLReader has yet been requested. - * + * The XMLReader object associated to this source or null if no XMLReader has yet been requested. + * * @see #getXMLReader */ private XMLReader xmlReader = null; @@ -69,12 +79,11 @@ /** * The list of Java objects to be serialized. */ - private List source = null; + private List source = null; - - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- // Constructors - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- /** * Creates a XStream TrAX source. @@ -84,226 +93,209 @@ } /** - * Creates a XStream TrAX source, specifying the object to - * marshal. - * + * Creates a XStream TrAX source, specifying the object to marshal. + * * @param source the object to marshal. - * @throws IllegalArgumentException if source is - * null. + * @throws IllegalArgumentException if source is null. * @see #setSource(java.lang.Object) */ - public TraxSource(Object source) { + public TraxSource(final Object source) { super(new InputSource()); - this.setSource(source); + setSource(source); } /** - * Creates a XStream TrAX source, specifying the object to - * marshal and a configured (with aliases) XStream facade. - * - * @param source the object to marshal. + * Creates a XStream TrAX source, specifying the object to marshal and a configured (with aliases) XStream facade. + * + * @param source the object to marshal. * @param xstream a configured XStream facade. - * @throws IllegalArgumentException if source or - * xstream is null. + * @throws IllegalArgumentException if source or xstream is null. * @see #setSource(java.lang.Object) * @see #setXStream(com.thoughtworks.xstream.XStream) */ - public TraxSource(Object source, XStream xstream) { + public TraxSource(final Object source, final XStream xstream) { super(new InputSource()); - this.setSource(source); - this.setXStream(xstream); + setSource(source); + setXStream(xstream); } /** - * Creates a XStream TrAX source, setting the objects to - * marshal. - * + * Creates a XStream TrAX source, setting the objects to marshal. + * * @param source the list of objects to marshal. - * @throws IllegalArgumentException if source is - * null or empty. + * @throws IllegalArgumentException if source is null or empty. * @see #setSourceAsList(java.util.List) */ - public TraxSource(List source) { + public TraxSource(final List source) { super(new InputSource()); - this.setSourceAsList(source); + setSourceAsList(source); } /** - * Creates a XStream TrAX source, setting the objects to - * marshal and a configured (with aliases) XStream facade. - * - * @param source the list of objects to marshal. + * Creates a XStream TrAX source, setting the objects to marshal and a configured (with aliases) XStream facade. + * + * @param source the list of objects to marshal. * @param xstream a configured XStream facade. - * @throws IllegalArgumentException if source or - * xstream is null or - * source is empty. + * @throws IllegalArgumentException if source or xstream is null or + * source is empty. * @see #setSourceAsList(java.util.List) * @see #setXStream(com.thoughtworks.xstream.XStream) */ - public TraxSource(List source, XStream xstream) { + public TraxSource(final List source, final XStream xstream) { super(new InputSource()); - this.setSourceAsList(source); - this.setXStream(xstream); + setSourceAsList(source); + setXStream(xstream); } - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- // SAXSource overwritten methods - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- /** * Sets the SAX InputSource to be used for the Source. - *

    - * As this implementation only supports object lists as data - * source, this method always throws an + *

    + * As this implementation only supports object lists as data source, this method always throws an * {@link UnsupportedOperationException}. *

    - * + * * @param inputSource a valid InputSource reference. * @throws UnsupportedOperationException always! */ - public void setInputSource(InputSource inputSource) { + @Override + public void setInputSource(final InputSource inputSource) { throw new UnsupportedOperationException(); } /** * Set the XMLReader to be used for the Source. - *

    - * As this implementation only supports object lists as data - * source, this method throws an - * {@link UnsupportedOperationException} if the provided reader - * object does not implement the SAX {@link XMLFilter} - * interface. Otherwise, a {@link SaxWriter} instance will be - * attached as parent of the filter chain.

    - * + *

    + * As this implementation only supports object lists as data source, this method throws an + * {@link UnsupportedOperationException} if the provided reader object does not implement the SAX {@link XMLFilter} + * interface. Otherwise, a {@link SaxWriter} instance will be attached as parent of the filter chain. + *

    + * * @param reader a valid XMLReader or XMLFilter reference. - * @throws UnsupportedOperationException if reader - * is not a SAX - * {@link XMLFilter}. + * @throws UnsupportedOperationException if reader is not a SAX {@link XMLFilter}. * @see #getXMLReader */ - public void setXMLReader(XMLReader reader) { - this.createXMLReader(reader); + @Override + public void setXMLReader(final XMLReader reader) { + createXMLReader(reader); } /** * Returns the XMLReader to be used for the Source. - *

    - * This implementation returns a specific XMLReader - * ({@link SaxWriter}) generating the XML from a list of input + *

    + * This implementation returns a specific XMLReader ({@link SaxWriter}) generating the XML from a list of input * objects. *

    - * - * @return an XMLReader generating the XML from a list of input - * objects. + * + * @return an XMLReader generating the XML from a list of input objects. */ + @Override public XMLReader getXMLReader() { - if (this.xmlReader == null) { - this.createXMLReader(null); + if (xmlReader == null) { + createXMLReader(null); } - return this.xmlReader; + return xmlReader; } - - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- // Specific implementation - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- /** * Sets the XStream facade to use when marshalling objects. - * + * * @param xstream a configured XStream facade. - * @throws IllegalArgumentException if xstream is - * null. + * @throws IllegalArgumentException if xstream is null. */ - public void setXStream(XStream xstream) { + public void setXStream(final XStream xstream) { if (xstream == null) { throw new IllegalArgumentException("xstream"); } this.xstream = xstream; - this.configureXMLReader(); + configureXMLReader(); } /** * Sets the object to marshal. - * + * * @param obj the object to marshal. - * @throws IllegalArgumentException if source is - * null. + * @throws IllegalArgumentException if source is null. */ - public void setSource(Object obj) { + public void setSource(final Object obj) { if (obj == null) { throw new IllegalArgumentException("obj"); } - List list = new ArrayList(1); + final List list = new ArrayList(1); list.add(obj); - this.setSourceAsList(list); + setSourceAsList(list); } /** * Sets the list of objects to marshal. - *

    - * When dealing with non-text input (such as SAX or DOM), XSLT - * processors support multiple root node children for the source - * tree (see - * section 3.1 - * of the "XSL Transformations (XSLT) Version 1.0" - * specification. Using a list of objects as source makes use - * of this feature and allows creating XML documents merging - * the XML serialization of several Java objects. - * + *

    + * When dealing with non-text input (such as SAX or DOM), XSLT processors support multiple root node children for + * the source tree (see section 3.1 of the "XSL + * Transformations (XSLT) Version 1.0" specification. Using a list of objects as source makes use of this + * feature and allows creating XML documents merging the XML serialization of several Java objects. + * * @param list the list of objects to marshal. - * @throws IllegalArgumentException if source is - * null or empty. + * @throws IllegalArgumentException if source is null or empty. */ - public void setSourceAsList(List list) { - if ((list == null) || (list.isEmpty())) { + public void setSourceAsList(final List list) { + if (list == null || list.isEmpty()) { throw new IllegalArgumentException("list"); } - this.source = list; + source = list; - this.configureXMLReader(); + configureXMLReader(); } - private void createXMLReader(XMLReader filterChain) { + private void createXMLReader(final XMLReader filterChain) { if (filterChain == null) { - this.xmlReader = new SaxWriter(); + xmlReader = new SaxWriter(); } else { if (filterChain instanceof XMLFilter) { // Connect the filter chain to a document reader. - XMLFilter filter = (XMLFilter) filterChain; + XMLFilter filter = (XMLFilter)filterChain; while (filter.getParent() instanceof XMLFilter) { - filter = (XMLFilter) (filter.getParent()); + filter = (XMLFilter)filter.getParent(); } - filter.setParent(new SaxWriter()); + if (!(filter.getParent() instanceof SaxWriter)) { + @SuppressWarnings("resource") + final SaxWriter saxWriter = new SaxWriter(); + filter.setParent(saxWriter); + } // Read XML data from filter chain. - this.xmlReader = filterChain; + xmlReader = filterChain; } else { throw new UnsupportedOperationException(); } } - this.configureXMLReader(); + configureXMLReader(); } private void configureXMLReader() { - if (this.xmlReader != null) { + if (xmlReader != null) { try { - if (this.xstream != null) { - this.xmlReader.setProperty(SaxWriter.CONFIGURED_XSTREAM_PROPERTY, this.xstream); + if (xstream != null) { + xmlReader.setProperty(SaxWriter.CONFIGURED_XSTREAM_PROPERTY, xstream); } - if (this.source != null) { - this.xmlReader.setProperty(SaxWriter.SOURCE_OBJECT_LIST_PROPERTY, this.source); + if (source != null) { + xmlReader.setProperty(SaxWriter.SOURCE_OBJECT_LIST_PROPERTY, source); } - } catch (SAXException e) { + } catch (final SAXException e) { throw new IllegalArgumentException(e.getMessage()); } } } } - Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/WstxDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/WstxDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/WstxDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 29. April 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; + +import com.ctc.wstx.stax.WstxInputFactory; +import com.ctc.wstx.stax.WstxOutputFactory; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * A driver using the Woodstox StAX implementation. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class WstxDriver extends StaxDriver { + + public WstxDriver() { + super(); + } + + /** + * @deprecated As of 1.4.6 use {@link #WstxDriver(QNameMap, NameCoder)} + */ + @Deprecated + public WstxDriver(final QNameMap qnameMap, final XmlFriendlyNameCoder nameCoder) { + super(qnameMap, nameCoder); + } + + /** + * @since 1.4.6 + */ + public WstxDriver(final QNameMap qnameMap, final NameCoder nameCoder) { + super(qnameMap, nameCoder); + } + + public WstxDriver(final QNameMap qnameMap) { + super(qnameMap); + } + + /** + * @deprecated As of 1.4.6 use {@link #WstxDriver(NameCoder)} + */ + @Deprecated + public WstxDriver(final XmlFriendlyNameCoder nameCoder) { + super(nameCoder); + } + + /** + * @since 1.4.6 + */ + public WstxDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + protected XMLInputFactory createInputFactory() { + return new WstxInputFactory(); + } + + @Override + protected XMLOutputFactory createOutputFactory() { + return new WstxOutputFactory(); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XStream11NameCoder.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XStream11NameCoder.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XStream11NameCoder.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 15. August 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +/** + * A XmlFriendlyNameCoder to support backward compatibility with XStream 1.1. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class XStream11NameCoder extends XmlFriendlyNameCoder { + + /** + * {@inheritDoc} Noop implementation that does not decode. Used for XStream 1.1 compatibility. + */ + @Override + public String decodeAttribute(final String attributeName) { + return attributeName; + } + + /** + * {@inheritDoc} Noop implementation that does not decode. Used for XStream 1.1 compatibility. + */ + @Override + public String decodeNode(final String elementName) { + return elementName; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XStream11XmlFriendlyReplacer.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XStream11XmlFriendlyReplacer.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XStream11XmlFriendlyReplacer.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 22. April 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.io.xml; + +/** + * Allows replacement of Strings in xml-friendly drivers to provide compatibility with XStream 1.1 format + * + * @author Mauro Talevi + * @since 1.2 + * @deprecated As of 1.4, use {@link XStream11NameCoder} instead + */ +@Deprecated +public class XStream11XmlFriendlyReplacer extends XmlFriendlyReplacer { + + /** + * Default constructor. + * + * @deprecated As of 1.4, use {@link XStream11NameCoder} instead + */ + @Deprecated + public XStream11XmlFriendlyReplacer() { + } + + /** + * {@inheritDoc} Noop implementation that does not decode. Used for XStream 1.1 compatibility. + */ + @Override + public String decodeAttribute(final String attributeName) { + return attributeName; + } + + /** + * {@inheritDoc} Noop implementation that does not decode. Used for XStream 1.1 compatibility. + */ + @Override + public String decodeNode(final String elementName) { + return elementName; + } + + /** + * Noop implementation that does not unescape name. Used for XStream 1.1 compatibility. + * + * @param name the name of attribute or node + * @return The String with unescaped name + */ + @Override + public String unescapeName(final String name) { + return name; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyNameCoder.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyNameCoder.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyNameCoder.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014 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 15. August 2009 by Joerg Schaible, copied from XmlFriendlyReplacer. + */ +package com.thoughtworks.xstream.io.xml; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * Encode and decode tag and attribute names in XML drivers. + *

    + * This NameCoder is designed to ensure the correct encoding and decoding of names used for Java types and fields to XML + * tags and attribute names. + *

    + *

    + * The default replacements are: + *

    + *
      + *
    • $ (dollar) chars are replaced with _- (underscore dash) string.
    • + *
    • _ (underscore) chars are replaced with __ (double underscore) string.
    • + *
    • other characters that are invalid in XML names are encoded with _.XXXX (underscore dot followed by hex + * representation of character).
    • + *
    + * + * @author Jörg Schaible + * @author Mauro Talevi + * @author Tatu Saloranta + * @author Michael Schnell + * @see XML 1.0 name definition + * @see XML 1.1 name definition + * @see Java identifier definition + * @since 1.4 + */ +public class XmlFriendlyNameCoder implements NameCoder, Cloneable { + private static final IntPair[] XML_NAME_START_CHAR_BOUNDS; + private static final IntPair[] XML_NAME_CHAR_EXTRA_BOUNDS; + static { + class IntPairList extends ArrayList { + void add(final int min, final int max) { + super.add(new IntPair(min, max)); + } + + void add(final char cp) { + super.add(new IntPair(cp, cp)); + } + } + + // legal characters in XML names according to + // http://www.w3.org/TR/REC-xml/#NT-Name and + // http://www.w3.org/TR/xml11/#NT-Name + final IntPairList list = new IntPairList(); + + list.add(':'); + list.add('A', 'Z'); + list.add('a', 'z'); + list.add('_'); + + list.add(0xC0, 0xD6); + list.add(0xD8, 0xF6); + list.add(0xF8, 0x2FF); + list.add(0x370, 0x37D); + list.add(0x37F, 0x1FFF); + list.add(0x200C, 0x200D); + list.add(0x2070, 0x218F); + list.add(0x2C00, 0x2FEF); + list.add(0x3001, 0xD7FF); + list.add(0xF900, 0xFDCF); + list.add(0xFDF0, 0xFFFD); + list.add(0x10000, 0xEFFFF); + XML_NAME_START_CHAR_BOUNDS = list.toArray(new IntPair[list.size()]); + + list.clear(); + list.add('-'); + list.add('.'); + list.add('0', '9'); + list.add('\u00b7'); + list.add(0x0300, 0x036F); + list.add(0x203F, 0x2040); + XML_NAME_CHAR_EXTRA_BOUNDS = list.toArray(new IntPair[list.size()]); + } + + private final String dollarReplacement; + private final String escapeCharReplacement; + private transient Map escapeCache; + private transient Map unescapeCache; + private final String hexPrefix; + + /** + * Construct a new XmlFriendlyNameCoder. + * + * @since 1.4 + */ + public XmlFriendlyNameCoder() { + this("_-", "__"); + } + + /** + * Construct a new XmlFriendlyNameCoder with custom replacement strings for dollar and the escape character. + * + * @param dollarReplacement + * @param escapeCharReplacement + * @since 1.4 + */ + public XmlFriendlyNameCoder(final String dollarReplacement, final String escapeCharReplacement) { + this(dollarReplacement, escapeCharReplacement, "_."); + } + + /** + * Construct a new XmlFriendlyNameCoder with custom replacement strings for dollar, the escape character and the + * prefix for hexadecimal encoding of invalid characters in XML names. + * + * @param dollarReplacement + * @param escapeCharReplacement + * @since 1.4 + */ + public XmlFriendlyNameCoder( + final String dollarReplacement, final String escapeCharReplacement, final String hexPrefix) { + this.dollarReplacement = dollarReplacement; + this.escapeCharReplacement = escapeCharReplacement; + this.hexPrefix = hexPrefix; + readResolve(); + } + + @Override + public String decodeAttribute(final String attributeName) { + return decodeName(attributeName); + } + + @Override + public String decodeNode(final String elementName) { + return decodeName(elementName); + } + + @Override + public String encodeAttribute(final String name) { + return encodeName(name); + } + + @Override + public String encodeNode(final String name) { + return encodeName(name); + } + + private String encodeName(final String name) { + String s = escapeCache.get(name); + if (s == null) { + final int length = name.length(); + + // First, fast (common) case: nothing to escape + int i = 0; + + for (; i < length; i++) { + final char c = name.charAt(i); + if (c == '$' || c == '_' || c <= 27 || c >= 127) { + break; + } + } + + if (i == length) { + return name; + } + + // Otherwise full processing + final StringBuffer result = new StringBuffer(length + 8); + + // We know first N chars are safe + if (i > 0) { + result.append(name.substring(0, i)); + } + + for (; i < length; i++) { + final char c = name.charAt(i); + if (c == '$') { + result.append(dollarReplacement); + } else if (c == '_') { + result.append(escapeCharReplacement); + } else if (i == 0 && !isXmlNameStartChar(c) || i > 0 && !isXmlNameChar(c)) { + result.append(hexPrefix); + if (c < 16) { + result.append("000"); + } else if (c < 256) { + result.append("00"); + } else if (c < 4096) { + result.append("0"); + } + result.append(Integer.toHexString(c)); + } else { + result.append(c); + } + } + s = result.toString(); + escapeCache.put(name, s); + } + return s; + } + + private String decodeName(final String name) { + String s = unescapeCache.get(name); + if (s == null) { + final char dollarReplacementFirstChar = dollarReplacement.charAt(0); + final char escapeReplacementFirstChar = escapeCharReplacement.charAt(0); + final char hexPrefixFirstChar = hexPrefix.charAt(0); + final int length = name.length(); + + // First, fast (common) case: nothing to decode + int i = 0; + + for (; i < length; i++) { + final char c = name.charAt(i); + // We'll do a quick check for potential match + if (c == dollarReplacementFirstChar || c == escapeReplacementFirstChar || c == hexPrefixFirstChar) { + // and if it might be a match, just quit, will check later on + break; + } + } + + if (i == length) { + return name; + } + + // Otherwise full processing + final StringBuffer result = new StringBuffer(length + 8); + + // We know first N chars are safe + if (i > 0) { + result.append(name.substring(0, i)); + } + + for (; i < length; i++) { + char c = name.charAt(i); + if (c == dollarReplacementFirstChar && name.startsWith(dollarReplacement, i)) { + i += dollarReplacement.length() - 1; + result.append('$'); + } else if (c == hexPrefixFirstChar && name.startsWith(hexPrefix, i)) { + i += hexPrefix.length(); + c = (char)Integer.parseInt(name.substring(i, i + 4), 16); + i += 3; + result.append(c); + } else if (c == escapeReplacementFirstChar && name.startsWith(escapeCharReplacement, i)) { + i += escapeCharReplacement.length() - 1; + result.append('_'); + } else { + result.append(c); + } + } + + s = result.toString(); + unescapeCache.put(name, s); + } + return s; + } + + @Override + public Object clone() { + try { + final XmlFriendlyNameCoder coder = (XmlFriendlyNameCoder)super.clone(); + coder.readResolve(); + return coder; + + } catch (final CloneNotSupportedException e) { + throw new ObjectAccessException("Cannot clone XmlFriendlyNameCoder", e); + } + } + + private Object readResolve() { + escapeCache = createCacheMap(); + unescapeCache = createCacheMap(); + return this; + } + + protected Map createCacheMap() { + return new HashMap(); + } + + private static class IntPair { + int min; + int max; + + public IntPair(final int min, final int max) { + this.min = min; + this.max = max; + } + } + + private static boolean isXmlNameStartChar(final int cp) { + return isInNameCharBounds(cp, XML_NAME_START_CHAR_BOUNDS); + } + + private static boolean isXmlNameChar(final int cp) { + if (isXmlNameStartChar(cp)) { + return true; + } + return isInNameCharBounds(cp, XML_NAME_CHAR_EXTRA_BOUNDS); + } + + private static boolean isInNameCharBounds(final int cp, final IntPair[] nameCharBounds) { + for (final IntPair p : nameCharBounds) { + if (cp >= p.min && cp <= p.max) { + return true; + } + } + return false; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyReader.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyReader.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyReader.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2011, 2014 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 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +/** + * An interface for a {@link com.thoughtworks.xstream.io.HierarchicalStreamReader} supporting XML-friendly names. + * + * @author Jörg Schaible + * @author Mauro Talevi + * @since 1.3 + * @deprecated As of 1.4 + */ +@Deprecated +public interface XmlFriendlyReader { + + /** + * Unescapes XML-friendly name (node or attribute) + * + * @param name the escaped XML-friendly name + * @return An unescaped name with original characters + * @deprecated As of 1.4 + */ + @Deprecated + String unescapeXmlName(String name); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyReplacer.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyReplacer.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyReplacer.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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 17. April 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.io.xml; + +/** + * Allows replacement of Strings in XML-friendly drivers. The default replacements are: + *
      + *
    • $ (dollar) chars are replaced with _- (underscore dash) string.
      + *
    • + *
    • _ (underscore) chars are replaced with __ (double underscore) string.
      + *
    • + *
    + * + * @author Mauro Talevi + * @author Jörg Schaible + * @author Tatu Saloranta + * @since 1.2 + * @deprecated As of 1.4, use {@link XmlFriendlyNameCoder} instead + */ +@Deprecated +public class XmlFriendlyReplacer extends XmlFriendlyNameCoder { + + /** + * Default constructor. + * + * @deprecated As of 1.4, use {@link XmlFriendlyNameCoder} instead + */ + @Deprecated + public XmlFriendlyReplacer() { + this("_-", "__"); + } + + /** + * Creates an XmlFriendlyReplacer with custom replacements + * + * @param dollarReplacement the replacement for '$' + * @param underscoreReplacement the replacement for '_' + * @deprecated As of 1.4, use {@link XmlFriendlyNameCoder} instead + */ + @Deprecated + public XmlFriendlyReplacer(final String dollarReplacement, final String underscoreReplacement) { + super(dollarReplacement, underscoreReplacement); + } + + /** + * Escapes name substituting '$' and '_' with replacement strings + * + * @param name the name of attribute or node + * @return The String with the escaped name + * @deprecated As of 1.4, use {@link XmlFriendlyNameCoder} instead + */ + @Deprecated + public String escapeName(final String name) { + return super.encodeNode(name); + } + + /** + * Unescapes name re-enstating '$' and '_' when replacement strings are found + * + * @param name the name of attribute or node + * @return The String with unescaped name + * @deprecated As of 1.4, use {@link XmlFriendlyNameCoder} instead + */ + @Deprecated + public String unescapeName(final String name) { + return super.decodeNode(name); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyWriter.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyWriter.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XmlFriendlyWriter.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2011, 2014 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 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +/** + * An interface for a {@link com.thoughtworks.xstream.io.HierarchicalStreamWriter} supporting XML-friendly names. + * + * @author Jörg Schaible + * @author Mauro Talevi + * @since 1.3 + * @deprecated As of 1.4 + */ +@Deprecated +public interface XmlFriendlyWriter { + + /** + * Escapes XML name (node or attribute) to be XML-friendly + * + * @param name the unescaped XML name + * @return An escaped name with original characters replaced + * @deprecated As of 1.4 + */ + @Deprecated + String escapeXmlName(String name); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 12. April 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + +import nu.xom.Builder; +import nu.xom.Document; +import nu.xom.ParsingException; +import nu.xom.ValidityException; + + +public class XomDriver extends AbstractXmlDriver { + + private final Builder builder; + + public XomDriver() { + this(new Builder()); + } + + public XomDriver(final Builder builder) { + this(builder, new XmlFriendlyNameCoder()); + } + + /** + * @since 1.4 + */ + public XomDriver(final NameCoder nameCoder) { + this(new Builder(), nameCoder); + } + + /** + * @since 1.4 + */ + public XomDriver(final Builder builder, final NameCoder nameCoder) { + super(nameCoder); + this.builder = builder; + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link #XomDriver(Builder, NameCoder)} instead + */ + @Deprecated + public XomDriver(final XmlFriendlyReplacer replacer) { + this(new Builder(), replacer); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link #XomDriver(Builder, NameCoder)} instead + */ + @Deprecated + public XomDriver(final Builder builder, final XmlFriendlyReplacer replacer) { + this((NameCoder)replacer); + } + + protected Builder getBuilder() { + return builder; + } + + @Override + public HierarchicalStreamReader createReader(final Reader text) { + try { + final Document document = builder.build(text); + return new XomReader(document, getNameCoder()); + } catch (final ValidityException e) { + throw new StreamException(e); + } catch (final ParsingException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamReader createReader(final InputStream in) { + try { + final Document document = builder.build(in); + return new XomReader(document, getNameCoder()); + } catch (final ValidityException e) { + throw new StreamException(e); + } catch (final ParsingException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamReader createReader(final URL in) { + try { + final Document document = builder.build(in.toExternalForm()); + return new XomReader(document, getNameCoder()); + } catch (final ValidityException e) { + throw new StreamException(e); + } catch (final ParsingException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamReader createReader(final File in) { + try { + final Document document = builder.build(in); + return new XomReader(document, getNameCoder()); + } catch (final ValidityException e) { + throw new StreamException(e); + } catch (final ParsingException e) { + throw new StreamException(e); + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { + return new PrettyPrintWriter(out, getNameCoder()); + } + + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { + return new PrettyPrintWriter(new OutputStreamWriter(out), getNameCoder()); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomReader.java (.../XomReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomReader.java (.../XomReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,66 +1,135 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 02. September 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import nu.xom.*; +import com.thoughtworks.xstream.io.naming.NameCoder; +import nu.xom.Document; +import nu.xom.Element; +import nu.xom.Elements; +import nu.xom.Node; +import nu.xom.Text; + + public class XomReader extends AbstractDocumentReader { private Element currentElement; - public XomReader(Element rootElement) { + public XomReader(final Element rootElement) { super(rootElement); } - public XomReader(Document document) { + public XomReader(final Document document) { super(document.getRootElement()); } + /** + * @since 1.4 + */ + public XomReader(final Element rootElement, final NameCoder nameCoder) { + super(rootElement, nameCoder); + } + + /** + * @since 1.4 + */ + public XomReader(final Document document, final NameCoder nameCoder) { + super(document.getRootElement(), nameCoder); + } + + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link XomReader#XomReader(Element, NameCoder)} instead. + */ + @Deprecated + public XomReader(final Element rootElement, final XmlFriendlyReplacer replacer) { + this(rootElement, (NameCoder)replacer); + } + + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link XomReader#XomReader(Element, NameCoder)} instead. + */ + @Deprecated + public XomReader(final Document document, final XmlFriendlyReplacer replacer) { + this(document.getRootElement(), (NameCoder)replacer); + } + + @Override public String getNodeName() { - return currentElement.getLocalName(); + return decodeNode(currentElement.getLocalName()); } + @Override public String getValue() { // currentElement.getValue() not used as this includes text of child elements, which we don't want. - StringBuffer result = new StringBuffer(); - int childCount = currentElement.getChildCount(); - for(int i = 0; i < childCount; i++) { - Node child = currentElement.getChild(i); + final StringBuffer result = new StringBuffer(); + final int childCount = currentElement.getChildCount(); + for (int i = 0; i < childCount; i++) { + final Node child = currentElement.getChild(i); if (child instanceof Text) { - Text text = (Text) child; + final Text text = (Text)child; result.append(text.getValue()); } } return result.toString(); } - public String getAttribute(String name) { - return currentElement.getAttributeValue(name); + @Override + public String getAttribute(final String name) { + return currentElement.getAttributeValue(encodeAttribute(name)); } - public String getAttribute(int index) { + @Override + public String getAttribute(final int index) { return currentElement.getAttribute(index).getValue(); } + @Override public int getAttributeCount() { return currentElement.getAttributeCount(); } - public String getAttributeName(int index) { - return currentElement.getAttribute(index).getQualifiedName(); + @Override + public String getAttributeName(final int index) { + return decodeAttribute(currentElement.getAttribute(index).getQualifiedName()); } + @Override protected int getChildCount() { return currentElement.getChildElements().size(); } + @Override protected Object getParent() { return currentElement.getParent(); } - protected Object getChild(int index) { + @Override + protected Object getChild(final int index) { return currentElement.getChildElements().get(index); } - protected void reassignCurrentElement(Object current) { - currentElement = (Element) current; + @Override + protected void reassignCurrentElement(final Object current) { + currentElement = (Element)current; } + + @Override + public String peekNextChild() { + final Elements children = currentElement.getChildElements(); + if (null == children || children.size() == 0) { + return null; + } + return decodeNode(children.get(0).getLocalName()); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomWriter.java (.../XomWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XomWriter.java (.../XomWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,44 +1,72 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 03. September 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import nu.xom.Element; +import com.thoughtworks.xstream.io.naming.NameCoder; + import nu.xom.Attribute; +import nu.xom.Element; -public class XomWriter implements HierarchicalStreamWriter { - private Element node; +public class XomWriter extends AbstractDocumentWriter { - public XomWriter(Element parentElement) { - this.node = parentElement; + /** + * @since 1.2.1 + */ + public XomWriter() { + this(null); } - public void startNode(String name) { - Element newNode = new Element(name); - node.appendChild(newNode); - node = newNode; + public XomWriter(final Element parentElement) { + this(parentElement, new XmlFriendlyNameCoder()); } - public void addAttribute(String name, String value) { - node.addAttribute(new Attribute(name, value)); + /** + * @since 1.4 + */ + public XomWriter(final Element parentElement, final NameCoder nameCoder) { + super(parentElement, nameCoder); } - public void setValue(String text) { - node.appendChild(text); + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link XomWriter#XomWriter(Element, NameCoder)} instead + */ + @Deprecated + public XomWriter(final Element parentElement, final XmlFriendlyReplacer replacer) { + this(parentElement, (NameCoder)replacer); } - public void endNode() { - node = (Element) node.getParent(); + @Override + protected Object createNode(final String name) { + final Element newNode = new Element(encodeNode(name)); + final Element top = top(); + if (top != null) { + top().appendChild(newNode); + } + return newNode; } - public void flush() { - // don't need to do anything + @Override + public void addAttribute(final String name, final String value) { + top().addAttribute(new Attribute(encodeAttribute(name), value)); } - public void close() { - // don't need to do anything + @Override + public void setValue(final String text) { + top().appendChild(text); } - public HierarchicalStreamWriter underlyingWriter() { - return this; + private Element top() { + return (Element)getCurrent(); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Xpp3DomDriver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Xpp3DomDriver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Xpp3DomDriver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 03. May 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import org.xmlpull.mxp1.MXParser; +import org.xmlpull.v1.XmlPullParser; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * A {@link HierarchicalStreamDriver} for XPP DOM using the Xpp3 parser. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class Xpp3DomDriver extends AbstractXppDomDriver { + + /** + * Construct an Xpp3DomDriver. + * + * @since 1.4 + */ + public Xpp3DomDriver() { + super(new XmlFriendlyNameCoder()); + } + + /** + * Construct an Xpp3DomDriver. + * + * @param nameCoder the replacer for XML friendly names + * @since 1.4 + */ + public Xpp3DomDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + protected XmlPullParser createParser() { + return new MXParser(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Xpp3Driver.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Xpp3Driver.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/Xpp3Driver.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 29. April 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import org.xmlpull.mxp1.MXParser; +import org.xmlpull.v1.XmlPullParser; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * A {@link HierarchicalStreamDriver} using the Xpp3 parser. + * + * @author Jörg Schaible + * @since 1.4 + */ +public class Xpp3Driver extends AbstractXppDriver { + + /** + * Construct an Xpp3Driver. + * + * @since 1.4 + */ + public Xpp3Driver() { + super(new XmlFriendlyNameCoder()); + } + + /** + * Construct an Xpp3Driver. + * + * @param nameCoder the replacer for XML friendly names + * @since 1.4 + */ + public Xpp3Driver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + protected XmlPullParser createParser() { + return new MXParser(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomDriver.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomDriver.java (.../XppDomDriver.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomDriver.java (.../XppDomDriver.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,32 +1,59 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + import com.thoughtworks.xstream.io.HierarchicalStreamDriver; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import com.thoughtworks.xstream.io.StreamException; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.xml.xppdom.Xpp3DomBuilder; +import com.thoughtworks.xstream.io.naming.NameCoder; -import java.io.*; -public class XppDomDriver implements HierarchicalStreamDriver { +/** + * A {@link HierarchicalStreamDriver} for XPP DOM using the XmlPullParserFactory to locate an parser. + * + * @author Joe Walnes + * @author Jörg Schaible + */ +public class XppDomDriver extends AbstractXppDomDriver { - public HierarchicalStreamReader createReader(Reader xml) { - try { - return new XppDomReader(Xpp3DomBuilder.build(xml)); - } catch (Exception e) { - throw new StreamException(e); - } + private static XmlPullParserFactory factory; + + public XppDomDriver() { + super(new XmlFriendlyNameCoder()); } - public HierarchicalStreamReader createReader(InputStream in) { - return createReader(new InputStreamReader(in)); + /** + * @since 1.4 + */ + public XppDomDriver(final NameCoder nameCoder) { + super(nameCoder); } - public HierarchicalStreamWriter createWriter(Writer out) { - return new PrettyPrintWriter(out); + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link XppDomDriver#XppDomDriver(NameCoder)} instead. + */ + @Deprecated + public XppDomDriver(final XmlFriendlyReplacer replacer) { + super(replacer); } - public HierarchicalStreamWriter createWriter(OutputStream out) { - return createWriter(new OutputStreamWriter(out)); + @Override + protected synchronized XmlPullParser createParser() throws XmlPullParserException { + if (factory == null) { + factory = XmlPullParserFactory.newInstance(null, XppDomDriver.class); + } + return factory.newPullParser(); } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomReader.java (.../XppDomReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomReader.java (.../XppDomReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,65 +1,111 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.xml.xppdom.Xpp3Dom; +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.xml.xppdom.XppDom; + /** - * @author Jason van Zyl - * @version $Id$ + * @author Jason van Zyl */ public class XppDomReader extends AbstractDocumentReader { - private Xpp3Dom currentElement; + private XppDom currentElement; - public XppDomReader(Xpp3Dom xpp3Dom) { - super(xpp3Dom); + public XppDomReader(final XppDom xppDom) { + super(xppDom); } + /** + * @since 1.4 + */ + public XppDomReader(final XppDom xppDom, final NameCoder nameCoder) { + super(xppDom, nameCoder); + } + + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link XppDomReader#XppDomReader(XppDom, NameCoder)} instead. + */ + @Deprecated + public XppDomReader(final XppDom xppDom, final XmlFriendlyReplacer replacer) { + this(xppDom, (NameCoder)replacer); + } + + @Override public String getNodeName() { - return currentElement.getName(); + return decodeNode(currentElement.getName()); } + @Override public String getValue() { String text = null; try { text = currentElement.getValue(); - } catch (Exception e) { + } catch (final Exception e) { // do nothing. } return text == null ? "" : text; } - public String getAttribute(String attributeName) { - return currentElement.getAttribute(attributeName); + @Override + public String getAttribute(final String attributeName) { + return currentElement.getAttribute(encodeAttribute(attributeName)); } - public String getAttribute(int index) { + @Override + public String getAttribute(final int index) { return currentElement.getAttribute(currentElement.getAttributeNames()[index]); } + @Override public int getAttributeCount() { return currentElement.getAttributeNames().length; } - public String getAttributeName(int index) { - return currentElement.getAttributeNames()[index]; + @Override + public String getAttributeName(final int index) { + return decodeAttribute(currentElement.getAttributeNames()[index]); } + @Override protected Object getParent() { return currentElement.getParent(); } - protected Object getChild(int index) { + @Override + protected Object getChild(final int index) { return currentElement.getChild(index); } + @Override protected int getChildCount() { return currentElement.getChildCount(); } - protected void reassignCurrentElement(Object current) { - this.currentElement = (Xpp3Dom) current; + @Override + protected void reassignCurrentElement(final Object current) { + currentElement = (XppDom)current; } + @Override + public String peekNextChild() { + if (currentElement.getChildCount() == 0) { + return null; + } + return decodeNode(currentElement.getChild(0).getName()); + } + } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomWriter.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomWriter.java (.../XppDomWriter.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDomWriter.java (.../XppDomWriter.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,60 +1,89 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.xml.xppdom.Xpp3Dom; +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.xml.xppdom.XppDom; -import java.util.LinkedList; -public class XppDomWriter implements HierarchicalStreamWriter { - private LinkedList elementStack = new LinkedList(); - - private Xpp3Dom configuration; - +public class XppDomWriter extends AbstractDocumentWriter { public XppDomWriter() { + this(null, new XmlFriendlyNameCoder()); } - public Xpp3Dom getConfiguration() { - return configuration; + /** + * @since 1.2.1 + */ + public XppDomWriter(final XppDom parent) { + this(parent, new XmlFriendlyNameCoder()); } - public void startNode(String name) { - Xpp3Dom configuration = new Xpp3Dom(name); + /** + * @since 1.4 + */ + public XppDomWriter(final NameCoder nameCoder) { + this(null, nameCoder); + } - if (this.configuration == null) { - this.configuration = configuration; - } else { - top().addChild(configuration); - } - - elementStack.addLast(configuration); + /** + * @since 1.4 + */ + public XppDomWriter(final XppDom parent, final NameCoder nameCoder) { + super(parent, nameCoder); } - public void setValue(String text) { - top().setValue(text); + /** + * @since 1.2 + * @deprecated As of 1.4 use {@link XppDomWriter#XppDomWriter(NameCoder)} instead + */ + @Deprecated + public XppDomWriter(final XmlFriendlyReplacer replacer) { + this(null, replacer); } - public void addAttribute(String key, String value) { - top().setAttribute(key, value); + /** + * @since 1.2.1 + * @deprecated As of 1.4 use {@link XppDomWriter#XppDomWriter(XppDom, NameCoder)} instead. + */ + @Deprecated + public XppDomWriter(final XppDom parent, final XmlFriendlyReplacer replacer) { + this(parent, (NameCoder)replacer); } - public void endNode() { - elementStack.removeLast(); + public XppDom getConfiguration() { + return (XppDom)getTopLevelNodes().get(0); } - private Xpp3Dom top() { - return (Xpp3Dom) elementStack.getLast(); + @Override + protected Object createNode(final String name) { + final XppDom newNode = new XppDom(encodeNode(name)); + final XppDom top = top(); + if (top != null) { + top().addChild(newNode); + } + return newNode; } - public void flush() { - // don't need to do anything + @Override + public void setValue(final String text) { + top().setValue(text); } - public void close() { - // don't need to do anything + @Override + public void addAttribute(final String key, final String value) { + top().setAttribute(encodeAttribute(key), value); } - public HierarchicalStreamWriter underlyingWriter() { - return this; + private XppDom top() { + return (XppDom)getCurrent(); } - } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDriver.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDriver.java (.../XppDriver.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppDriver.java (.../XppDriver.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,41 +1,59 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2014 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 08. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + import com.thoughtworks.xstream.io.HierarchicalStreamDriver; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.naming.NameCoder; -import java.io.*; -public class XppDriver implements HierarchicalStreamDriver { +/** + * A {@link HierarchicalStreamDriver} using the XmlPullParserFactory to locate an XML Pull Parser. + * + * @author Joe Walnes + * @author Jörg Schaible + */ +public class XppDriver extends AbstractXppDriver { - private static boolean xppLibraryPresent; + private static XmlPullParserFactory factory; - public HierarchicalStreamReader createReader(Reader xml) { - loadLibrary(); - return new XppReader(xml); + public XppDriver() { + super(new XmlFriendlyNameCoder()); } - public HierarchicalStreamReader createReader(InputStream in) { - return createReader(new InputStreamReader(in)); + /** + * @since 1.4 + */ + public XppDriver(final NameCoder nameCoder) { + super(nameCoder); } - private void loadLibrary() { - if (!xppLibraryPresent) { - try { - Class.forName("org.xmlpull.mxp1.MXParser"); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("XPP3 pull parser library not present. Specify another driver." + - " For example: new XStream(new DomDriver())"); - } - xppLibraryPresent = true; - } + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link XppDriver#XppDriver(NameCoder)} instead. + */ + @Deprecated + public XppDriver(final XmlFriendlyReplacer replacer) { + this((NameCoder)replacer); } - public HierarchicalStreamWriter createWriter(Writer out) { - return new PrettyPrintWriter(out); + @Override + protected synchronized XmlPullParser createParser() throws XmlPullParserException { + if (factory == null) { + factory = XmlPullParserFactory.newInstance(); + } + return factory.newPullParser(); } - - public HierarchicalStreamWriter createWriter(OutputStream out) { - return createWriter(new OutputStreamWriter(out)); - } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppReader.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppReader.java (.../XppReader.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/XppReader.java (.../XppReader.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,100 +1,182 @@ +/* + * Copyright (C) 2004, 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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 08. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.converters.ErrorWriter; -import com.thoughtworks.xstream.io.StreamException; -import org.xmlpull.mxp1.MXParser; +import java.io.IOException; +import java.io.Reader; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; +import com.thoughtworks.xstream.converters.ErrorWriter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.naming.NameCoder; + /** * XStream reader that pulls directly from the stream using the XmlPullParser API. - * + * * @author Joe Walnes + * @author Jörg Schaible */ public class XppReader extends AbstractPullReader { private final XmlPullParser parser; - private final BufferedReader reader; + private final Reader reader; - public XppReader(Reader reader) { + /** + * Construct an XppReader. + * + * @param reader the reader with the input data + * @param parser the XPP parser to use + * @since 1.4 + */ + public XppReader(final Reader reader, final XmlPullParser parser) { + this(reader, parser, new XmlFriendlyNameCoder()); + } + + /** + * Construct an XppReader. + * + * @param reader the reader with the input data + * @param parser the XPP parser to use + * @param nameCoder the coder for XML friendly tag and attribute names + * @since 1.4 + */ + public XppReader(final Reader reader, final XmlPullParser parser, final NameCoder nameCoder) { + super(nameCoder); + this.parser = parser; + this.reader = reader; try { + parser.setInput(this.reader); + } catch (final XmlPullParserException e) { + throw new StreamException(e); + } + moveDown(); + } + + /** + * @deprecated As of 1.4, use {@link #XppReader(Reader, XmlPullParser)} instead + */ + @Deprecated + public XppReader(final Reader reader) { + this(reader, new XmlFriendlyReplacer()); + } + + /** + * @since 1.2 + * @deprecated As of 1.4, use {@link #XppReader(Reader, XmlPullParser, NameCoder)} instead + */ + @Deprecated + public XppReader(final Reader reader, final XmlFriendlyReplacer replacer) { + super(replacer); + try { parser = createParser(); - this.reader = new BufferedReader(reader); + this.reader = reader; parser.setInput(this.reader); moveDown(); - } catch (XmlPullParserException e) { + } catch (final XmlPullParserException e) { throw new StreamException(e); } } /** * To use another implementation of org.xmlpull.v1.XmlPullParser, override this method. + * + * @deprecated As of 1.4, use {@link #XppReader(Reader, XmlPullParser)} instead */ + @Deprecated protected XmlPullParser createParser() { - return new MXParser(); + Exception exception = null; + try { + return (XmlPullParser)Class + .forName("org.xmlpull.mxp1.MXParser", true, XmlPullParser.class.getClassLoader()) + .newInstance(); + } catch (final InstantiationException e) { + exception = e; + } catch (final IllegalAccessException e) { + exception = e; + } catch (final ClassNotFoundException e) { + exception = e; + } + throw new StreamException("Cannot create Xpp3 parser instance.", exception); } + @Override protected int pullNextEvent() { try { - switch(parser.next()) { - case XmlPullParser.START_DOCUMENT: - case XmlPullParser.START_TAG: - return START_NODE; - case XmlPullParser.END_DOCUMENT: - case XmlPullParser.END_TAG: - return END_NODE; - case XmlPullParser.TEXT: - return TEXT; - case XmlPullParser.COMMENT: - return COMMENT; - default: - return OTHER; + switch (parser.next()) { + case XmlPullParser.START_DOCUMENT: + case XmlPullParser.START_TAG: + return START_NODE; + case XmlPullParser.END_DOCUMENT: + case XmlPullParser.END_TAG: + return END_NODE; + case XmlPullParser.TEXT: + return TEXT; + case XmlPullParser.COMMENT: + return COMMENT; + default: + return OTHER; } - } catch (XmlPullParserException e) { + } catch (final XmlPullParserException e) { throw new StreamException(e); - } catch (IOException e) { + } catch (final IOException e) { throw new StreamException(e); } } + @Override protected String pullElementName() { return parser.getName(); } + @Override protected String pullText() { return parser.getText(); } - public String getAttribute(String name) { - return parser.getAttributeValue(null, name); + @Override + public String getAttribute(final String name) { + return parser.getAttributeValue(null, encodeAttribute(name)); } - public String getAttribute(int index) { + @Override + public String getAttribute(final int index) { return parser.getAttributeValue(index); } + @Override public int getAttributeCount() { return parser.getAttributeCount(); } - public String getAttributeName(int index) { - return parser.getAttributeName(index); + @Override + public String getAttributeName(final int index) { + return decodeAttribute(parser.getAttributeName(index)); } - public void appendErrors(ErrorWriter errorWriter) { + @Override + public void appendErrors(final ErrorWriter errorWriter) { errorWriter.add("line number", String.valueOf(parser.getLineNumber())); } + @Override public void close() { try { reader.close(); - } catch (IOException e) { + } catch (final IOException e) { throw new StreamException(e); } } -} \ No newline at end of file +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3Dom.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3Dom.java (.../Xpp3Dom.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3Dom.java (.../Xpp3Dom.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,137 +1,32 @@ +/* + * Copyright (C) 2004 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml.xppdom; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +/** + * Simple Document Object Model for XmlPullParser implementations. + * + * @author Jason van Zyl + * @author Joe Walnes + * @author Jörg Schaible + * @deprecated As of 1.4, use {@link XppDom} instead + */ +@Deprecated +public class Xpp3Dom extends XppDom { -public class Xpp3Dom { - protected String name; - - protected String value; - - protected Map attributes; - - protected List childList; - - protected Map childMap; - - protected Xpp3Dom parent; - - public Xpp3Dom(String name) { - this.name = name; - childList = new ArrayList(); - childMap = new HashMap(); + /** + * @deprecated As of 1.4, use {@link XppDom} instead + */ + @Deprecated + public Xpp3Dom(final String name) { + super(name); } - - // ---------------------------------------------------------------------- - // Name handling - // ---------------------------------------------------------------------- - - public String getName() { - return name; - } - - // ---------------------------------------------------------------------- - // Value handling - // ---------------------------------------------------------------------- - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - // ---------------------------------------------------------------------- - // Attribute handling - // ---------------------------------------------------------------------- - - public String[] getAttributeNames() { - if ( null == attributes ) { - return new String[0]; - } - else { - return (String[]) attributes.keySet().toArray( new String[0] ); - } - } - - public String getAttribute(String name) { - return (null != attributes) ? (String) attributes.get(name) : null; - } - - public void setAttribute(String name, String value) { - if (null == attributes) { - attributes = new HashMap(); - } - - attributes.put(name, value); - } - - // ---------------------------------------------------------------------- - // Child handling - // ---------------------------------------------------------------------- - - public Xpp3Dom getChild(int i) { - return (Xpp3Dom) childList.get(i); - } - - public Xpp3Dom getChild(String name) { - return (Xpp3Dom) childMap.get(name); - } - - public void addChild(Xpp3Dom xpp3Dom) { - xpp3Dom.setParent(this); - childList.add(xpp3Dom); - childMap.put(xpp3Dom.getName(), xpp3Dom); - } - - public Xpp3Dom[] getChildren() { - if ( null == childList ) { - return new Xpp3Dom[0]; - } - else { - return (Xpp3Dom[]) childList.toArray( new Xpp3Dom[0] ); - } - } - - public Xpp3Dom[] getChildren( String name ) { - if ( null == childList ) { - return new Xpp3Dom[0]; - } - else { - ArrayList children = new ArrayList(); - int size = this.childList.size(); - - for ( int i = 0; i < size; i++ ) { - Xpp3Dom configuration = (Xpp3Dom) this.childList.get( i ); - if ( name.equals( configuration.getName() ) ) { - children.add( configuration ); - } - } - - return (Xpp3Dom[]) children.toArray( new Xpp3Dom[0] ); - } - } - - public int getChildCount() { - if (null == childList) { - return 0; - } - - return childList.size(); - } - - // ---------------------------------------------------------------------- - // Parent handling - // ---------------------------------------------------------------------- - - public Xpp3Dom getParent() { - return parent; - } - - public void setParent(Xpp3Dom parent) { - this.parent = parent; - } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3DomBuilder.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3DomBuilder.java (.../Xpp3DomBuilder.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/Xpp3DomBuilder.java (.../Xpp3DomBuilder.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,88 +1,41 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 07. March 2004 by Joe Walnes + */ package com.thoughtworks.xstream.io.xml.xppdom; +import java.io.Reader; + import org.xmlpull.mxp1.MXParser; import org.xmlpull.v1.XmlPullParser; -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; +/** + * @author Jason van Zyl + * @author Joe Walnes + * @author Jörg Schaible + * @deprecated As of 1.4, use {@link XppDom#build(XmlPullParser)} instead + */ +@Deprecated public class Xpp3DomBuilder { - public static Xpp3Dom build(Reader reader) - throws Exception { - List elements = new ArrayList(); - - List values = new ArrayList(); - - Xpp3Dom node = null; - - XmlPullParser parser = new MXParser(); - + /** + * @deprecated As of 1.4, use {@link XppDom#build(XmlPullParser)} instead + */ + @Deprecated + public static Xpp3Dom build(final Reader reader) throws Exception { + final XmlPullParser parser = new MXParser(); parser.setInput(reader); - - int eventType = parser.getEventType(); - - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG) { - String rawName = parser.getName(); - - Xpp3Dom child = new Xpp3Dom(rawName); - - int depth = elements.size(); - - if (depth > 0) { - Xpp3Dom parent = (Xpp3Dom) elements.get(depth - 1); - - parent.addChild(child); - } - - elements.add(child); - - values.add(new StringBuffer()); - - int attributesSize = parser.getAttributeCount(); - - for (int i = 0; i < attributesSize; i++) { - String name = parser.getAttributeName(i); - - String value = parser.getAttributeValue(i); - - child.setAttribute(name, value); - } - } else if (eventType == XmlPullParser.TEXT) { - int depth = values.size() - 1; - - StringBuffer valueBuffer = (StringBuffer) values.get(depth); - - valueBuffer.append(parser.getText()); - } else if (eventType == XmlPullParser.END_TAG) { - int depth = elements.size() - 1; - - Xpp3Dom finalNode = (Xpp3Dom) elements.remove(depth); - - String accumulatedValue = (values.remove(depth)).toString(); - - String finishedValue; - - if (0 == accumulatedValue.length()) { - finishedValue = null; - } else { - finishedValue = accumulatedValue; - } - - finalNode.setValue(finishedValue); - - if (0 == depth) { - node = finalNode; - } - } - - eventType = parser.next(); + try { + return (Xpp3Dom)XppDom.build(parser); + } finally { + reader.close(); } - - reader.close(); - - return node; } - -} \ No newline at end of file +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/XppDom.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/XppDom.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/XppDom.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2009, 2011, 2014 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 02. May 2009 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml.xppdom; + +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + + +/** + * Simple Document Object Model for XmlPullParser implementations. + * + * @author Jason van Zyl + * @author Joe Walnes + * @author Jörg Schaible + * @since 1.4 + */ +public class XppDom implements Serializable { + private static final long serialVersionUID = 1L; + + private final String name; + private String value; + private Map attributes; + private final List childList; + transient private Map childMap; + private XppDom parent; + + public XppDom(final String name) { + this.name = name; + childList = new ArrayList(); + childMap = new HashMap(); + } + + // ---------------------------------------------------------------------- + // Name handling + // ---------------------------------------------------------------------- + + public String getName() { + return name; + } + + // ---------------------------------------------------------------------- + // Value handling + // ---------------------------------------------------------------------- + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + + // ---------------------------------------------------------------------- + // Attribute handling + // ---------------------------------------------------------------------- + + public String[] getAttributeNames() { + if (null == attributes) { + return new String[0]; + } else { + return attributes.keySet().toArray(new String[0]); + } + } + + public String getAttribute(final String name) { + return null != attributes ? (String)attributes.get(name) : null; + } + + public void setAttribute(final String name, final String value) { + if (null == attributes) { + attributes = new HashMap(); + } + + attributes.put(name, value); + } + + // ---------------------------------------------------------------------- + // Child handling + // ---------------------------------------------------------------------- + + public XppDom getChild(final int i) { + return childList.get(i); + } + + public XppDom getChild(final String name) { + return childMap.get(name); + } + + public void addChild(final XppDom xpp3Dom) { + xpp3Dom.setParent(this); + childList.add(xpp3Dom); + childMap.put(xpp3Dom.getName(), xpp3Dom); + } + + public XppDom[] getChildren() { + if (null == childList) { + return new XppDom[0]; + } else { + return childList.toArray(new XppDom[0]); + } + } + + public XppDom[] getChildren(final String name) { + if (null == childList) { + return new XppDom[0]; + } else { + final ArrayList children = new ArrayList(); + final int size = childList.size(); + + for (int i = 0; i < size; i++) { + final XppDom configuration = childList.get(i); + if (name.equals(configuration.getName())) { + children.add(configuration); + } + } + + return children.toArray(new XppDom[0]); + } + } + + public int getChildCount() { + if (null == childList) { + return 0; + } + + return childList.size(); + } + + // ---------------------------------------------------------------------- + // Parent handling + // ---------------------------------------------------------------------- + + public XppDom getParent() { + return parent; + } + + public void setParent(final XppDom parent) { + this.parent = parent; + } + + // ---------------------------------------------------------------------- + // Serialization + // ---------------------------------------------------------------------- + + Object readResolve() { + childMap = new HashMap(); + for (final XppDom element : childList) { + childMap.put(element.getName(), element); + } + return this; + } + + // ---------------------------------------------------------------------- + // DOM builder + // ---------------------------------------------------------------------- + + /** + * Build an XPP DOM hierarchy. The {@link java.io.InputStream} or {@link java.io.Reader} used by the parser must + * have already been set. The method does not close it after reading the document's end. + * + * @param parser the XPP instance + * @throws XmlPullParserException if the parser turns into an invalid state or reads invalid XML + * @throws IOException if the data cannot be read + */ + public static XppDom build(final XmlPullParser parser) throws XmlPullParserException, IOException { + final List elements = new ArrayList(); + final List values = new ArrayList(); + XppDom node = null; + + int eventType = parser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + final String rawName = parser.getName(); + + // Use XppDom when deprecated Xpp3Dom is removed + final XppDom child = new Xpp3Dom(rawName); + + final int depth = elements.size(); + if (depth > 0) { + final XppDom parent = elements.get(depth - 1); + parent.addChild(child); + } + + elements.add(child); + values.add(new StringBuilder()); + + final int attributesSize = parser.getAttributeCount(); + for (int i = 0; i < attributesSize; i++) { + final String name = parser.getAttributeName(i); + final String value = parser.getAttributeValue(i); + child.setAttribute(name, value); + } + } else if (eventType == XmlPullParser.TEXT) { + final int depth = values.size() - 1; + final StringBuilder valueBuffer = values.get(depth); + valueBuffer.append(parser.getText()); + } else if (eventType == XmlPullParser.END_TAG) { + final int depth = elements.size() - 1; + final XppDom finalNode = elements.remove(depth); + final String accumulatedValue = values.remove(depth).toString(); + + String finishedValue; + if (0 == accumulatedValue.length()) { + finishedValue = null; + } else { + finishedValue = accumulatedValue; + } + + finalNode.setValue(finishedValue); + if (0 == depth) { + node = finalNode; + } + } + + eventType = parser.next(); + } + + return node; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/XppDomComparator.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/XppDomComparator.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/XppDomComparator.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2011, 2014 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 11. August 2011 by Joerg Schaible. + */ +package com.thoughtworks.xstream.io.xml.xppdom; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + + +/** + * Comparator for {@link XppDom}. Comparator can trace the XPath where the comparison failed. + * + * @author Jörg Schaible + * @since 1.4.1 + */ +public class XppDomComparator implements Comparator { + private final ThreadLocal xpath; + + /** + * Creates a new Xpp3DomComparator object. + * + * @since 1.4.1 + */ + public XppDomComparator() { + this(null); + } + + /** + * Creates a new Xpp3DomComparator object with XPath identification. + * + * @param xpath the reference for the XPath + * @since 1.4.1 + */ + public XppDomComparator(final ThreadLocal xpath) { + this.xpath = xpath; + } + + @Override + public int compare(final XppDom dom1, final XppDom dom2) { + + final StringBuilder xpath = new StringBuilder("/"); + final int s = compareInternal(dom1, dom2, xpath, -1); + if (this.xpath != null) { + if (s != 0) { + this.xpath.set(xpath.toString()); + } else { + this.xpath.set(null); + } + } + + return s; + } + + private int compareInternal(final XppDom dom1, final XppDom dom2, final StringBuilder xpath, final int count) { + final int pathlen = xpath.length(); + final String name = dom1.getName(); + int s = name.compareTo(dom2.getName()); + xpath.append(name); + if (count >= 0) { + xpath.append('[').append(count).append(']'); + } + + if (s != 0) { + xpath.append('?'); + + return s; + } + + final String[] attributes = dom1.getAttributeNames(); + final String[] attributes2 = dom2.getAttributeNames(); + final int len = attributes.length; + s = attributes2.length - len; + if (s != 0) { + xpath.append("::count(@*)"); + + return s < 0 ? 1 : -1; + } + + Arrays.sort(attributes); + Arrays.sort(attributes2); + for (int i = 0; i < len; ++i) { + final String attribute = attributes[i]; + s = attribute.compareTo(attributes2[i]); + if (s != 0) { + xpath.append("[@").append(attribute).append("?]"); + + return s; + } + + s = dom1.getAttribute(attribute).compareTo(dom2.getAttribute(attribute)); + if (s != 0) { + xpath.append("[@").append(attribute).append(']'); + + return s; + } + } + + final int children = dom1.getChildCount(); + s = dom2.getChildCount() - children; + if (s != 0) { + xpath.append("::count(*)"); + + return s < 0 ? 1 : -1; + } + + if (children > 0) { + if (dom1.getValue() != null || dom2.getValue() != null) { + throw new IllegalArgumentException("XppDom cannot handle mixed mode at " + xpath + "::text()"); + } + + xpath.append('/'); + + final Map names = new HashMap(); + for (int i = 0; i < children; ++i) { + final XppDom child1 = dom1.getChild(i); + final XppDom child2 = dom2.getChild(i); + final String child = child1.getName(); + if (!names.containsKey(child)) { + names.put(child, new int[1]); + } + + s = compareInternal(child1, child2, xpath, names.get(child)[0]++); + if (s != 0) { + return s; + } + } + } else { + final String value2 = dom2.getValue(); + final String value1 = dom1.getValue(); + if (value1 == null) { + s = value2 == null ? 0 : -1; + } else { + s = value2 == null ? 1 : value1.compareTo(value2); + } + + if (s != 0) { + xpath.append("::text()"); + + return s; + } + } + + xpath.setLength(pathlen); + + return s; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/XppFactory.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/XppFactory.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/io/xml/xppdom/XppFactory.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 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 11. August 2011 by Joerg Schaible, code from XppDom. + */ +package com.thoughtworks.xstream.io.xml.xppdom; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + +/** + * XmlPullParser utility methods. + * + * @author Jörg Schaible + * @since 1.4.1 + */ +public class XppFactory { + + /** + * Create a new XmlPullParser using the XPP factory. + * + * @return a new parser instance + * @throws XmlPullParserException if the factory fails + * @since 1.4.1 + */ + public static XmlPullParser createDefaultParser() throws XmlPullParserException { + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + return factory.newPullParser(); + } + + /** + * Build an XPP DOM hierarchy from a String. + * + * @param xml the XML data + * @throws XmlPullParserException if the default parser cannot be created or fails with invalid XML + * @throws IOException if the data cannot be read + * @see XppDom#build(XmlPullParser) + * @since 1.4.1 + */ + public static XppDom buildDom(String xml) throws XmlPullParserException, IOException { + return buildDom(new StringReader(xml)); + } + + /** + * Build an XPP DOM hierarchy from a Reader. + * + * @param r the reader + * @throws XmlPullParserException if the default parser cannot be created or fails with invalid XML + * @throws IOException if the data cannot be read + * @see XppDom#build(XmlPullParser) + * @since 1.4.1 + */ + public static XppDom buildDom(Reader r) throws XmlPullParserException, IOException { + XmlPullParser parser = createDefaultParser(); + parser.setInput(r); + return XppDom.build(parser); + } + + /** + * Build an XPP DOM hierarchy from an InputStream. + * + * @param in the input stream + * @param encoding the encoding of the input stream + * @throws XmlPullParserException if the default parser cannot be created or fails with invalid XML + * @throws IOException if the data cannot be read + * @see XppDom#build(XmlPullParser) + * @since 1.4.1 + */ + public static XppDom buildDom(InputStream in, String encoding) throws XmlPullParserException, IOException { + XmlPullParser parser = createDefaultParser(); + parser.setInput(in, encoding); + return XppDom.build(parser); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AbstractAttributeAliasingMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AbstractAttributeAliasingMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AbstractAttributeAliasingMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008, 2014 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 09. October 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.mapper; + +import java.util.HashMap; +import java.util.Map; + + +/** + * Abstract base class for AttributeAliassingMapper and its system version. + * + * @author Jörg Schaible + * @since 1.3.1 + */ +public abstract class AbstractAttributeAliasingMapper extends MapperWrapper { + + protected final Map aliasToName = new HashMap(); + protected transient Map nameToAlias = new HashMap(); + + public AbstractAttributeAliasingMapper(final Mapper wrapped) { + super(wrapped); + } + + public void addAliasFor(final String attributeName, final String alias) { + aliasToName.put(alias, attributeName); + nameToAlias.put(attributeName, alias); + } + + private Object readResolve() { + nameToAlias = new HashMap(); + for (final Map.Entry entry : aliasToName.entrySet()) { + nameToAlias.put(entry.getValue(), entry.getKey()); + } + return this; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AbstractXmlFriendlyMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AbstractXmlFriendlyMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AbstractXmlFriendlyMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2011, 2014 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 03. May 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.mapper; + +/** + * Mapper that ensures that all names in the serialization stream are XML friendly. The replacement chars and strings + * are: + *
      + *
    • $ (dollar) chars appearing in class names are replaced with _ (underscore) chars.
      + *
    • + *
    • $ (dollar) chars appearing in field names are replaced with _DOLLAR_ string.
      + *
    • + *
    • _ (underscore) chars appearing in field names are replaced with __ (double underscore) string.
      + *
    • + *
    • default as the prefix for class names with no package.
    • + *
    + * Note, this class is no longer in regular use for current XStream versions. It exists to provide backward + * compatibility to existing XML data written with older XStream versions. + * + * @author Joe Walnes + * @author Mauro Talevi + * @deprecated As of 1.4 use {@link com.thoughtworks.xstream.io.xml.XmlFriendlyReader} + */ +@Deprecated +public class AbstractXmlFriendlyMapper extends MapperWrapper { + + private final char dollarReplacementInClass = '-'; + private final String dollarReplacementInField = "_DOLLAR_"; + private final String underscoreReplacementInField = "__"; + private final String noPackagePrefix = "default"; + + protected AbstractXmlFriendlyMapper(final Mapper wrapped) { + super(wrapped); + } + + protected String escapeClassName(String className) { + // the $ used in inner class names is illegal as an xml element getNodeName + className = className.replace('$', dollarReplacementInClass); + + // special case for classes named $Blah with no package; <-Blah> is illegal XML + if (className.charAt(0) == dollarReplacementInClass) { + className = noPackagePrefix + className; + } + + return className; + } + + protected String unescapeClassName(String className) { + // special case for classes named $Blah with no package; <-Blah> is illegal XML + if (className.startsWith(noPackagePrefix + dollarReplacementInClass)) { + className = className.substring(noPackagePrefix.length()); + } + + // the $ used in inner class names is illegal as an xml element getNodeName + className = className.replace(dollarReplacementInClass, '$'); + + return className; + } + + protected String escapeFieldName(final String fieldName) { + final StringBuilder result = new StringBuilder(); + final int length = fieldName.length(); + for (int i = 0; i < length; i++) { + final char c = fieldName.charAt(i); + if (c == '$') { + result.append(dollarReplacementInField); + } else if (c == '_') { + result.append(underscoreReplacementInField); + } else { + result.append(c); + } + } + return result.toString(); + } + + protected String unescapeFieldName(final String xmlName) { + final StringBuilder result = new StringBuilder(); + final int length = xmlName.length(); + for (int i = 0; i < length; i++) { + final char c = xmlName.charAt(i); + if (stringFoundAt(xmlName, i, underscoreReplacementInField)) { + i += underscoreReplacementInField.length() - 1; + result.append('_'); + } else if (stringFoundAt(xmlName, i, dollarReplacementInField)) { + i += dollarReplacementInField.length() - 1; + result.append('$'); + } else { + result.append(c); + } + } + return result.toString(); + } + + private boolean stringFoundAt(final String name, final int i, final String replacement) { + if (name.length() >= i + replacement.length() + && name.substring(i, i + replacement.length()).equals(replacement)) { + return true; + } + return false; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AnnotationConfiguration.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AnnotationConfiguration.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AnnotationConfiguration.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2007, 2008, 2013, 2014 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 07. November 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.mapper; + +/** + * A helper interface for the configuration part of the AnnotationMapper. + * + * @author Jörg Schaible + * @since 1.3 + * @deprecated As of 1.4.5, minimal JDK version will be 1.6 for next major release and AnnotationMapper can be used + * directly + */ +@Deprecated +public interface AnnotationConfiguration { + + void autodetectAnnotations(boolean mode); + + void processAnnotations(Class... types); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AnnotationMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AnnotationMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AnnotationMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2011, 2012, 2013, 2014 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 07. November 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.mapper; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.thoughtworks.xstream.InitializationException; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAliasType; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.annotations.XStreamConverters; +import com.thoughtworks.xstream.annotations.XStreamImplicit; +import com.thoughtworks.xstream.annotations.XStreamInclude; +import com.thoughtworks.xstream.annotations.XStreamOmitField; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.ConverterMatcher; +import com.thoughtworks.xstream.converters.ConverterRegistry; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.converters.SingleValueConverterWrapper; +import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; +import com.thoughtworks.xstream.core.ClassLoaderReference; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.core.util.DependencyInjectionFactory; +import com.thoughtworks.xstream.core.util.TypedNull; + + +/** + * A mapper that uses annotations to prepare the remaining mappers in the chain. + * + * @author Jörg Schaible + * @since 1.3 + */ +public class AnnotationMapper extends MapperWrapper implements AnnotationConfiguration { + + private boolean locked; + private transient Object[] arguments; + private final ConverterRegistry converterRegistry; + private transient ClassAliasingMapper classAliasingMapper; + private transient DefaultImplementationsMapper defaultImplementationsMapper; + private transient ImplicitCollectionMapper implicitCollectionMapper; + private transient FieldAliasingMapper fieldAliasingMapper; + private transient AttributeMapper attributeMapper; + private transient LocalConversionMapper localConversionMapper; + private final Map, Map, Converter>> converterCache = new HashMap, Map, Converter>>(); + private final Set> annotatedTypes = Collections.synchronizedSet(new HashSet>()); + + /** + * Construct an AnnotationMapper. + * + * @param wrapped the next {@link Mapper} in the chain + * @since 1.4.5 + */ + public AnnotationMapper( + final Mapper wrapped, final ConverterRegistry converterRegistry, final ConverterLookup converterLookup, + final ClassLoaderReference classLoaderReference, final ReflectionProvider reflectionProvider) { + super(wrapped); + this.converterRegistry = converterRegistry; + annotatedTypes.add(Object.class); + setupMappers(); + locked = true; + + final ClassLoader classLoader = classLoaderReference.getReference(); + arguments = new Object[]{ + this, classLoaderReference, reflectionProvider, converterLookup, new JVM(), + classLoader != null ? classLoader : new TypedNull(ClassLoader.class)}; + } + + /** + * Construct an AnnotationMapper. + * + * @param wrapped the next {@link Mapper} in the chain + * @since 1.3 + * @deprecated As of 1.4.5 use + * {@link #AnnotationMapper(Mapper, ConverterRegistry, ConverterLookup, ClassLoaderReference, ReflectionProvider)} + */ + @Deprecated + public AnnotationMapper( + final Mapper wrapped, final ConverterRegistry converterRegistry, final ConverterLookup converterLookup, + final ClassLoader classLoader, final ReflectionProvider reflectionProvider, final JVM jvm) { + this(wrapped, converterRegistry, converterLookup, new ClassLoaderReference(classLoader), reflectionProvider); + } + + @Override + public String realMember(final Class type, final String serialized) { + if (!locked) { + processAnnotation(type); + } + return super.realMember(type, serialized); + } + + @Override + public String serializedClass(final Class type) { + if (!locked) { + processAnnotation(type); + } + return super.serializedClass(type); + } + + @Override + public Class defaultImplementationOf(final Class type) { + if (!locked) { + processAnnotation(type); + } + final Class defaultImplementation = super.defaultImplementationOf(type); + if (!locked) { + processAnnotation(defaultImplementation); + } + return defaultImplementation; + } + + @Override + public Converter getLocalConverter(final Class definedIn, final String fieldName) { + if (!locked) { + processAnnotation(definedIn); + } + return super.getLocalConverter(definedIn, fieldName); + } + + @Override + public void autodetectAnnotations(final boolean mode) { + locked = !mode; + } + + @Override + public void processAnnotations(final Class... initialTypes) { + if (initialTypes == null || initialTypes.length == 0) { + return; + } + locked = true; + + final Set> types = new UnprocessedTypesSet(); + for (final Class initialType : initialTypes) { + types.add(initialType); + } + processTypes(types); + } + + private void processAnnotation(final Class initialType) { + if (initialType == null) { + return; + } + + final Set> types = new UnprocessedTypesSet(); + types.add(initialType); + processTypes(types); + } + + private void processTypes(final Set> types) { + while (!types.isEmpty()) { + final Iterator> iter = types.iterator(); + final Class type = iter.next(); + iter.remove(); + + synchronized (type) { + if (annotatedTypes.contains(type)) { + continue; + } + try { + if (type.isPrimitive()) { + continue; + } + + addParametrizedTypes(type, types); + + processConverterAnnotations(type); + processAliasAnnotation(type, types); + processAliasTypeAnnotation(type); + + if (type.isInterface()) { + continue; + } + + final Field[] fields = type.getDeclaredFields(); + for (final Field field : fields) { + if (field.isEnumConstant() + || (field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) > 0) { + continue; + } + + addParametrizedTypes(field.getGenericType(), types); + + if (field.isSynthetic()) { + continue; + } + + processFieldAliasAnnotation(field); + processAsAttributeAnnotation(field); + processImplicitAnnotation(field); + processOmitFieldAnnotation(field); + processLocalConverterAnnotation(field); + } + } finally { + annotatedTypes.add(type); + } + } + } + } + + private void addParametrizedTypes(Type type, final Set> types) { + final Set processedTypes = new HashSet(); + final Set localTypes = new LinkedHashSet() { + + @Override + public boolean add(final Type o) { + if (o instanceof Class) { + return types.add((Class)o); + } + return o == null || processedTypes.contains(o) ? false : super.add(o); + } + + }; + while (type != null) { + processedTypes.add(type); + if (type instanceof Class) { + final Class clazz = (Class)type; + types.add(clazz); + if (!clazz.isPrimitive()) { + final TypeVariable[] typeParameters = clazz.getTypeParameters(); + for (final TypeVariable typeVariable : typeParameters) { + localTypes.add(typeVariable); + } + localTypes.add(clazz.getGenericSuperclass()); + for (final Type iface : clazz.getGenericInterfaces()) { + localTypes.add(iface); + } + } + } else if (type instanceof TypeVariable) { + final TypeVariable typeVariable = (TypeVariable)type; + final Type[] bounds = typeVariable.getBounds(); + for (final Type bound : bounds) { + localTypes.add(bound); + } + } else if (type instanceof ParameterizedType) { + final ParameterizedType parametrizedType = (ParameterizedType)type; + localTypes.add(parametrizedType.getRawType()); + final Type[] actualArguments = parametrizedType.getActualTypeArguments(); + for (final Type actualArgument : actualArguments) { + localTypes.add(actualArgument); + } + } else if (type instanceof GenericArrayType) { + final GenericArrayType arrayType = (GenericArrayType)type; + localTypes.add(arrayType.getGenericComponentType()); + } + + if (!localTypes.isEmpty()) { + final Iterator iter = localTypes.iterator(); + type = iter.next(); + iter.remove(); + } else { + type = null; + } + } + } + + private void processConverterAnnotations(final Class type) { + if (converterRegistry != null) { + final XStreamConverters convertersAnnotation = type.getAnnotation(XStreamConverters.class); + final XStreamConverter converterAnnotation = type.getAnnotation(XStreamConverter.class); + final List annotations = convertersAnnotation != null ? new ArrayList( + Arrays.asList(convertersAnnotation.value())) : new ArrayList(); + if (converterAnnotation != null) { + annotations.add(converterAnnotation); + } + for (final XStreamConverter annotation : annotations) { + final Converter converter = cacheConverter(annotation, converterAnnotation != null ? type : null); + if (converter != null) { + if (converterAnnotation != null || converter.canConvert(type)) { + converterRegistry.registerConverter(converter, annotation.priority()); + } else { + throw new InitializationException("Converter " + + annotation.value().getName() + + " cannot handle annotated class " + + type.getName()); + } + } + } + } + } + + private void processAliasAnnotation(final Class type, final Set> types) { + final XStreamAlias aliasAnnotation = type.getAnnotation(XStreamAlias.class); + if (aliasAnnotation != null) { + if (classAliasingMapper == null) { + throw new InitializationException("No " + ClassAliasingMapper.class.getName() + " available"); + } + classAliasingMapper.addClassAlias(aliasAnnotation.value(), type); + if (aliasAnnotation.impl() != Void.class) { + // Alias for Interface/Class with an impl + defaultImplementationsMapper.addDefaultImplementation(aliasAnnotation.impl(), type); + if (type.isInterface()) { + types.add(aliasAnnotation.impl()); // alias Interface's impl + } + } + } + } + + private void processAliasTypeAnnotation(final Class type) { + final XStreamAliasType aliasAnnotation = type.getAnnotation(XStreamAliasType.class); + if (aliasAnnotation != null) { + if (classAliasingMapper == null) { + throw new InitializationException("No " + ClassAliasingMapper.class.getName() + " available"); + } + classAliasingMapper.addTypeAlias(aliasAnnotation.value(), type); + } + } + + private void processFieldAliasAnnotation(final Field field) { + final XStreamAlias aliasAnnotation = field.getAnnotation(XStreamAlias.class); + if (aliasAnnotation != null) { + if (fieldAliasingMapper == null) { + throw new InitializationException("No " + FieldAliasingMapper.class.getName() + " available"); + } + fieldAliasingMapper.addFieldAlias(aliasAnnotation.value(), field.getDeclaringClass(), field.getName()); + } + } + + private void processAsAttributeAnnotation(final Field field) { + final XStreamAsAttribute asAttributeAnnotation = field.getAnnotation(XStreamAsAttribute.class); + if (asAttributeAnnotation != null) { + if (attributeMapper == null) { + throw new InitializationException("No " + AttributeMapper.class.getName() + " available"); + } + attributeMapper.addAttributeFor(field); + } + } + + private void processImplicitAnnotation(final Field field) { + final XStreamImplicit implicitAnnotation = field.getAnnotation(XStreamImplicit.class); + if (implicitAnnotation != null) { + if (implicitCollectionMapper == null) { + throw new InitializationException("No " + ImplicitCollectionMapper.class.getName() + " available"); + } + final String fieldName = field.getName(); + final String itemFieldName = implicitAnnotation.itemFieldName(); + final String keyFieldName = implicitAnnotation.keyFieldName(); + final boolean isMap = Map.class.isAssignableFrom(field.getType()); + Class itemType = null; + if (!field.getType().isArray()) { + final Type genericType = field.getGenericType(); + if (genericType instanceof ParameterizedType) { + final Type[] actualTypeArguments = ((ParameterizedType)genericType).getActualTypeArguments(); + final Type typeArgument = actualTypeArguments[isMap ? 1 : 0]; + itemType = getClass(typeArgument); + } + } + if (isMap) { + implicitCollectionMapper.add(field.getDeclaringClass(), fieldName, itemFieldName != null + && !"".equals(itemFieldName) ? itemFieldName : null, itemType, keyFieldName != null + && !"".equals(keyFieldName) ? keyFieldName : null); + } else { + if (itemFieldName != null && !"".equals(itemFieldName)) { + implicitCollectionMapper.add(field.getDeclaringClass(), fieldName, itemFieldName, itemType); + } else { + implicitCollectionMapper.add(field.getDeclaringClass(), fieldName, itemType); + } + } + } + } + + private void processOmitFieldAnnotation(final Field field) { + final XStreamOmitField omitFieldAnnotation = field.getAnnotation(XStreamOmitField.class); + if (omitFieldAnnotation != null) { + if (fieldAliasingMapper == null) { + throw new InitializationException("No " + FieldAliasingMapper.class.getName() + " available"); + } + fieldAliasingMapper.omitField(field.getDeclaringClass(), field.getName()); + } + } + + private void processLocalConverterAnnotation(final Field field) { + final XStreamConverter annotation = field.getAnnotation(XStreamConverter.class); + if (annotation != null) { + final Converter converter = cacheConverter(annotation, field.getType()); + if (converter != null) { + if (localConversionMapper == null) { + throw new InitializationException("No " + LocalConversionMapper.class.getName() + " available"); + } + localConversionMapper.registerLocalConverter(field.getDeclaringClass(), field.getName(), converter); + } + } + } + + private Converter cacheConverter(final XStreamConverter annotation, final Class targetType) { + Converter result = null; + final Object[] args; + final List parameter = new ArrayList(); + if (targetType != null && annotation.useImplicitType()) { + parameter.add(targetType); + } + final List arrays = new ArrayList(); + arrays.add(annotation.booleans()); + arrays.add(annotation.bytes()); + arrays.add(annotation.chars()); + arrays.add(annotation.doubles()); + arrays.add(annotation.floats()); + arrays.add(annotation.ints()); + arrays.add(annotation.longs()); + arrays.add(annotation.shorts()); + arrays.add(annotation.strings()); + arrays.add(annotation.types()); + for (final Object array : arrays) { + if (array != null) { + final int length = Array.getLength(array); + for (int i = 0; i < length; i++) { + final Object object = Array.get(array, i); + if (!parameter.contains(object)) { + parameter.add(object); + } + } + } + } + final Class converterType = annotation.value(); + Map, Converter> converterMapping = converterCache.get(converterType); + if (converterMapping != null) { + result = converterMapping.get(parameter); + } + if (result == null) { + final int size = parameter.size(); + if (size > 0) { + args = new Object[arguments.length + size]; + System.arraycopy(arguments, 0, args, size, arguments.length); + System.arraycopy(parameter.toArray(new Object[size]), 0, args, 0, size); + } else { + args = arguments; + } + + final Converter converter; + try { + if (SingleValueConverter.class.isAssignableFrom(converterType) + && !Converter.class.isAssignableFrom(converterType)) { + final SingleValueConverter svc = (SingleValueConverter)DependencyInjectionFactory.newInstance( + converterType, args); + converter = new SingleValueConverterWrapper(svc); + } else { + converter = (Converter)DependencyInjectionFactory.newInstance(converterType, args); + } + } catch (final Exception e) { + throw new InitializationException("Cannot instantiate converter " + + converterType.getName() + + (targetType != null ? " for type " + targetType.getName() : ""), e); + } + if (converterMapping == null) { + converterMapping = new HashMap, Converter>(); + converterCache.put(converterType, converterMapping); + } + converterMapping.put(parameter, converter); + result = converter; + } + return result; + } + + private Class getClass(final Type typeArgument) { + Class type = null; + if (typeArgument instanceof ParameterizedType) { + type = (Class)((ParameterizedType)typeArgument).getRawType(); + } else if (typeArgument instanceof Class) { + type = (Class)typeArgument; + } + return type; + } + + private void setupMappers() { + classAliasingMapper = lookupMapperOfType(ClassAliasingMapper.class); + defaultImplementationsMapper = lookupMapperOfType(DefaultImplementationsMapper.class); + implicitCollectionMapper = lookupMapperOfType(ImplicitCollectionMapper.class); + fieldAliasingMapper = lookupMapperOfType(FieldAliasingMapper.class); + attributeMapper = lookupMapperOfType(AttributeMapper.class); + localConversionMapper = lookupMapperOfType(LocalConversionMapper.class); + } + + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + final int max = arguments.length - 2; + out.writeInt(max); + for (int i = 0; i < max; i++) { + out.writeObject(arguments[i]); + } + } + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setupMappers(); + final int max = in.readInt(); + arguments = new Object[max + 2]; + for (int i = 0; i < max; i++) { + arguments[i] = in.readObject(); + if (arguments[i] instanceof ClassLoaderReference) { + arguments[max + 1] = ((ClassLoaderReference)arguments[i]).getReference(); + } + } + arguments[max] = new JVM(); + } + + private final class UnprocessedTypesSet extends LinkedHashSet> { + @Override + public boolean add(Class type) { + if (type == null) { + return false; + } + while (type.isArray()) { + type = type.getComponentType(); + } + final String name = type.getName(); + if (name.startsWith("java.") || name.startsWith("javax.")) { + return false; + } + final boolean ret = annotatedTypes.contains(type) ? false : super.add(type); + if (ret) { + final XStreamInclude inc = type.getAnnotation(XStreamInclude.class); + if (inc != null) { + final Class[] incTypes = inc.value(); + if (incTypes != null) { + for (final Class incType : incTypes) { + add(incType); + } + } + } + } + return ret; + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ArrayMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ArrayMapper.java (.../ArrayMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ArrayMapper.java (.../ArrayMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,43 +1,49 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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 22. January 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; -import com.thoughtworks.xstream.alias.CannotResolveClassException; +import com.thoughtworks.xstream.core.util.Primitives; -import java.util.Arrays; -import java.util.Collection; /** - * Mapper that detects arrays and changes the name so it can identified as an array - * (for example Foo[] gets serialized as foo-array). Supports multi-dimensional arrays. - * - * @author Joe Walnes + * Mapper that detects arrays and changes the name so it can identified as an array (for example Foo[] gets serialized + * as foo-array). Supports multi-dimensional arrays. + * + * @author Joe Walnes */ public class ArrayMapper extends MapperWrapper { - private final static Collection BOXED_TYPES = Arrays.asList( - new Class[] { - Boolean.class, - Byte.class, - Character.class, - Short.class, - Integer.class, - Long.class, - Float.class, - Double.class - }); - - public ArrayMapper(ClassMapper wrapped) { + public ArrayMapper(final Mapper wrapped) { super(wrapped); } - public String serializedClass(Class type) { - StringBuffer arraySuffix = new StringBuffer(); + @Override + public String serializedClass(Class type) { + final StringBuilder arraySuffix = new StringBuilder(); + String name = null; while (type.isArray()) { - type = type.getComponentType(); - arraySuffix.append("-array"); + name = super.serializedClass(type); + if (type.getName().equals(name)) { + type = type.getComponentType(); + arraySuffix.append("-array"); + name = null; + } else { + break; + } } - String name = boxedTypeName(type); if (name == null) { + name = boxedTypeName(type); + } + if (name == null) { name = super.serializedClass(type); } if (arraySuffix.length() > 0) { @@ -47,72 +53,46 @@ } } - public Class realClass(String elementName) { + @Override + public Class realClass(String elementName) { int dimensions = 0; // strip off "-array" suffix while (elementName.endsWith("-array")) { elementName = elementName.substring(0, elementName.length() - 6); // cut off -array - dimensions++; + ++dimensions; } if (dimensions > 0) { - Class componentType = primitiveClassNamed(elementName); + Class componentType = Primitives.primitiveType(elementName); if (componentType == null) { componentType = super.realClass(elementName); } - try { - return arrayType(dimensions, componentType); - } catch (ClassNotFoundException e) { - throw new CannotResolveClassException(elementName + " : " + e.getMessage()); + while (componentType.isArray()) { + componentType = componentType.getComponentType(); + ++dimensions; } + return super.realClass(arrayType(dimensions, componentType)); } else { return super.realClass(elementName); } } - private Class arrayType(int dimensions, Class componentType) throws ClassNotFoundException { - StringBuffer className = new StringBuffer(); + private String arrayType(final int dimensions, final Class componentType) { + final StringBuilder className = new StringBuilder(); for (int i = 0; i < dimensions; i++) { className.append('['); } if (componentType.isPrimitive()) { - className.append(charThatJavaUsesToRepresentPrimitiveArrayType(componentType)); - return Class.forName(className.toString()); + className.append(Primitives.representingChar(componentType)); + return className.toString(); } else { className.append('L').append(componentType.getName()).append(';'); - return Class.forName(className.toString(), false, componentType.getClassLoader()); + return className.toString(); } } - private Class primitiveClassNamed(String name) { - return - name.equals("void") ? Void.TYPE : - name.equals("boolean") ? Boolean.TYPE : - name.equals("byte") ? Byte.TYPE : - name.equals("char") ? Character.TYPE : - name.equals("short") ? Short.TYPE : - name.equals("int") ? Integer.TYPE : - name.equals("long") ? Long.TYPE : - name.equals("float") ? Float.TYPE : - name.equals("double") ? Double.TYPE : - null; + private String boxedTypeName(final Class type) { + return Primitives.isBoxed(type) ? type.getName() : null; } - - private char charThatJavaUsesToRepresentPrimitiveArrayType(Class primvCls) { - return - (primvCls == boolean.class) ? 'Z' : - (primvCls == byte.class) ? 'B' : - (primvCls == char.class) ? 'C' : - (primvCls == short.class) ? 'S' : - (primvCls == int.class) ? 'I' : - (primvCls == long.class) ? 'J' : - (primvCls == float.class) ? 'F' : - (primvCls == double.class) ? 'D' : - 0; - } - - private String boxedTypeName(Class type) { - return BOXED_TYPES.contains(type) ? type.getName() : null; - } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AttributeAliasingMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AttributeAliasingMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AttributeAliasingMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2014 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 27. March 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.mapper; + +/** + * Mapper that allows aliasing of attribute names. + * + * @author Jörg Schaible + * @author Guilherme Silveira + * @since 1.2 + */ +public class AttributeAliasingMapper extends AbstractAttributeAliasingMapper { + + public AttributeAliasingMapper(final Mapper wrapped) { + super(wrapped); + } + + @Override + public String aliasForAttribute(final String attribute) { + final String alias = nameToAlias.get(attribute); + return alias == null ? super.aliasForAttribute(attribute) : alias; + } + + @Override + public String attributeForAlias(final String alias) { + final String name = aliasToName.get(alias); + return name == null ? super.attributeForAlias(alias) : name; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AttributeMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AttributeMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/AttributeMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013, 2014 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 20. February 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.mapper; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; + + +/** + * Mapper that allows the usage of attributes for fields and corresponding types or specified arbitrary types. It is + * responsible for the lookup of the {@link SingleValueConverter} for item types and attribute names. + * + * @author Paul Hammant + * @author Ian Cartwright + * @author Jörg Schaible + * @author Mauro Talevi + * @author Guilherme Silveira + * @since 1.2 + */ +public class AttributeMapper extends MapperWrapper { + + private final Map> fieldNameToTypeMap = new HashMap>(); + private final Set> typeSet = new HashSet>(); + private final ConverterLookup converterLookup; + private final ReflectionProvider reflectionProvider; + private final Set fieldToUseAsAttribute = new HashSet(); + + public AttributeMapper( + final Mapper wrapped, final ConverterLookup converterLookup, final ReflectionProvider refProvider) { + super(wrapped); + this.converterLookup = converterLookup; + reflectionProvider = refProvider; + } + + public void addAttributeFor(final String fieldName, final Class type) { + fieldNameToTypeMap.put(fieldName, type); + } + + public void addAttributeFor(final Class type) { + typeSet.add(type); + } + + private SingleValueConverter getLocalConverterFromItemType(final Class type) { + final Converter converter = converterLookup.lookupConverterForType(type); + if (converter != null && converter instanceof SingleValueConverter) { + return (SingleValueConverter)converter; + } else { + return null; + } + } + + @Override + public SingleValueConverter getConverterFromItemType(final String fieldName, final Class type, + final Class definedIn) { + if (shouldLookForSingleValueConverter(fieldName, type, definedIn)) { + final SingleValueConverter converter = getLocalConverterFromItemType(type); + if (converter != null) { + return converter; + } + } + return super.getConverterFromItemType(fieldName, type, definedIn); + } + + public boolean shouldLookForSingleValueConverter(final String fieldName, final Class type, + final Class definedIn) { + if (typeSet.contains(type)) { + return true; + } else if (fieldNameToTypeMap.get(fieldName) == type) { + return true; + } else if (fieldName != null && definedIn != null) { + final Field field = reflectionProvider.getField(definedIn, fieldName); + return fieldToUseAsAttribute.contains(field); + } + return false; + } + + /** + * @deprecated As of 1.3.1, use {@link #getConverterFromAttribute(Class, String, Class)} + */ + @Deprecated + @Override + public SingleValueConverter getConverterFromAttribute(final Class definedIn, final String attribute) { + final Field field = reflectionProvider.getField(definedIn, attribute); + return getConverterFromAttribute(definedIn, attribute, field.getType()); + } + + @Override + public SingleValueConverter getConverterFromAttribute(final Class definedIn, final String attribute, + final Class type) { + if (shouldLookForSingleValueConverter(attribute, type, definedIn)) { + final SingleValueConverter converter = getLocalConverterFromItemType(type); + if (converter != null) { + return converter; + } + } + return super.getConverterFromAttribute(definedIn, attribute, type); + } + + /** + * Tells this mapper to use an attribute for this field. + * + * @param field the field itself + * @since 1.2.2 + */ + public void addAttributeFor(final Field field) { + fieldToUseAsAttribute.add(field); + } + + /** + * Tells this mapper to use an attribute for this field. + * + * @param definedIn the declaring class of the field + * @param fieldName the name of the field + * @throws IllegalArgumentException if the field does not exist + * @since 1.3 + */ + public void addAttributeFor(final Class definedIn, final String fieldName) { + fieldToUseAsAttribute.add(reflectionProvider.getField(definedIn, fieldName)); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CGLIBMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CGLIBMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CGLIBMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2014 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 08. April 2006 by Joerg Schaible + */ +package com.thoughtworks.xstream.mapper; + +import net.sf.cglib.proxy.Enhancer; + + +/** + * Mapper that detects proxies generated by the CGLIB enhancer. The implementation modifies the name, so that it can + * identify these types. Note, that this mapper relies on the CGLIB converters: + *
      + *
    • CGLIBEnhancedConverter
    • + *
    + * + * @author Jörg Schaible + * @since 1.2 + */ +public class CGLIBMapper extends MapperWrapper { + + private static String DEFAULT_NAMING_MARKER = "$$EnhancerByCGLIB$$"; + private final String alias; + + public interface Marker {} + + public CGLIBMapper(final Mapper wrapped) { + this(wrapped, "CGLIB-enhanced-proxy"); + } + + public CGLIBMapper(final Mapper wrapped, final String alias) { + super(wrapped); + this.alias = alias; + } + + @Override + public String serializedClass(final Class type) { + final String serializedName = super.serializedClass(type); + if (type == null) { + return serializedName; + } + final String typeName = type.getName(); + return typeName.equals(serializedName) + && typeName.indexOf(DEFAULT_NAMING_MARKER) > 0 + && Enhancer.isEnhanced(type) ? alias : serializedName; + } + + @Override + public Class realClass(final String elementName) { + return elementName.equals(alias) ? Marker.class : super.realClass(elementName); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CachingMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CachingMapper.java (.../CachingMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CachingMapper.java (.../CachingMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,33 +1,70 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014 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 22. January 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; - -import java.util.Map; import java.util.Collections; import java.util.HashMap; +import java.util.Map; +import com.thoughtworks.xstream.XStreamException; +import com.thoughtworks.xstream.core.Caching; +import com.thoughtworks.xstream.security.ForbiddenClassException; + + /** * Mapper that caches which names map to which classes. Prevents repetitive searching and class loading. - * + * * @author Joe Walnes + * @author Jörg Schaible */ -public class CachingMapper extends MapperWrapper { +public class CachingMapper extends MapperWrapper implements Caching { - private final Map cache = Collections.synchronizedMap(new HashMap()); + private transient Map realClassCache; - public CachingMapper(ClassMapper wrapped) { + public CachingMapper(final Mapper wrapped) { super(wrapped); + readResolve(); } - public Class realClass(String elementName) { - Class cached = (Class) cache.get(elementName); + @Override + public Class realClass(final String elementName) { + final Object cached = realClassCache.get(elementName); if (cached != null) { - return cached; - } else { - Class result = super.realClass(elementName); - cache.put(elementName, result); + if (cached instanceof Class) { + return (Class)cached; + } + throw (XStreamException)cached; + } + + try { + final Class result = super.realClass(elementName); + realClassCache.put(elementName, result); return result; + } catch (final ForbiddenClassException e) { + realClassCache.put(elementName, e); + throw e; + } catch (final CannotResolveClassException e) { + realClassCache.put(elementName, e); + throw e; } } + @Override + public void flushCache() { + realClassCache.clear(); + } + + private Object readResolve() { + realClassCache = Collections.synchronizedMap(new HashMap(128)); + return this; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CannotResolveClassException.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CannotResolveClassException.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/CannotResolveClassException.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2003 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011 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.mapper; + +import com.thoughtworks.xstream.XStreamException; + +/** + * Exception thrown if a mapper cannot locate the appropriate class for an element. + * + * @author Joe Walnes + * @author Jörg Schaible + * @since 1.2 + */ +public class CannotResolveClassException extends XStreamException { + public CannotResolveClassException(String className) { + super(className); + } + /** + * @since 1.4.2 + */ + public CannotResolveClassException(String className, Throwable cause) { + super(className, cause); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ClassAliasingMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ClassAliasingMapper.java (.../ClassAliasingMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ClassAliasingMapper.java (.../ClassAliasingMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,52 +1,94 @@ +/* + * Copyright (C) 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 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 09. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; - -import java.util.Map; -import java.util.Collections; import java.util.HashMap; +import java.util.Map; +import com.thoughtworks.xstream.core.util.Primitives; + + /** - * Mapper that allows a fully qualified class name to be replaced with a shorter alias. - * + * Mapper that allows a fully qualified class name to be replaced with an alias. + * * @author Joe Walnes + * @author Jörg Schaible */ public class ClassAliasingMapper extends MapperWrapper { - protected final Map typeToNameMap = Collections.synchronizedMap(new HashMap()); - protected final Map nameToTypeMap = Collections.synchronizedMap(new HashMap()); + private final Map, String> typeToName = new HashMap, String>(); + private final Map classToName = new HashMap(); + private transient Map nameToType = new HashMap(); - public ClassAliasingMapper(ClassMapper wrapped) { + public ClassAliasingMapper(final Mapper wrapped) { super(wrapped); } - public void addClassAlias(String name, Class type) { - nameToTypeMap.put(name, type.getName()); - typeToNameMap.put(type.getName(), name); + public void addClassAlias(final String name, final Class type) { + nameToType.put(name, type.getName()); + classToName.put(type.getName(), name); } - public String serializedClass(Class type) { - String name = super.serializedClass(type); - String alias = (String) typeToNameMap.get(type.getName()); + public void addTypeAlias(final String name, final Class type) { + nameToType.put(name, type.getName()); + typeToName.put(type, name); + } + + @Override + public String serializedClass(final Class type) { + final String alias = classToName.get(type.getName()); if (alias != null) { return alias; } else { - return name; + for (final Class compatibleType : typeToName.keySet()) { + if (compatibleType.isAssignableFrom(type)) { + return typeToName.get(compatibleType); + } + } + return super.serializedClass(type); } } - public Class realClass(String elementName) { - if (elementName.equals("null")) { // TODO: This is probably the wrong place for this. - return null; - } + @Override + public Class realClass(String elementName) { + final String mappedName = nameToType.get(elementName); - String mappedName = (String) nameToTypeMap.get(mapNameFromXML(elementName)); - if (mappedName != null) { + final Class type = Primitives.primitiveType(mappedName); + if (type != null) { + return type; + } elementName = mappedName; } return super.realClass(elementName); } + public boolean itemTypeAsAttribute(final Class clazz) { + return classToName.containsKey(clazz); + } + + public boolean aliasIsAttribute(final String name) { + return nameToType.containsKey(name); + } + + private Object readResolve() { + nameToType = new HashMap(); + for (final String type : classToName.keySet()) { + nameToType.put(classToName.get(type), type); + } + for (final Class type : typeToName.keySet()) { + nameToType.put(typeToName.get(type), type.getName()); + } + return this; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultImplementationsMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultImplementationsMapper.java (.../DefaultImplementationsMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultImplementationsMapper.java (.../DefaultImplementationsMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,28 +1,41 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2014 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 22. January 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; - -import java.util.Collections; import java.util.HashMap; import java.util.Map; +import com.thoughtworks.xstream.InitializationException; + + /** - * Mapper that resolves default implementations of classes. For example, mapper.lookupName(ArrayList.class) will return - * java.util.List. Calling mapper.defaultImplementationOf(List.class) will return ArrayList. - * - * @author Joe Walnes + * Mapper that resolves default implementations of classes. For example, mapper.serializedClass(ArrayList.class) will + * return java.util.List. Calling mapper.defaultImplementationOf(List.class) will return ArrayList. + * + * @author Joe Walnes */ public class DefaultImplementationsMapper extends MapperWrapper { - private final Map typeToImpl = Collections.synchronizedMap(new HashMap()); - private final Map implToType = Collections.synchronizedMap(new HashMap()); + private final Map, Class> typeToImpl = new HashMap, Class>(); + private transient Map, Class> implToType = new HashMap, Class>(); - public DefaultImplementationsMapper(ClassMapper wrapped) { + public DefaultImplementationsMapper(final Mapper wrapped) { super(wrapped); addDefaults(); } protected void addDefaults() { + // null handling + addDefaultImplementation(null, Mapper.Null.class); // register primitive types addDefaultImplementation(Boolean.class, boolean.class); addDefaultImplementation(Character.class, char.class); @@ -34,19 +47,35 @@ addDefaultImplementation(Long.class, long.class); } - public void addDefaultImplementation(Class defaultImplementation, Class ofType) { + public void addDefaultImplementation(final Class defaultImplementation, final Class ofType) { + if (defaultImplementation != null && defaultImplementation.isInterface()) { + throw new InitializationException("Default implementation is not a concrete class: " + + defaultImplementation.getName()); + } typeToImpl.put(ofType, defaultImplementation); implToType.put(defaultImplementation, ofType); } - public String serializedClass(Class type) { - Class baseType = (Class) implToType.get(type); + @Override + public String serializedClass(final Class type) { + final Class baseType = implToType.get(type); return baseType == null ? super.serializedClass(type) : super.serializedClass(baseType); } - public Class defaultImplementationOf(Class type) { - Class result = (Class) typeToImpl.get(type); - return result == null ? super.defaultImplementationOf(type) : result; + @Override + public Class defaultImplementationOf(final Class type) { + if (typeToImpl.containsKey(type)) { + return typeToImpl.get(type); + } else { + return super.defaultImplementationOf(type); + } } + private Object readResolve() { + implToType = new HashMap, Class>(); + for (final Class type : typeToImpl.keySet()) { + implToType.put(typeToImpl.get(type), type); + } + return this; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultMapper.java (.../DefaultMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DefaultMapper.java (.../DefaultMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,110 +1,226 @@ +/* + * Copyright (C) 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 3014 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 22. January 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.CannotResolveClassException; -import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.core.ClassLoaderReference; +import com.thoughtworks.xstream.core.util.Primitives; + /** - * Default mapper implementation with 'vanilla' functionality. To build up the functionality required, wrap this mapper - * with other mapper implementations. - * + * Default mapper implementation with 'vanilla' functionality. + *

    + * To build up the functionality required, wrap this mapper with other mapper implementations. + *

    + * * @author Joe Walnes + * @author Jörg Schaible */ -public class DefaultMapper extends MapperWrapper { +public class DefaultMapper implements Mapper { - private final ClassLoader classLoader; - private final String classAttributeIdentifier; + private static String XSTREAM_PACKAGE_ROOT; + static { + final String packageName = DefaultMapper.class.getName(); + final int idx = packageName.indexOf(".xstream."); + XSTREAM_PACKAGE_ROOT = idx > 0 ? packageName.substring(0, idx + 9) : ".N/A"; + } - public DefaultMapper(ClassLoader classLoader) { - this(classLoader, "class"); + private final ClassLoaderReference classLoaderReference; + + /** + * Construct a DefaultMapper. + * + * @param classLoaderReference the reference to the classloader used by the XStream instance. + * @since 1.4.5 + */ + public DefaultMapper(final ClassLoaderReference classLoaderReference) { + this.classLoaderReference = classLoaderReference; } - public DefaultMapper(ClassLoader classLoader, String classAttributeIdentifier) { - super(null); - this.classLoader = classLoader; - this.classAttributeIdentifier = classAttributeIdentifier == null ? "class" : classAttributeIdentifier; + /** + * Construct a DefaultMapper. + * + * @param classLoader the ClassLoader used by the XStream instance. + * @deprecated As of 1.4.5 use {@link #DefaultMapper(ClassLoaderReference)} + */ + @Deprecated + public DefaultMapper(final ClassLoader classLoader) { + this(new ClassLoaderReference(classLoader)); } - public String serializedClass(Class type) { + @Override + public String serializedClass(final Class type) { return type.getName(); } - public Class realClass(String elementName) { + @Override + public Class realClass(final String elementName) { + final Class resultingClass = Primitives.primitiveType(elementName); + if (resultingClass != null) { + return resultingClass; + } try { - return classLoader.loadClass(elementName); - } catch (ClassNotFoundException e) { - throw new CannotResolveClassException(elementName + " : " + e.getMessage()); + boolean initialize = true; + final ClassLoader classLoader; + if (elementName.startsWith(XSTREAM_PACKAGE_ROOT)) { + classLoader = DefaultMapper.class.getClassLoader(); + } else { + classLoader = classLoaderReference.getReference(); + initialize = elementName.charAt(0) == '['; + } + return Class.forName(elementName, initialize, classLoader); + } catch (final ClassNotFoundException e) { + throw new CannotResolveClassException(elementName); } } - public Class lookupDefaultType(Class baseType) { - return baseType; - } - - public Class defaultImplementationOf(Class type) { + @Override + public Class defaultImplementationOf(final Class type) { return type; } - public String attributeForClassDefiningField() { - return "defined-in"; + @Override + public String aliasForAttribute(final String attribute) { + return attribute; } - public String attributeForReadResolveField() { - return "resolves-to"; + @Override + public String attributeForAlias(final String alias) { + return alias; } - public String attributeForEnumType() { - return "enum-type"; + @Override + public String aliasForSystemAttribute(final String attribute) { + return attribute; } - public String attributeForImplementationClass() { - return classAttributeIdentifier; - } - - public boolean isImmutableValueType(Class type) { + @Override + public boolean isImmutableValueType(final Class type) { return false; } - public String getFieldNameForItemTypeAndName(Class definedIn, Class itemType, String itemFieldName) { + @Override + public String getFieldNameForItemTypeAndName(final Class definedIn, final Class itemType, + final String itemFieldName) { return null; } - public Class getItemTypeForItemFieldName(Class definedIn, String itemFieldName) { + @Override + public Class getItemTypeForItemFieldName(final Class definedIn, final String itemFieldName) { return null; } - public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(Class itemType, String fieldName) { + @Override + public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(final Class itemType, + final String fieldName) { return null; } - public boolean shouldSerializeMember(Class definedIn, String fieldName) { + @Override + public boolean shouldSerializeMember(final Class definedIn, final String fieldName) { return true; } - public String lookupName(Class type) { + public String lookupName(final Class type) { return serializedClass(type); } - public Class lookupType(String elementName) { + public Class lookupType(final String elementName) { return realClass(elementName); } - public String serializedMember(Class type, String memberName) { + @Override + public String serializedMember(final Class type, final String memberName) { return memberName; } - public String realMember(Class type, String serialized) { + @Override + public String realMember(final Class type, final String serialized) { return serialized; } - public String mapNameFromXML(String xmlName) { - return xmlName; + /** + * @deprecated As of 1.3, use {@link #getConverterFromAttribute(Class, String, Class)} + */ + @Deprecated + public SingleValueConverter getConverterFromAttribute(final String name) { + throw new UnsupportedOperationException(); } - public String mapNameToXML(String javaName) { - return javaName; + /** + * @deprecated As of 1.3, use {@link #getConverterFromItemType(String, Class, Class)} + */ + @Deprecated + public SingleValueConverter getConverterFromItemType(final String fieldName, final Class type) { + throw new UnsupportedOperationException(); } - public void alias(String elementName, Class type, Class defaultImplementation) { + /** + * @deprecated As of 1.3, use {@link #getConverterFromItemType(String, Class, Class)} + */ + @Deprecated + public SingleValueConverter getConverterFromItemType(final Class type) { + throw new UnsupportedOperationException(); } + @Override + public SingleValueConverter getConverterFromItemType(final String fieldName, final Class type, + final Class definedIn) { + return null; + } + + @Override + public Converter getLocalConverter(final Class definedIn, final String fieldName) { + return null; + } + + @Override + public T lookupMapperOfType(final Class type) { + @SuppressWarnings("unchecked") + final T t = type.isAssignableFrom(getClass()) ? (T)this : null; + return t; + } + + /** + * @deprecated As of 1.3, use combination of {@link #serializedMember(Class, String)} and + * {@link #getConverterFromItemType(String, Class, Class)} + */ + @Deprecated + public String aliasForAttribute(final Class definedIn, final String fieldName) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated As of 1.3, use combination of {@link #realMember(Class, String)} and + * {@link #getConverterFromItemType(String, Class, Class)} + */ + @Deprecated + public String attributeForAlias(final Class definedIn, final String alias) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated As of 1.3.1, use {@link #getConverterFromAttribute(Class, String, Class)} + */ + @Deprecated + @Override + public SingleValueConverter getConverterFromAttribute(final Class definedIn, final String attribute) { + return null; + } + + @Override + public SingleValueConverter getConverterFromAttribute(final Class definedIn, final String attribute, + final Class type) { + return null; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DynamicProxyMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DynamicProxyMapper.java (.../DynamicProxyMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/DynamicProxyMapper.java (.../DynamicProxyMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,24 +1,36 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2014 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 22. January 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; - import java.lang.reflect.Proxy; + /** - * Mapper for handling special cases of aliasing dynamic proxies. The alias property specifies the name an instance - * of a dynamic proxy should be serialized with. - * + * Mapper for handling special cases of aliasing dynamic proxies. + *

    + * The alias property specifies the name an instance of a dynamic proxy should be serialized with. + *

    + * * @author Joe Walnes */ public class DynamicProxyMapper extends MapperWrapper { - private String alias = "dynamic-proxy"; + private String alias; - public DynamicProxyMapper(ClassMapper wrapped) { - super(wrapped); + public DynamicProxyMapper(final Mapper wrapped) { + this(wrapped, "dynamic-proxy"); } - public DynamicProxyMapper(ClassMapper wrapped, String alias) { + public DynamicProxyMapper(final Mapper wrapped, final String alias) { super(wrapped); this.alias = alias; } @@ -27,19 +39,21 @@ return alias; } - public void setAlias(String alias) { + public void setAlias(final String alias) { this.alias = alias; } - public String serializedClass(Class type) { + @Override + public String serializedClass(final Class type) { if (Proxy.isProxyClass(type)) { return alias; } else { return super.serializedClass(type); } } - public Class realClass(String elementName) { + @Override + public Class realClass(final String elementName) { if (elementName.equals(alias)) { return DynamicProxy.class; } else { Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/EnumMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/EnumMapper.java (.../EnumMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/EnumMapper.java (.../EnumMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,40 +1,111 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014 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 20. March 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; -import com.thoughtworks.xstream.core.JVM; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.converters.enums.EnumSingleValueConverter; +import com.thoughtworks.xstream.core.Caching; + + /** - * Mapper that handles the special case of polymorphic enums in Java 1.5. This renames MyEnum$1 to MyEnum making it - * less bloaty in the XML and avoiding the need for an alias per enum value to be specified. - * + * Mapper that handles the special case of polymorphic enums in Java 1.5. This renames MyEnum$1 to MyEnum making it less + * bloaty in the XML and avoiding the need for an alias per enum value to be specified. Additionally every enum is + * treated automatically as immutable type and can be written as attribute. + * * @author Joe Walnes + * @author Jörg Schaible */ -public class EnumMapper extends MapperWrapper { +public class EnumMapper extends MapperWrapper implements Caching { - // Dynamically try to load Enum class. Pre JDK1.5 will silently fail. - private static JVM jvm = new JVM(); - private static final Class enumClass = jvm.loadClass("java.lang.Enum"); + private transient AttributeMapper attributeMapper; + private transient Map, SingleValueConverter> enumConverterMap; - private static final boolean active = enumClass != null; - - private static final Class enumSetClass = active ? jvm.loadClass("java.util.EnumSet") : null; - - public EnumMapper(ClassMapper wrapped) { + public EnumMapper(final Mapper wrapped) { super(wrapped); + readResolve(); } - public String serializedClass(Class type) { - if (!active) { + @Override + public String serializedClass(final Class type) { + if (type == null) { return super.serializedClass(type); + } + if (Enum.class.isAssignableFrom(type) && type.getSuperclass() != Enum.class) { + return super.serializedClass(type.getSuperclass()); + } else if (EnumSet.class.isAssignableFrom(type)) { + return super.serializedClass(EnumSet.class); } else { - if (enumClass.isAssignableFrom(type) && type.getSuperclass() != enumClass) { - return super.serializedClass(type.getSuperclass()); - } else if (enumSetClass.isAssignableFrom(type)) { - return super.serializedClass(enumSetClass); - } else { - return super.serializedClass(type); + return super.serializedClass(type); + } + } + + @Override + public boolean isImmutableValueType(final Class type) { + return Enum.class.isAssignableFrom(type) || super.isImmutableValueType(type); + } + + @Override + public SingleValueConverter getConverterFromItemType(final String fieldName, final Class type, + final Class definedIn) { + final SingleValueConverter converter = getLocalConverter(fieldName, type, definedIn); + return converter == null ? super.getConverterFromItemType(fieldName, type, definedIn) : converter; + } + + @Override + public SingleValueConverter getConverterFromAttribute(final Class definedIn, final String attribute, + final Class type) { + final SingleValueConverter converter = getLocalConverter(attribute, type, definedIn); + return converter == null ? super.getConverterFromAttribute(definedIn, attribute, type) : converter; + } + + private SingleValueConverter getLocalConverter(final String fieldName, final Class type, final Class definedIn) { + if (attributeMapper != null + && Enum.class.isAssignableFrom(type) + && attributeMapper.shouldLookForSingleValueConverter(fieldName, type, definedIn)) { + synchronized (enumConverterMap) { + SingleValueConverter singleValueConverter = enumConverterMap.get(type); + if (singleValueConverter == null) { + singleValueConverter = super.getConverterFromItemType(fieldName, type, definedIn); + if (singleValueConverter == null) { + @SuppressWarnings("unchecked") + final Class> enumType = (Class>)type; + @SuppressWarnings({"rawtypes", "unchecked"}) + final EnumSingleValueConverter enumConverter = new EnumSingleValueConverter(enumType); + singleValueConverter = enumConverter; + } + enumConverterMap.put(type, singleValueConverter); + } + return singleValueConverter; } } + return null; } + @Override + public void flushCache() { + if (enumConverterMap.size() > 0) { + synchronized (enumConverterMap) { + enumConverterMap.clear(); + } + } + } + + private Object readResolve() { + enumConverterMap = new HashMap, SingleValueConverter>(); + attributeMapper = lookupMapperOfType(AttributeMapper.class); + return this; + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java (.../FieldAliasingMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java (.../FieldAliasingMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,57 +1,99 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014 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 09. April 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; -import java.util.*; +import com.thoughtworks.xstream.core.util.FastField; + /** - * Mapper that allows a field of a specific class to be replaced with a shorter alias, or omitted - * entirely. - * + * Mapper that allows a field of a specific class to be replaced with a shorter alias, or omitted entirely. + * * @author Joe Walnes */ public class FieldAliasingMapper extends MapperWrapper { - protected final Map fieldToAliasMap = Collections.synchronizedMap(new HashMap()); - protected final Map aliasToFieldMap = Collections.synchronizedMap(new HashMap()); - protected final Set fieldsToOmit = Collections.synchronizedSet(new HashSet()); + protected final Map fieldToAliasMap = new HashMap(); + protected final Map aliasToFieldMap = new HashMap(); + protected final Set fieldsToOmit = new HashSet(); + protected final Set unknownFieldsToIgnore = new LinkedHashSet(); - public FieldAliasingMapper(ClassMapper wrapped) { + public FieldAliasingMapper(final Mapper wrapped) { super(wrapped); } - public void addFieldAlias(String alias, Class type, String fieldName) { + public void addFieldAlias(final String alias, final Class type, final String fieldName) { fieldToAliasMap.put(key(type, fieldName), alias); aliasToFieldMap.put(key(type, alias), fieldName); } - private Object key(Class type, String value) { - return type.getName() + '.' + value; + public void addFieldsToIgnore(final Pattern pattern) { + unknownFieldsToIgnore.add(pattern); } - public String serializedMember(Class type, String memberName) { - String alias = (String) fieldToAliasMap.get(key(type, memberName)); + private FastField key(final Class type, final String name) { + return new FastField(type, name); + } + + @Override + public String serializedMember(final Class type, final String memberName) { + final String alias = getMember(type, memberName, fieldToAliasMap); if (alias == null) { return super.serializedMember(type, memberName); } else { return alias; } } - public String realMember(Class type, String serialized) { - String real = (String) aliasToFieldMap.get(key(type, serialized)); + @Override + public String realMember(final Class type, final String serialized) { + final String real = getMember(type, serialized, aliasToFieldMap); if (real == null) { return super.realMember(type, serialized); } else { return real; } } - public boolean shouldSerializeMember(Class definedIn, String fieldName) { - return !fieldsToOmit.contains(key(definedIn, fieldName)); + private String getMember(final Class type, final String name, final Map map) { + String member = null; + for (Class declaringType = type; member == null && declaringType != Object.class && declaringType != null; declaringType = declaringType + .getSuperclass()) { + member = map.get(key(declaringType, name)); + } + return member; } - public void omitField(Class type, String fieldName) { - fieldsToOmit.add(key(type, fieldName)); + @Override + public boolean shouldSerializeMember(final Class definedIn, final String fieldName) { + if (fieldsToOmit.contains(key(definedIn, fieldName))) { + return false; + } else if (definedIn == Object.class && !unknownFieldsToIgnore.isEmpty()) { + for (final Pattern pattern : unknownFieldsToIgnore) { + if (pattern.matcher(fieldName).matches()) { + return false; + } + } + } + return true; } + + public void omitField(final Class definedIn, final String fieldName) { + fieldsToOmit.add(key(definedIn, fieldName)); + } } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImmutableTypesMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImmutableTypesMapper.java (.../ImmutableTypesMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImmutableTypesMapper.java (.../ImmutableTypesMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,30 +1,40 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2014 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 22. January 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; - -import java.util.Collections; import java.util.HashSet; import java.util.Set; + /** * Mapper that specifies which types are basic immutable types. Types that are marked as immutable will be written * multiple times in the serialization stream without using references. - * + * * @author Joe Walnes */ public class ImmutableTypesMapper extends MapperWrapper { - private final Set immutableTypes = Collections.synchronizedSet(new HashSet()); + private final Set> immutableTypes = new HashSet>(); - public ImmutableTypesMapper(ClassMapper wrapped) { + public ImmutableTypesMapper(final Mapper wrapped) { super(wrapped); } - public void addImmutableType(Class type) { + public void addImmutableType(final Class type) { immutableTypes.add(type); } - public boolean isImmutableValueType(Class type) { + @Override + public boolean isImmutableValueType(final Class type) { if (immutableTypes.contains(type)) { return true; } else { Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImplicitCollectionMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImplicitCollectionMapper.java (.../ImplicitCollectionMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/ImplicitCollectionMapper.java (.../ImplicitCollectionMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,24 +1,36 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2012, 2013, 2014 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 16. February 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; - -import java.util.Collections; +import java.lang.reflect.Field; +import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; +import com.thoughtworks.xstream.InitializationException; +import com.thoughtworks.xstream.core.util.Primitives; + + public class ImplicitCollectionMapper extends MapperWrapper { - public ImplicitCollectionMapper(ClassMapper wrapped) { + public ImplicitCollectionMapper(final Mapper wrapped) { super(wrapped); } - // { definedIn (Class) -> (ImplicitCollectionMapperForClass) } - private Map classNameToMapper = Collections.synchronizedMap(new HashMap()); + private final Map, ImplicitCollectionMapperForClass> classNameToMapper = new HashMap, ImplicitCollectionMapperForClass>(); - private ImplicitCollectionMapperForClass getMapper(Class definedIn) { + private ImplicitCollectionMapperForClass getMapper(Class definedIn) { while (definedIn != null) { - ImplicitCollectionMapperForClass mapper = (ImplicitCollectionMapperForClass) classNameToMapper.get(definedIn); + final ImplicitCollectionMapperForClass mapper = classNameToMapper.get(definedIn); if (mapper != null) { return mapper; } @@ -27,108 +39,176 @@ return null; } - private ImplicitCollectionMapperForClass getOrCreateMapper(Class definedIn) { - ImplicitCollectionMapperForClass mapper = getMapper(definedIn); + private ImplicitCollectionMapperForClass getOrCreateMapper(final Class definedIn) { + ImplicitCollectionMapperForClass mapper = classNameToMapper.get(definedIn); if (mapper == null) { mapper = new ImplicitCollectionMapperForClass(definedIn); classNameToMapper.put(definedIn, mapper); } return mapper; } - public String getFieldNameForItemTypeAndName(Class definedIn, Class itemType, String itemFieldName) { - ImplicitCollectionMapperForClass mapper = getMapper(definedIn); + @Override + public String getFieldNameForItemTypeAndName(final Class definedIn, final Class itemType, + final String itemFieldName) { + final ImplicitCollectionMapperForClass mapper = getMapper(definedIn); if (mapper != null) { return mapper.getFieldNameForItemTypeAndName(itemType, itemFieldName); } else { return null; } } - public Class getItemTypeForItemFieldName(Class definedIn, String itemFieldName) { - ImplicitCollectionMapperForClass mapper = getMapper(definedIn); + @Override + public Class getItemTypeForItemFieldName(final Class definedIn, final String itemFieldName) { + final ImplicitCollectionMapperForClass mapper = getMapper(definedIn); if (mapper != null) { return mapper.getItemTypeForItemFieldName(itemFieldName); } else { return null; } } - public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(Class itemType, String fieldName) { - ImplicitCollectionMapperForClass mapper = getMapper(itemType); + @Override + public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(final Class itemType, + final String fieldName) { + final ImplicitCollectionMapperForClass mapper = getMapper(itemType); if (mapper != null) { return mapper.getImplicitCollectionDefForFieldName(fieldName); } else { return null; } } - public void add(Class definedIn, String fieldName, Class itemType) { + public void add(final Class definedIn, final String fieldName, final Class itemType) { add(definedIn, fieldName, null, itemType); } - public void add(Class definedIn, String fieldName, String itemFieldName, Class itemType) { - ImplicitCollectionMapperForClass mapper = getOrCreateMapper(definedIn); - mapper.add(new ImplicitCollectionMappingImpl(fieldName, itemType, itemFieldName)); + public void add(final Class definedIn, final String fieldName, final String itemFieldName, + final Class itemType) { + add(definedIn, fieldName, itemFieldName, itemType, null); } - private static class ImplicitCollectionMapperForClass { - //private Class definedIn; - private Map namedItemTypeToDef = new HashMap(); // { (NamedItemType) -> (ImplicitCollectionDefImpl) } - private Map itemFieldNameToDef = new HashMap(); // { itemFieldName (String) -> (ImplicitCollectionDefImpl) } - private Map fieldNameToDef = new HashMap(); // { fieldName (String) -> (ImplicitCollectionDefImpl) } + public void add(final Class definedIn, final String fieldName, final String itemFieldName, Class itemType, + final String keyFieldName) { + Field field = null; + Class declaredIn = definedIn; + while (declaredIn != Object.class && definedIn != null) { + try { + field = declaredIn.getDeclaredField(fieldName); + break; + } catch (final SecurityException e) { + throw new InitializationException("Access denied for field with implicit collection", e); + } catch (final NoSuchFieldException e) { + declaredIn = declaredIn.getSuperclass(); + } + } + if (field == null) { + throw new InitializationException("No field \"" + fieldName + "\" for implicit collection"); + } else if (Map.class.isAssignableFrom(field.getType())) { + if (itemFieldName == null && keyFieldName == null) { + itemType = Map.Entry.class; + } + } else if (!Collection.class.isAssignableFrom(field.getType())) { + final Class fieldType = field.getType(); + if (!fieldType.isArray()) { + throw new InitializationException("Field \"" + fieldName + "\" declares no collection or array"); + } else { + Class componentType = fieldType.getComponentType(); + componentType = componentType.isPrimitive() ? Primitives.box(componentType) : componentType; + if (itemType == null) { + itemType = componentType; + } else { + itemType = itemType.isPrimitive() ? Primitives.box(itemType) : itemType; + if (!componentType.isAssignableFrom(itemType)) { + throw new InitializationException("Field \"" + + fieldName + + "\" declares an array, but the array type is not compatible with " + + itemType.getName()); - public ImplicitCollectionMapperForClass(Class definedIn) { - //this.definedIn = definedIn; + } + } + } } + final ImplicitCollectionMapperForClass mapper = getOrCreateMapper(definedIn); + mapper.add(new ImplicitCollectionMappingImpl(fieldName, itemType, itemFieldName, keyFieldName)); + } - public String getFieldNameForItemTypeAndName(Class itemType, String itemFieldName) { + private class ImplicitCollectionMapperForClass { + private final Class definedIn; + private final Map namedItemTypeToDef = new HashMap(); + private final Map itemFieldNameToDef = new HashMap(); + private final Map fieldNameToDef = new HashMap(); + + ImplicitCollectionMapperForClass(final Class definedIn) { + this.definedIn = definedIn; + } + + public String getFieldNameForItemTypeAndName(final Class itemType, final String itemFieldName) { ImplicitCollectionMappingImpl unnamed = null; - for (Iterator iterator = namedItemTypeToDef.keySet().iterator(); iterator.hasNext();) { - NamedItemType itemTypeForFieldName = (NamedItemType) iterator.next(); - if (itemTypeForFieldName.itemType.isAssignableFrom(itemType)) { - ImplicitCollectionMappingImpl def = (ImplicitCollectionMappingImpl) namedItemTypeToDef.get(itemTypeForFieldName); + for (final NamedItemType itemTypeForFieldName : namedItemTypeToDef.keySet()) { + final ImplicitCollectionMappingImpl def = namedItemTypeToDef.get(itemTypeForFieldName); + if (itemType == Mapper.Null.class) { + unnamed = def; + break; + } else if (itemTypeForFieldName.itemType.isAssignableFrom(itemType)) { if (def.getItemFieldName() != null) { if (def.getItemFieldName().equals(itemFieldName)) { return def.getFieldName(); } } else { - unnamed = def; - if (itemFieldName == null) { - break; + if (unnamed == null + || unnamed.getItemType() == null + || def.getItemType() != null + && unnamed.getItemType().isAssignableFrom(def.getItemType())) { + unnamed = def; } } } } - return unnamed != null ? unnamed.getFieldName() : null; + if (unnamed != null) { + return unnamed.getFieldName(); + } else { + final ImplicitCollectionMapperForClass mapper = getMapper(definedIn.getSuperclass()); + return mapper != null ? mapper.getFieldNameForItemTypeAndName(itemType, itemFieldName) : null; + } } - public Class getItemTypeForItemFieldName(String itemFieldName) { - ImplicitCollectionMappingImpl def = getImplicitCollectionDefByItemFieldName(itemFieldName); + public Class getItemTypeForItemFieldName(final String itemFieldName) { + final ImplicitCollectionMappingImpl def = getImplicitCollectionDefByItemFieldName(itemFieldName); if (def != null) { return def.getItemType(); } else { - return null; + final ImplicitCollectionMapperForClass mapper = getMapper(definedIn.getSuperclass()); + return mapper != null ? mapper.getItemTypeForItemFieldName(itemFieldName) : null; } } - private ImplicitCollectionMappingImpl getImplicitCollectionDefByItemFieldName(String itemFieldName) { + private ImplicitCollectionMappingImpl getImplicitCollectionDefByItemFieldName(final String itemFieldName) { if (itemFieldName == null) { return null; } else { - return (ImplicitCollectionMappingImpl) itemFieldNameToDef.get(itemFieldName); + final ImplicitCollectionMappingImpl mapping = itemFieldNameToDef.get(itemFieldName); + if (mapping != null) { + return mapping; + } else { + final ImplicitCollectionMapperForClass mapper = getMapper(definedIn.getSuperclass()); + return mapper != null ? mapper.getImplicitCollectionDefByItemFieldName(itemFieldName) : null; + } } } - public ImplicitCollectionMappingImpl getImplicitCollectionDefByFieldName(String fieldName) { - return (ImplicitCollectionMappingImpl) fieldNameToDef.get(fieldName); + public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(final String fieldName) { + final ImplicitCollectionMapping mapping = fieldNameToDef.get(fieldName); + if (mapping != null) { + return mapping; + } else { + final ImplicitCollectionMapperForClass mapper = getMapper(definedIn.getSuperclass()); + return mapper != null ? mapper.getImplicitCollectionDefForFieldName(fieldName) : null; + } } - public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(String fieldName) { - return (ImplicitCollectionMapping) fieldNameToDef.get(fieldName); - } - - public void add(ImplicitCollectionMappingImpl def) { + public void add(final ImplicitCollectionMappingImpl def) { fieldNameToDef.put(def.getFieldName(), def); namedItemTypeToDef.put(def.createNamedItemType(), def); if (def.getItemFieldName() != null) { @@ -139,88 +219,72 @@ } private static class ImplicitCollectionMappingImpl implements ImplicitCollectionMapping { - private String fieldName; - private String itemFieldName; - private Class itemType; + private final String fieldName; + private final String itemFieldName; + private final Class itemType; + private final String keyFieldName; - ImplicitCollectionMappingImpl(String fieldName, Class itemType, String itemFieldName) { + ImplicitCollectionMappingImpl( + final String fieldName, final Class itemType, final String itemFieldName, final String keyFieldName) { this.fieldName = fieldName; this.itemFieldName = itemFieldName; this.itemType = itemType; + this.keyFieldName = keyFieldName; } - - public boolean equals(Object obj) { - if (obj instanceof ImplicitCollectionMappingImpl) { - ImplicitCollectionMappingImpl b = (ImplicitCollectionMappingImpl) obj; - return fieldName.equals(b.fieldName) - && isEquals(itemFieldName, b.itemFieldName); - } else { - return false; - } - } - public NamedItemType createNamedItemType() { return new NamedItemType(itemType, itemFieldName); } - private static boolean isEquals(Object a, Object b) { - if (a == null) { - return b == null; - } else { - return a.equals(b); - } - } - - public int hashCode() { - int hash = fieldName.hashCode(); - if (itemFieldName != null) { - hash += itemFieldName.hashCode() << 7; - } - return hash; - } - + @Override public String getFieldName() { return fieldName; } + @Override public String getItemFieldName() { return itemFieldName; } - public Class getItemType() { + @Override + public Class getItemType() { return itemType; } + + @Override + public String getKeyFieldName() { + return keyFieldName; + } } private static class NamedItemType { - Class itemType; + Class itemType; String itemFieldName; - NamedItemType(Class itemType, String itemFieldName) { - this.itemType = itemType; + NamedItemType(final Class itemType, final String itemFieldName) { + this.itemType = itemType == null ? Object.class : itemType; this.itemFieldName = itemFieldName; } - - public boolean equals(Object obj) { + @Override + public boolean equals(final Object obj) { if (obj instanceof NamedItemType) { - NamedItemType b = (NamedItemType) obj; - return itemType.equals(b.itemType) - && isEquals(itemFieldName, b.itemFieldName); + final NamedItemType b = (NamedItemType)obj; + return itemType.equals(b.itemType) && isEquals(itemFieldName, b.itemFieldName); } else { return false; } } - private static boolean isEquals(Object a, Object b) { + private static boolean isEquals(final Object a, final Object b) { if (a == null) { return b == null; } else { return a.equals(b); } } + @Override public int hashCode() { int hash = itemType.hashCode() << 7; if (itemFieldName != null) { @@ -230,4 +294,3 @@ } } } - Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/LocalConversionMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/LocalConversionMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/LocalConversionMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2007, 2008, 2014 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 06. November 2007 by Joerg Schaible + */ +package com.thoughtworks.xstream.mapper; + +import java.util.HashMap; +import java.util.Map; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.core.util.FastField; + + +/** + * A Mapper for locally defined converters for a member field. + * + * @author Jörg Schaible + * @since 1.3 + */ +public class LocalConversionMapper extends MapperWrapper { + + private final Map localConverters = new HashMap(); + private transient AttributeMapper attributeMapper; + + /** + * Constructs a LocalConversionMapper. + * + * @param wrapped + * @since 1.3 + */ + public LocalConversionMapper(final Mapper wrapped) { + super(wrapped); + readResolve(); + } + + public void registerLocalConverter(final Class definedIn, final String fieldName, final Converter converter) { + localConverters.put(new FastField(definedIn, fieldName), converter); + } + + @Override + public Converter getLocalConverter(final Class definedIn, final String fieldName) { + return localConverters.get(new FastField(definedIn, fieldName)); + } + + @Override + public SingleValueConverter getConverterFromAttribute(final Class definedIn, final String attribute, + final Class type) { + final SingleValueConverter converter = getLocalSingleValueConverter(definedIn, attribute, type); + return converter == null ? super.getConverterFromAttribute(definedIn, attribute, type) : converter; + } + + @Override + public SingleValueConverter getConverterFromItemType(final String fieldName, final Class type, + final Class definedIn) { + final SingleValueConverter converter = getLocalSingleValueConverter(definedIn, fieldName, type); + return converter == null ? super.getConverterFromItemType(fieldName, type, definedIn) : converter; + } + + private SingleValueConverter getLocalSingleValueConverter(final Class definedIn, final String fieldName, + final Class type) { + if (attributeMapper != null && attributeMapper.shouldLookForSingleValueConverter(fieldName, type, definedIn)) { + final Converter converter = getLocalConverter(definedIn, fieldName); + if (converter != null && converter instanceof SingleValueConverter) { + return (SingleValueConverter)converter; + } + } + return null; + } + + private Object readResolve() { + attributeMapper = lookupMapperOfType(AttributeMapper.class); + return this; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/Mapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/Mapper.java (.../Mapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/Mapper.java (.../Mapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,67 +1,143 @@ +/* + * Copyright (C) 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2103, 2014 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 22. January 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.SingleValueConverter; + + public interface Mapper { + /** + * Place holder type used for null values. + */ + class Null {} /** * How a class name should be represented in its serialized form. */ - String serializedClass(Class type); + String serializedClass(Class type); /** * How a serialized class representation should be mapped back to a real class. */ - Class realClass(String elementName); + Class realClass(String elementName); /** * How a class member should be represented in its serialized form. */ - String serializedMember(Class type, String memberName); + String serializedMember(Class type, String memberName); /** * How a serialized member representation should be mapped back to a real member. */ - String realMember(Class type, String serialized); + String realMember(Class type, String serialized); /** - * Whether this type is a simple immutable value (int, boolean, String, URL, etc. - * Immutable types will be repeatedly written in the serialized stream, instead of using object references. + * Whether this type is a simple immutable value (int, boolean, String, URL, etc. Immutable types will be repeatedly + * written in the serialized stream, instead of using object references. */ - boolean isImmutableValueType(Class type); + boolean isImmutableValueType(Class type); - Class defaultImplementationOf(Class type); + Class defaultImplementationOf(Class type); - String attributeForImplementationClass(); + /** + * Get the alias for an attribute's name. + * + * @param attribute the attribute + * @return the alias + * @since 1.2 + */ + String aliasForAttribute(String attribute); - String attributeForClassDefiningField(); + /** + * Get the attribute's name for an alias. + * + * @param alias the alias + * @return the attribute's name + * @since 1.2 + */ + String attributeForAlias(String alias); - String attributeForReadResolveField(); + /** + * Get the alias for a system attribute's name. + * + * @param attribute the system attribute + * @return the alias + * @since 1.3.1 + */ + String aliasForSystemAttribute(String attribute); - String attributeForEnumType(); - /** * Get the name of the field that acts as the default collection for an object, or return null if there is none. - * - * @param definedIn owning type - * @param itemType item type + * + * @param definedIn owning type + * @param itemType item type * @param itemFieldName optional item element name */ - String getFieldNameForItemTypeAndName(Class definedIn, Class itemType, String itemFieldName); + String getFieldNameForItemTypeAndName(Class definedIn, Class itemType, String itemFieldName); - Class getItemTypeForItemFieldName(Class definedIn, String itemFieldName); + Class getItemTypeForItemFieldName(Class definedIn, String itemFieldName); - ImplicitCollectionMapping getImplicitCollectionDefForFieldName(Class itemType, String fieldName); + ImplicitCollectionMapping getImplicitCollectionDefForFieldName(Class itemType, String fieldName); /** * Determine whether a specific member should be serialized. - * - * @since 1.2 + * + * @since 1.1.3 */ - boolean shouldSerializeMember(Class definedIn, String fieldName); + boolean shouldSerializeMember(Class definedIn, String fieldName); interface ImplicitCollectionMapping { String getFieldName(); + String getItemFieldName(); - Class getItemType(); + + Class getItemType(); + + String getKeyFieldName(); } + Converter getLocalConverter(Class definedIn, String fieldName); + + T lookupMapperOfType(final Class type); + + /** + * Returns a single value converter to be used in a specific field. + * + * @param fieldName the field name + * @param type the field type + * @param definedIn the type which defines this field + * @return a SingleValueConverter or null if there no such converter should be used for this field. + * @since 1.2.2 + */ + SingleValueConverter getConverterFromItemType(String fieldName, Class type, Class definedIn); + + /** + * Returns which converter to use for an specific attribute in a type. + * + * @param definedIn the field's parent + * @param attribute the attribute name + * @deprecated As of 1.3.1, use {@link #getConverterFromAttribute(Class, String, Class)} + */ + @Deprecated + SingleValueConverter getConverterFromAttribute(Class definedIn, String attribute); + + /** + * Returns which converter to use for an specific attribute in a type. + * + * @param definedIn the field's parent + * @param attribute the attribute name + * @param type the type the converter should create + * @since 1.3.1 + */ + SingleValueConverter getConverterFromAttribute(Class definedIn, String attribute, Class type); } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/MapperWrapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/MapperWrapper.java (.../MapperWrapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/MapperWrapper.java (.../MapperWrapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,127 +1,126 @@ +/* + * Copyright (C) 2005, 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014 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 22. January 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.SingleValueConverter; -public abstract class MapperWrapper implements ClassMapper { - private final ClassMapper wrapped; +public abstract class MapperWrapper implements Mapper { - public MapperWrapper(ClassMapper wrapped) { + private final Mapper wrapped; + + public MapperWrapper(final Mapper wrapped) { this.wrapped = wrapped; } - public String serializedClass(Class type) { + @Override + public String serializedClass(final Class type) { return wrapped.serializedClass(type); } - public Class realClass(String elementName) { + @Override + public Class realClass(final String elementName) { return wrapped.realClass(elementName); } - public String serializedMember(Class type, String memberName) { + @Override + public String serializedMember(final Class type, final String memberName) { return wrapped.serializedMember(type, memberName); } - public String realMember(Class type, String serialized) { + @Override + public String realMember(final Class type, final String serialized) { return wrapped.realMember(type, serialized); } - public String mapNameFromXML(String xmlName) { - return wrapped.mapNameFromXML(xmlName); - } - - public String mapNameToXML(String javaName) { - return wrapped.mapNameToXML(javaName); - } - - public boolean isImmutableValueType(Class type) { + @Override + public boolean isImmutableValueType(final Class type) { return wrapped.isImmutableValueType(type); } - public Class defaultImplementationOf(Class type) { + @Override + public Class defaultImplementationOf(final Class type) { return wrapped.defaultImplementationOf(type); } - public String attributeForClassDefiningField() { - return wrapped.attributeForClassDefiningField(); + @Override + public String aliasForAttribute(final String attribute) { + return wrapped.aliasForAttribute(attribute); } - public String attributeForImplementationClass() { - return wrapped.attributeForImplementationClass(); + @Override + public String attributeForAlias(final String alias) { + return wrapped.attributeForAlias(alias); } - public String attributeForReadResolveField() { - return wrapped.attributeForReadResolveField(); + @Override + public String aliasForSystemAttribute(final String attribute) { + return wrapped.aliasForSystemAttribute(attribute); } - public String attributeForEnumType() { - return wrapped.attributeForEnumType(); - } - - public String getFieldNameForItemTypeAndName(Class definedIn, Class itemType, String itemFieldName) { + @Override + public String getFieldNameForItemTypeAndName(final Class definedIn, final Class itemType, + final String itemFieldName) { return wrapped.getFieldNameForItemTypeAndName(definedIn, itemType, itemFieldName); } - public Class getItemTypeForItemFieldName(Class definedIn, String itemFieldName) { + @Override + public Class getItemTypeForItemFieldName(final Class definedIn, final String itemFieldName) { return wrapped.getItemTypeForItemFieldName(definedIn, itemFieldName); } - public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(Class itemType, String fieldName) { + @Override + public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(final Class itemType, + final String fieldName) { return wrapped.getImplicitCollectionDefForFieldName(itemType, fieldName); } - public boolean shouldSerializeMember(Class definedIn, String fieldName) { + @Override + public boolean shouldSerializeMember(final Class definedIn, final String fieldName) { return wrapped.shouldSerializeMember(definedIn, fieldName); } - /** - * @deprecated As of 1.1.1, use {@link #defaultImplementationOf(Class)} - */ - public Class lookupDefaultType(Class baseType) { - return defaultImplementationOf(baseType); + @Override + public Converter getLocalConverter(final Class definedIn, final String fieldName) { + return wrapped.getLocalConverter(definedIn, fieldName); } - public String lookupName(Class type) { - return serializedClass(type); + @Override + public T lookupMapperOfType(final Class type) { + @SuppressWarnings("unchecked") + final T t = type.isAssignableFrom(getClass()) ? (T)this : wrapped.lookupMapperOfType(type); + return t; } - public Class lookupType(String elementName) { - return realClass(elementName); + @Override + public SingleValueConverter getConverterFromItemType(final String fieldName, final Class type, + final Class definedIn) { + return wrapped.getConverterFromItemType(fieldName, type, definedIn); } /** - * @deprecated As of 1.1.1, use {@link com.thoughtworks.xstream.mapper.ClassAliasingMapper#addClassAlias(String, Class)} for creating an alias and - * {@link DefaultImplementationsMapper#addDefaultImplementation(Class, Class)} for specifiny a - * default implementation. + * @deprecated As of 1.3.1, use {@link #getConverterFromAttribute(Class, String, Class)} */ - public void alias(String elementName, Class type, Class defaultImplementation) { - ClassAliasingMapper classAliasingMapper = (ClassAliasingMapper) findWrapped(ClassAliasingMapper.class); - if (classAliasingMapper == null) { - throw new UnsupportedOperationException("ClassMapper.alias() longer supported. Use ClassAliasingMapper.alias() instead."); - } else { - classAliasingMapper.addClassAlias(elementName, type); - } - if (defaultImplementation != null && defaultImplementation != type) { - DefaultImplementationsMapper defaultImplementationsMapper = (DefaultImplementationsMapper) findWrapped(DefaultImplementationsMapper.class); - if (defaultImplementationsMapper == null) { - throw new UnsupportedOperationException("ClassMapper.alias() longer supported. Use DefaultImplementatoinsMapper.add() instead."); - } else { - defaultImplementationsMapper.addDefaultImplementation(defaultImplementation, type); - } - } + @Deprecated + @Override + public SingleValueConverter getConverterFromAttribute(final Class type, final String attribute) { + return wrapped.getConverterFromAttribute(type, attribute); } - private ClassMapper findWrapped(Class typeOfMapper) { - ClassMapper current = this; - while (true) { - if (current.getClass().isAssignableFrom(typeOfMapper)) { - return current; - } else if (current instanceof MapperWrapper) { - MapperWrapper wrapper = (MapperWrapper) current; - current = wrapper.wrapped; - } else { - return null; - } - } + @Override + public SingleValueConverter getConverterFromAttribute(final Class definedIn, final String attribute, + final Class type) { + return wrapped.getConverterFromAttribute(definedIn, attribute, type); } + } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/OuterClassMapper.java =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/OuterClassMapper.java (.../OuterClassMapper.java) (revision 4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/OuterClassMapper.java (.../OuterClassMapper.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -1,57 +1,49 @@ +/* + * Copyright (C) 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2014 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 31. January 2005 by Joe Walnes + */ package com.thoughtworks.xstream.mapper; -import com.thoughtworks.xstream.alias.ClassMapper; - /** * Mapper that uses a more meaningful alias for the field in an inner class (this$0) that refers to the outer class. - * + * * @author Joe Walnes */ public class OuterClassMapper extends MapperWrapper { private final String alias; - public OuterClassMapper(ClassMapper wrapped, String alias) { + public OuterClassMapper(final Mapper wrapped) { + this(wrapped, "outer-class"); + } + + public OuterClassMapper(final Mapper wrapped, final String alias) { super(wrapped); this.alias = alias; } - public OuterClassMapper(ClassMapper wrapped) { - this(wrapped, "outer-class"); - } - - public String serializedMember(Class type, String memberName) { + @Override + public String serializedMember(final Class type, final String memberName) { if (memberName.equals("this$0")) { return alias; } else { return super.serializedMember(type, memberName); } } - public String realMember(Class type, String serialized) { + @Override + public String realMember(final Class type, final String serialized) { if (serialized.equals(alias)) { return "this$0"; } else { return super.realMember(type, serialized); } } - - // --- Maintain backwards compatability - - public String mapNameToXML(String javaName) { - if (javaName.equals("this$0")) { - return alias; - } else { - return super.mapNameToXML(javaName); - } - } - - public String mapNameFromXML(String xmlName) { - if (xmlName.equals(alias)) { - return "this$0"; - } else { - return super.mapNameFromXML(xmlName); - } - } - } Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/PackageAliasingMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/PackageAliasingMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/PackageAliasingMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008, 2014 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 10. November 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.mapper; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + + +/** + * Mapper that allows a package name to be replaced with an alias. + * + * @author Jörg Schaible + */ +public class PackageAliasingMapper extends MapperWrapper implements Serializable { + + private static final Comparator REVERSE = new Comparator() { + + @Override + public int compare(final String o1, final String o2) { + return o2.compareTo(o1); + } + }; + + private Map packageToName = new TreeMap(REVERSE); + protected transient Map nameToPackage = new HashMap(); + + public PackageAliasingMapper(final Mapper wrapped) { + super(wrapped); + } + + public void addPackageAlias(String name, String pkg) { + if (name.length() > 0 && name.charAt(name.length() - 1) != '.') { + name += '.'; + } + if (pkg.length() > 0 && pkg.charAt(pkg.length() - 1) != '.') { + pkg += '.'; + } + nameToPackage.put(name, pkg); + packageToName.put(pkg, name); + } + + @Override + public String serializedClass(final Class type) { + final String className = type.getName(); + int length = className.length(); + int dot = -1; + do { + dot = className.lastIndexOf('.', length); + final String pkg = dot < 0 ? "" : className.substring(0, dot + 1); + final String alias = packageToName.get(pkg); + if (alias != null) { + return alias + (dot < 0 ? className : className.substring(dot + 1)); + } + length = dot - 1; + } while (dot >= 0); + return super.serializedClass(type); + } + + @Override + public Class realClass(String elementName) { + int length = elementName.length(); + int dot = -1; + do { + dot = elementName.lastIndexOf('.', length); + final String name = dot < 0 ? "" : elementName.substring(0, dot) + '.'; + final String packageName = nameToPackage.get(name); + + if (packageName != null) { + elementName = packageName + (dot < 0 ? elementName : elementName.substring(dot + 1)); + break; + } + length = dot - 1; + } while (dot >= 0); + + return super.realClass(elementName); + } + + private void writeObject(final ObjectOutputStream out) throws IOException { + out.writeObject(new HashMap(packageToName)); + } + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + packageToName = new TreeMap(REVERSE); + @SuppressWarnings("unchecked") + final Map map = (Map)in.readObject(); + packageToName.putAll(map); + nameToPackage = new HashMap(); + for (final Map.Entry entry : packageToName.entrySet()) { + nameToPackage.put(entry.getValue(), entry.getKey()); + } + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/SecurityMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/SecurityMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/SecurityMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 08. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.mapper; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.thoughtworks.xstream.security.AnyTypePermission; +import com.thoughtworks.xstream.security.ForbiddenClassException; +import com.thoughtworks.xstream.security.NoTypePermission; +import com.thoughtworks.xstream.security.TypePermission; + + +/** + * A Mapper implementation injecting a security layer based on permission rules for any type required in the + * unmarshalling process. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class SecurityMapper extends MapperWrapper { + + private final List permissions; + + /** + * Construct a SecurityMapper. + * + * @param wrapped the mapper chain + * @since 1.4.7 + */ + public SecurityMapper(final Mapper wrapped) { + this(wrapped, (TypePermission[])null); + } + + /** + * Construct a SecurityMapper. + * + * @param wrapped the mapper chain + * @param permissions the predefined permissions + * @since 1.4.7 + */ + public SecurityMapper(final Mapper wrapped, final TypePermission... permissions) { + super(wrapped); + this.permissions = permissions == null // + ? new ArrayList() + : new ArrayList(Arrays.asList(permissions)); + } + + /** + * Add a new permission. + *

    + * Permissions are evaluated in the added sequence. An instance of {@link NoTypePermission} or + * {@link AnyTypePermission} will implicitly wipe any existing permission. + *

    + * + * @param permission the permission to add. + * @since 1.4.7 + */ + public void addPermission(final TypePermission permission) { + if (permission.equals(NoTypePermission.NONE) || permission.equals(AnyTypePermission.ANY)) { + permissions.clear(); + } + permissions.add(0, permission); + } + + @Override + public Class realClass(final String elementName) { + final Class type = super.realClass(elementName); + for (final TypePermission permission : permissions) { + if (permission.allows(type)) { + return type; + } + } + throw new ForbiddenClassException(type); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/SystemAttributeAliasingMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/SystemAttributeAliasingMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/SystemAttributeAliasingMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008, 2014 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 09. October 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.mapper; + +/** + * Mapper that allows aliasing of system attribute names. + * + * @author Jörg Schaible + * @since 1.3.1 + */ +public class SystemAttributeAliasingMapper extends AbstractAttributeAliasingMapper { + + public SystemAttributeAliasingMapper(final Mapper wrapped) { + super(wrapped); + } + + @Override + public String aliasForSystemAttribute(final String attribute) { + String alias = nameToAlias.get(attribute); + if (alias == null && !nameToAlias.containsKey(attribute)) { + alias = super.aliasForSystemAttribute(attribute); + if (alias == attribute) { + alias = super.aliasForAttribute(attribute); + } + } + return alias; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/XStream11XmlFriendlyMapper.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/XStream11XmlFriendlyMapper.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/XStream11XmlFriendlyMapper.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2006, 2007, 2009, 2011, 2014 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 03. May 2006 by Mauro Talevi + */ +package com.thoughtworks.xstream.mapper; + +/** + * Mapper that ensures that all names in the serialization stream are read in an XML friendly way. + *
      + *
    • _ (underscore) chars appearing in class names are replaced with $ (dollar)
    • + *
    • _DOLLAR_ string appearing in field names are replaced with $ (dollar)
    • + *
    • __ string appearing in field names are replaced with _ (underscore)
    • + *
    • default is the prefix for class names with no package.
    • + *
    + * Note, this class is no longer in regular use for current XStream versions. It exists to provide backward + * compatibility to existing XML data written with older XStream versions (<= 1.1). + * + * @author Joe Walnes + * @author Mauro Talevi + * @deprecated As of 1.4 use {@link com.thoughtworks.xstream.io.xml.XmlFriendlyReader} + */ +@Deprecated +public class XStream11XmlFriendlyMapper extends AbstractXmlFriendlyMapper { + + public XStream11XmlFriendlyMapper(final Mapper wrapped) { + super(wrapped); + } + + @Override + public Class realClass(final String elementName) { + return super.realClass(unescapeClassName(elementName)); + } + + @Override + public String realMember(final Class type, final String serialized) { + return unescapeFieldName(super.realMember(type, serialized)); + } + + public String mapNameFromXML(final String xmlName) { + return unescapeFieldName(xmlName); + } +} Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `3rdParty_sources/xstream/com/thoughtworks/xstream/mapper/XmlFriendlyMapper.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/AbstractFilePersistenceStrategy.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/AbstractFilePersistenceStrategy.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/AbstractFilePersistenceStrategy.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2008, 2014 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 18. November 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.persistence; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.Iterator; +import java.util.Map; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Abstract base class for file based persistence strategies. + * + * @author Guilherme Silveira + * @author Joerg Schaible + * @since 1.3.1 + */ +public abstract class AbstractFilePersistenceStrategy implements PersistenceStrategy { + + private final FilenameFilter filter; + private final File baseDirectory; + private final String encoding; + private final transient XStream xstream; + + public AbstractFilePersistenceStrategy(final File baseDirectory, final XStream xstream, final String encoding) { + this.baseDirectory = baseDirectory; + this.xstream = xstream; + this.encoding = encoding; + filter = new ValidFilenameFilter(); + } + + protected ConverterLookup getConverterLookup() { + return xstream.getConverterLookup(); + } + + protected Mapper getMapper() { + return xstream.getMapper(); + } + + protected boolean isValid(final File dir, final String name) { + return name.endsWith(".xml"); + } + + /** + * Given a filename, the unescape method returns the key which originated it. + * + * @param name the filename + * @return the original key + */ + protected abstract K extractKey(String name); + + /** + * Given a key, the escape method returns the filename which shall be used. + * + * @param key the key + * @return the desired and escaped filename + */ + protected abstract String getName(Object key); + + protected class ValidFilenameFilter implements FilenameFilter { + @Override + public boolean accept(final File dir, final String name) { + return new File(dir, name).isFile() && isValid(dir, name); + } + } + + protected class XmlMapEntriesIterator implements Iterator> { + + private final File[] files = baseDirectory.listFiles(filter); + + private int position = -1; + + private File current = null; + + @Override + public boolean hasNext() { + return position + 1 < files.length; + } + + @Override + public void remove() { + if (current == null) { + throw new IllegalStateException(); + } + // removes without loading + current.delete(); + } + + @Override + public Map.Entry next() { + return new Map.Entry() { + private final File file = current = files[++position]; + private final K key = extractKey(file.getName()); + + @Override + public K getKey() { + return key; + } + + @Override + public V getValue() { + return readFile(file); + } + + @Override + public V setValue(final V value) { + return put(key, value); + } + + @Override + public int hashCode() { + final V value = getValue(); + return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof Map.Entry)) { + return false; + } + @SuppressWarnings("unchecked") + final Map.Entry e2 = (Map.Entry)obj; + final K key2 = e2.getKey(); + if (key == null ? key2 == null : key.equals(key2)) { + final V value = getValue(); + final V value2 = e2.getValue(); + return value == null ? value2 == null : value.equals(value2); + } + return false; + } + }; + } + } + + @SuppressWarnings("resource") + private void writeFile(final File file, final Object value) { + try { + final FileOutputStream out = new FileOutputStream(file); + final Writer writer = encoding != null + ? new OutputStreamWriter(out, encoding) + : new OutputStreamWriter(out); + try { + xstream.toXML(value, writer); + } finally { + writer.close(); + } + } catch (final IOException e) { + throw new StreamException(e); + } + } + + private File getFile(final String filename) { + return new File(baseDirectory, filename); + } + + @SuppressWarnings("resource") + private V readFile(final File file) { + try { + final FileInputStream in = new FileInputStream(file); + final Reader reader = encoding != null ? new InputStreamReader(in, encoding) : new InputStreamReader(in); + try { + @SuppressWarnings("unchecked") + final V value = (V)xstream.fromXML(reader); + return value; + } finally { + reader.close(); + } + } catch (final FileNotFoundException e) { + // not found... file.exists might generate a sync problem + return null; + } catch (final IOException e) { + throw new StreamException(e); + } + } + + @Override + public V put(final K key, final V value) { + final V oldValue = get(key); + final String filename = getName(key); + writeFile(new File(baseDirectory, filename), value); + return oldValue; + } + + @Override + public Iterator> iterator() { + return new XmlMapEntriesIterator(); + } + + @Override + public int size() { + return baseDirectory.list(filter).length; + } + + public boolean containsKey(final K key) { + // faster lookup + final File file = getFile(getName(key)); + return file.isFile(); + } + + @Override + public V get(final Object key) { + return readFile(getFile(getName(key))); + } + + @Override + public V remove(final Object key) { + // faster lookup + final File file = getFile(getName(key)); + V value = null; + if (file.isFile()) { + value = readFile(file); + file.delete(); + } + return value; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/FilePersistenceStrategy.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/FilePersistenceStrategy.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/FilePersistenceStrategy.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2008, 2014 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 20. November 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.persistence; + +import java.io.File; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.SingleValueConverter; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.io.xml.DomDriver; + + +/** + * PersistenceStrategy to assign keys with single value to objects persisted in files. + *

    + * The default naming strategy is based on the key's type and its {@link SingleValueConverter}. It escapes all + * characters that are normally illegal in the most common file systems. Such a character is escaped with percent + * escaping as it is done by URL encoding. The XStream used to marshal the values is also requested for the key's + * SingleValueConverter. A {@link StreamException} is thrown if no such converter is registered. + *

    + * + * @author Jörg Schaible + * @author Guilherme Silveira + * @since 1.3.1 + */ +public class FilePersistenceStrategy extends AbstractFilePersistenceStrategy { + + private final String illegalChars; + + /** + * Create a new FilePersistenceStrategy. Use a standard XStream instance with a {@link DomDriver}. + * + * @param baseDirectory the directory for the serialized values + * @since 1.3.1 + */ + public FilePersistenceStrategy(final File baseDirectory) { + this(baseDirectory, new XStream(new DomDriver())); + } + + /** + * Create a new FilePersistenceStrategy with a provided XStream instance. + * + * @param baseDirectory the directory for the serialized values + * @param xstream the XStream instance to use for (de)serialization + * @since 1.3.1 + */ + public FilePersistenceStrategy(final File baseDirectory, final XStream xstream) { + this(baseDirectory, xstream, "utf-8", "<>?:/\\\"|*%"); + } + + /** + * Create a new FilePersistenceStrategy with a provided XStream instance and the characters to encode. + * + * @param baseDirectory the directory for the serialized values + * @param xstream the XStream instance to use for (de)serialization + * @param encoding encoding used to write the files + * @param illegalChars illegal characters for file names (should always include '%' as long as you do not overwrite + * the (un)escape methods) + * @since 1.3.1 + */ + public FilePersistenceStrategy( + final File baseDirectory, final XStream xstream, final String encoding, final String illegalChars) { + super(baseDirectory, xstream, encoding); + this.illegalChars = illegalChars; + } + + @Override + protected boolean isValid(final File dir, final String name) { + return super.isValid(dir, name) && name.indexOf('@') > 0; + } + + /** + * Given a filename, the unescape method returns the key which originated it. + * + * @param name the filename + * @return the original key + */ + @Override + protected K extractKey(final String name) { + final String key = unescape(name.substring(0, name.length() - 4)); + if ("null@null".equals(key)) { + return null; + } + final int idx = key.indexOf('@'); + if (idx < 0) { + throw new StreamException("Not a valid key: " + key); + } + final Class type = getMapper().realClass(key.substring(0, idx)); + final Converter converter = getConverterLookup().lookupConverterForType(type); + if (converter instanceof SingleValueConverter) { + final SingleValueConverter svConverter = (SingleValueConverter)converter; + @SuppressWarnings("unchecked") + final K k = (K)svConverter.fromString(key.substring(idx + 1)); + return k; + } else { + throw new StreamException("No SingleValueConverter for type " + type.getName() + " available"); + } + } + + protected String unescape(String name) { + final StringBuilder buffer = new StringBuilder(); + for (int idx = name.indexOf('%'); idx >= 0; idx = name.indexOf('%')) { + buffer.append(name.substring(0, idx)); + final int c = Integer.parseInt(name.substring(idx + 1, idx + 3), 16); + buffer.append((char)c); + name = name.substring(idx + 3); + } + buffer.append(name); + return buffer.toString(); + } + + /** + * Given a key, the escape method returns the filename which shall be used. + * + * @param key the key + * @return the desired and escaped filename + */ + @Override + protected String getName(final Object key) { + if (key == null) { + return "null@null.xml"; + } + final Class type = key.getClass(); + final Converter converter = getConverterLookup().lookupConverterForType(type); + if (converter instanceof SingleValueConverter) { + final SingleValueConverter svConverter = (SingleValueConverter)converter; + return getMapper().serializedClass(type) + '@' + escape(svConverter.toString(key)) + ".xml"; + } else { + throw new StreamException("No SingleValueConverter for type " + type.getName() + " available"); + } + } + + protected String escape(final String key) { + final StringBuilder buffer = new StringBuilder(); + final char[] array = key.toCharArray(); + for (final char c : array) { + if (c >= ' ' && illegalChars.indexOf(c) < 0) { + buffer.append(c); + } else { + buffer.append("%" + Integer.toHexString(c).toUpperCase()); + } + } + return buffer.toString(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/FileStreamStrategy.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/FileStreamStrategy.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/FileStreamStrategy.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2007, 2008, 2009, 2014 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 13. June 2006 by Guilherme Silveira + */ +package com.thoughtworks.xstream.persistence; + +import java.io.File; + +import com.thoughtworks.xstream.XStream; + + +/** + * PersistenceStrategy to assign string based keys to objects persisted in files. + *

    + * The file naming strategy is based on the key's type name and its toString method. It escapes non digit, non a-z and + * A-Z characters. In order to change the escaping/unescaping algorithm, simply extend this class and rewrite its + * getName/extractKey methods. Note, this implementation silently implies that the keys actually are Strings, since the + * keys will be turned into string keys at deserialization time. + *

    + * + * @author Guilherme Silveira + * @deprecated As of 1.3.1, use FilePersistenceStrategy + */ +@Deprecated +public class FileStreamStrategy extends AbstractFilePersistenceStrategy implements + StreamStrategy { + public FileStreamStrategy(final File baseDirectory) { + this(baseDirectory, new XStream()); + } + + public FileStreamStrategy(final File baseDirectory, final XStream xstream) { + super(baseDirectory, xstream, null); + } + + /** + * Given a filename, the unescape method returns the key which originated it. + * + * @param name the filename + * @return the original key + */ + @Override + protected String extractKey(final String name) { + final String key = unescape(name.substring(0, name.length() - 4)); + return key.equals("\0") ? null : key; + } + + protected String unescape(final String name) { + final StringBuilder buffer = new StringBuilder(); + char lastC = '\uffff'; + int currentValue = -1; + // do we have a regex master to do it? + final char[] array = name.toCharArray(); + for (final char c : array) { + if (c == '_' && currentValue != -1) { + if (lastC == '_') { + buffer.append('_'); + } else { + buffer.append((char)currentValue); + } + currentValue = -1; + } else if (c == '_') { + currentValue = 0; + } else if (currentValue != -1) { + currentValue = currentValue * 16 + Integer.parseInt(String.valueOf(c), 16); + } else { + buffer.append(c); + } + lastC = c; + } + return buffer.toString(); + } + + /** + * Given a key, the escape method returns the filename which shall be used. + * + * @param key the key + * @return the desired and escaped filename + */ + @Override + protected String getName(final Object key) { + return escape(key == null ? "\0" : key.toString()) + ".xml"; + } + + protected String escape(final String key) { + final StringBuilder buffer = new StringBuilder(); + final char[] array = key.toCharArray(); + for (final char c : array) { + if (Character.isDigit(c) || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') { + buffer.append(c); + } else if (c == '_') { + buffer.append("__"); + } else { + buffer.append("_" + Integer.toHexString(c) + "_"); + } + } + return buffer.toString(); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/PersistenceStrategy.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/PersistenceStrategy.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/PersistenceStrategy.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008, 2014 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 20. November 2008 by Joerg Schaible + */ +package com.thoughtworks.xstream.persistence; + +import java.util.Iterator; +import java.util.Map; + + +/** + * A key to a persistent storage and vice-versa strategy interface. + * + * @author Guilherme Silveira + * @since 1.3.1 + */ +public interface PersistenceStrategy { + + Iterator> iterator(); + + int size(); + + V get(Object key); + + V put(K key, V value); + + V remove(Object key); + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/StreamStrategy.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/StreamStrategy.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/StreamStrategy.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2007, 2008, 2009, 2014 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 13. June 2006 by Guilherme Silveira + */ +package com.thoughtworks.xstream.persistence; + +/** + * A key to filename and vice-versa strategy interface. + * + * @author Guilherme Silveira + * @deprecated As of 1.3.1, use {@link PersistenceStrategy} instead + */ +@Deprecated +public interface StreamStrategy extends PersistenceStrategy {} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/XmlArrayList.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/XmlArrayList.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/XmlArrayList.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2007, 2008, 2014 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 06. July 2006 by Guilherme Silveira + */ +package com.thoughtworks.xstream.persistence; + +import java.util.AbstractList; + + +/** + * A persistent list implementation backed on a XmlMap. + * + * @author Guilherme Silveira + */ +public class XmlArrayList extends AbstractList { + + private final XmlMap map; + + public XmlArrayList(final PersistenceStrategy persistenceStrategy) { + this.map = new XmlMap(persistenceStrategy); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public V set(final int index, final V element) { + rangeCheck(index); + final V value = get(index); + map.put(Integer.valueOf(index), element); + return value; + } + + @Override + public void add(final int index, final V element) { + final int size = size(); + if (index >= size + 1 || index < 0) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + final int to = index != size ? index - 1 : index; + for (int i = size; i > to; i--) { + map.put(Integer.valueOf(i + 1), map.get(Integer.valueOf(i))); + } + map.put(new Integer(index), element); + } + + private void rangeCheck(final int index) { + final int size = size(); + if (index >= size || index < 0) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + } + + @Override + public V get(final int index) { + rangeCheck(index); + return map.get(Integer.valueOf(index)); + } + + @Override + public V remove(final int index) { + final int size = size(); + rangeCheck(index); + final V value = map.get(Integer.valueOf(index)); + for (int i = index; i < size - 1; i++) { + map.put(Integer.valueOf(i), map.get(Integer.valueOf(i + 1))); + } + map.remove(Integer.valueOf(size - 1)); + return value; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/XmlMap.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/XmlMap.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/XmlMap.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2007, 2008, 2014 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 13. June 2006 by Guilherme Silveira + */ +package com.thoughtworks.xstream.persistence; + +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + + +/** + * A persistent map. Its values are actually serialized as xml files. + *

    + * If you need an application-wide synchronized version of this map, try the respective Collections methods. + *

    + * + * @author Guilherme Silveira + */ +public class XmlMap extends AbstractMap { + + private final PersistenceStrategy persistenceStrategy; + + public XmlMap(final PersistenceStrategy streamStrategy) { + this.persistenceStrategy = streamStrategy; + } + + @Override + public int size() { + return persistenceStrategy.size(); + } + + @Override + public V get(final Object key) { + // faster lookup + return persistenceStrategy.get(key); + } + + @Override + public V put(final K key, final V value) { + return persistenceStrategy.put(key, value); + } + + @Override + public V remove(final Object key) { + return persistenceStrategy.remove(key); + } + + @Override + public Set> entrySet() { + return new XmlMapEntries(); + } + + class XmlMapEntries extends AbstractSet> { + + @Override + public int size() { + return XmlMap.this.size(); + } + + @Override + public boolean isEmpty() { + return XmlMap.this.isEmpty(); + } + + @Override + public Iterator> iterator() { + return persistenceStrategy.iterator(); + } + + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/XmlSet.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/XmlSet.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/persistence/XmlSet.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006 Joe Walnes. + * Copyright (C) 2007, 2008, 2014 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 28. June 2006 by Guilherme Silveira + */ +package com.thoughtworks.xstream.persistence; + +import java.util.AbstractSet; +import java.util.Iterator; + + +/** + * A persistent set implementation. + * + * @author Guilherme Silveira + */ +public class XmlSet extends AbstractSet { + + private final XmlMap map; + + public XmlSet(final PersistenceStrategy persistenceStrategy) { + this.map = new XmlMap(persistenceStrategy); + } + + @Override + public Iterator iterator() { + return map.values().iterator(); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean add(final V o) { + if (map.containsValue(o)) { + return false; + } else { + // not-synchronized! + map.put(findEmptyKey(), o); + return true; + } + } + + private Long findEmptyKey() { + long i = System.currentTimeMillis(); + while (map.containsKey(Long.valueOf(i))) { + i++; + } + return Long.valueOf(i); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/AnyTypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/AnyTypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/AnyTypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 08. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +/** + * Permission for any type and null. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class AnyTypePermission implements TypePermission { + /** + * @since 1.4.7 + */ + public static final TypePermission ANY = new AnyTypePermission(); + + @Override + public boolean allows(Class type) { + return true; + } + + @Override + public int hashCode() { + return 3; + } + + @Override + public boolean equals(Object obj) { + return obj != null && obj.getClass() == AnyTypePermission.class; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ArrayTypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ArrayTypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ArrayTypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 09. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +/** + * Permission for any array type. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class ArrayTypePermission implements TypePermission { + /** + * @since 1.4.7 + */ + public static final TypePermission ARRAYS = new ArrayTypePermission(); + + @Override + public boolean allows(Class type) { + return type != null && type.isArray(); + } + + @Override + public int hashCode() { + return 13; + } + + @Override + public boolean equals(Object obj) { + return obj != null && obj.getClass() == ArrayTypePermission.class; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/CGLIBProxyTypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/CGLIBProxyTypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/CGLIBProxyTypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 19. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +import net.sf.cglib.proxy.Proxy; + + +/** + * Permission for any array type. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class CGLIBProxyTypePermission implements TypePermission { + /** + * @since 1.4.7 + */ + public static final TypePermission PROXIES = new CGLIBProxyTypePermission(); + + @Override + public boolean allows(final Class type) { + return type != null && type != Object.class && !type.isInterface() + && (Proxy.isProxyClass(type) || type.getName().startsWith(Proxy.class.getPackage().getName() + ".")); + } + + @Override + public int hashCode() { + return 19; + } + + @Override + public boolean equals(final Object obj) { + return obj != null && obj.getClass() == CGLIBProxyTypePermission.class; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ExplicitTypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ExplicitTypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ExplicitTypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 09. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + + +/** + * Explicit permission for a type with a name matching one in the provided list. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class ExplicitTypePermission implements TypePermission { + + final Set names; + + /** + * @since 1.4.7 + */ + public ExplicitTypePermission(final Class... types) { + this(new Object() { + public String[] getNames() { + if (types == null) + return null; + String[] names = new String[types.length]; + for (int i = 0; i < types.length; ++i) + names[i] = types[i].getName(); + return names; + } + }.getNames()); + } + + /** + * @since 1.4.7 + */ + public ExplicitTypePermission(String... names) { + this.names = names == null ? Collections.emptySet() : new HashSet(Arrays.asList(names)); + } + + @Override + public boolean allows(Class type) { + if (type == null) + return false; + return names.contains(type.getName()); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ForbiddenClassException.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ForbiddenClassException.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ForbiddenClassException.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 08. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +import com.thoughtworks.xstream.XStreamException; + +/** + * Exception thrown for a forbidden class. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class ForbiddenClassException extends XStreamException { + + /** + * Construct a ForbiddenClassException. + * @param type the forbidden class + * @since 1.4.7 + */ + public ForbiddenClassException(Class type) { + super(type == null ? "null" : type.getName()); + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/InterfaceTypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/InterfaceTypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/InterfaceTypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 27. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +/** + * Permission for any interface type. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class InterfaceTypePermission implements TypePermission { + /** + * @since 1.4.7 + */ + public static final TypePermission INTERFACES = new InterfaceTypePermission(); + + @Override + public boolean allows(Class type) { + return type != null && type.isInterface(); + } + + @Override + public int hashCode() { + return 31; + } + + @Override + public boolean equals(Object obj) { + return obj != null && obj.getClass() == InterfaceTypePermission.class; + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/NoPermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/NoPermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/NoPermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 09. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +/** + * Wrapper to negate another type permission. + *

    + * If the wrapped {@link TypePermission} allows the type, this instance will throw a {@link ForbiddenClassException} + * instead. An instance of this permission cannot be used to allow a type. + *

    + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class NoPermission implements TypePermission { + + private final TypePermission permission; + + /** + * Construct a NoPermission. + * + * @param permission the permission to negate or null to forbid any type + * @since 1.4.7 + */ + public NoPermission(final TypePermission permission) { + this.permission = permission; + } + + @Override + public boolean allows(final Class type) { + if (permission == null || permission.allows(type)) { + throw new ForbiddenClassException(type); + } + return false; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/NoTypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/NoTypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/NoTypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 08. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +/** + * No permission for any type. + *

    + * Can be used to skip any existing default permission. + *

    + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class NoTypePermission implements TypePermission { + + /** + * @since 1.4.7 + */ + public static final TypePermission NONE = new NoTypePermission(); + + @Override + public boolean allows(Class type) { + throw new ForbiddenClassException(type); + } + + @Override + public int hashCode() { + return 1; + } + + @Override + public boolean equals(Object obj) { + return obj != null && obj.getClass() == NoTypePermission.class; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/NullPermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/NullPermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/NullPermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 09. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +import com.thoughtworks.xstream.mapper.Mapper; + +/** + * Permission for null or XStream's null replacement type. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class NullPermission implements TypePermission { + /** + * @since 1.4.7 + */ + public static final TypePermission NULL = new NullPermission(); + + @Override + public boolean allows(Class type) { + return type == null || type == Mapper.Null.class; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/PrimitiveTypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/PrimitiveTypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/PrimitiveTypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 09. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +import com.thoughtworks.xstream.core.util.Primitives; + +/** + * Permission for any primitive type and its boxed counterpart (incl. void). + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class PrimitiveTypePermission implements TypePermission { + /** + * @since 1.4.7 + */ + public static final TypePermission PRIMITIVES = new PrimitiveTypePermission(); + + @Override + public boolean allows(Class type) { + return type != null && type.isPrimitive() || Primitives.isBoxed(type); + } + + @Override + public int hashCode() { + return 7; + } + + @Override + public boolean equals(Object obj) { + return obj != null && obj.getClass() == PrimitiveTypePermission.class; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ProxyTypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ProxyTypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/ProxyTypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 19. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +import java.lang.reflect.Proxy; + +import com.thoughtworks.xstream.mapper.DynamicProxyMapper; + + +/** + * Permission for any array type. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class ProxyTypePermission implements TypePermission { + /** + * @since 1.4.7 + */ + public static final TypePermission PROXIES = new ProxyTypePermission(); + + @Override + public boolean allows(final Class type) { + return type != null && (Proxy.isProxyClass(type) || type == DynamicProxyMapper.DynamicProxy.class); + } + + @Override + public int hashCode() { + return 17; + } + + @Override + public boolean equals(final Object obj) { + return obj != null && obj.getClass() == ProxyTypePermission.class; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/RegExpTypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/RegExpTypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/RegExpTypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 09. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +import java.util.regex.Pattern; + + +/** + * Permission for any type with a name matching one of the provided regular expressions. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class RegExpTypePermission implements TypePermission { + + private final Pattern[] patterns; + + public RegExpTypePermission(final String... patterns) { + this(getPatterns(patterns)); + } + + public RegExpTypePermission(final Pattern... patterns) { + this.patterns = patterns == null ? new Pattern[0] : patterns; + } + + @Override + public boolean allows(final Class type) { + if (type != null) { + final String name = type.getName(); + for (final Pattern pattern : patterns) + if (pattern.matcher(name).matches()) + return true; + } + return false; + } + + private static Pattern[] getPatterns(final String... patterns) { + if (patterns == null) + return null; + final Pattern[] array = new Pattern[patterns.length]; + for (int i = 0; i < array.length; ++i) + array[i] = Pattern.compile(patterns[i]); + return array; + } +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/TypeHierarchyPermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/TypeHierarchyPermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/TypeHierarchyPermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 23. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +/** + * Permission for a type hierarchy with a name matching one in the provided list. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class TypeHierarchyPermission implements TypePermission { + + private Class type; + + /** + * @since 1.4.7 + */ + public TypeHierarchyPermission(Class type) { + this.type = type; + } + + @Override + public boolean allows(Class type) { + if (type == null) + return false; + return this.type.isAssignableFrom(type); + } + +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/TypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/TypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/TypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 08. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +/** + * Definition of a type permission. + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public interface TypePermission { + /** + * Check permission for a provided type. + * + * @param type the type to check + * @return true if provided type is allowed, false if permission does not handle the type + * @throws ForbiddenClassException if provided type is explicitly forbidden + * @since 1.4.7 + */ + boolean allows(Class type); +} Index: 3rdParty_sources/xstream/com/thoughtworks/xstream/security/WildcardTypePermission.java =================================================================== diff -u --- 3rdParty_sources/xstream/com/thoughtworks/xstream/security/WildcardTypePermission.java (revision 0) +++ 3rdParty_sources/xstream/com/thoughtworks/xstream/security/WildcardTypePermission.java (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 09. January 2014 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +/** + * Permission for any type with a name matching one of the provided wildcard expressions. + * + *

    + * Supported are patterns with path expressions using dot as separator: + *

    + *
      + *
    • ?: one non-control character except separator, e.g. for 'java.net.Inet?Address'
    • + *
    • *: arbitrary number of non-control characters except separator, e.g. for types in a package like 'java.lang.*'
    • + *
    • **: arbitrary number of non-control characters including separator, e.g. for types in a package and subpackages like 'java.lang.**'
    • + *
    + *

    + * The complete range of UTF-8 characters is supported except control characters. + *

    + * + * @author Jörg Schaible + * @since 1.4.7 + */ +public class WildcardTypePermission extends RegExpTypePermission { + + /** + * @since 1.4.7 + */ + public WildcardTypePermission(final String... patterns) { + super(getRegExpPatterns(patterns)); + } + + private static String[] getRegExpPatterns(final String... wildcards) { + if (wildcards == null) + return null; + final String[] regexps = new String[wildcards.length]; + for (int i = 0; i < wildcards.length; ++i) { + final String wildcardExpression = wildcards[i]; + final StringBuilder result = new StringBuilder(wildcardExpression.length() * 2); + result.append("(?u)"); + final int length = wildcardExpression.length(); + for (int j = 0; j < length; j++) { + final char ch = wildcardExpression.charAt(j); + switch (ch) { + case '\\': + case '.': + case '+': + case '|': + case '[': + case ']': + case '(': + case ')': + case '^': + case '$': + result.append('\\').append(ch); + break; + + case '?': + result.append('.'); + break; + + case '*': + // see "General Category Property" in http://www.unicode.org/reports/tr18/ + if (j + 1 < length && wildcardExpression.charAt(j + 1) == '*') { + result.append("[\\P{C}]*"); + j++; + } else { + result.append("[\\P{C}&&[^").append('.').append("]]*"); + } + break; + + default: + result.append(ch); + break; + } + } + regexps[i] = result.toString(); + } + return regexps; + } +} Index: lams_build/3rdParty.userlibraries =================================================================== diff -u -re604030b7b751a1ead9cfd3e01e4e48c42a8ab19 -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- lams_build/3rdParty.userlibraries (.../3rdParty.userlibraries) (revision e604030b7b751a1ead9cfd3e01e4e48c42a8ab19) +++ lams_build/3rdParty.userlibraries (.../3rdParty.userlibraries) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -23,14 +23,11 @@ - - - @@ -44,5 +41,7 @@ + + Index: lams_build/build.xml =================================================================== diff -u -r5e14c9f717ba4fc837df61e34ae22bbf606ad60c -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- lams_build/build.xml (.../build.xml) (revision 5e14c9f717ba4fc837df61e34ae22bbf606ad60c) +++ lams_build/build.xml (.../build.xml) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -711,19 +711,20 @@ - + + - + file="lib/xstream/xmlpull.module.xml" overwrite="true" verbose="true" /> + - + + file="lib/joda/joda.module.xml" overwrite="true" verbose="true" /> Index: lams_build/conf/j2ee/jboss-deployment-structure.xml =================================================================== diff -u -rf3fbbb8ec1732de7e5ce51567287b42b55ab33e1 -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- lams_build/conf/j2ee/jboss-deployment-structure.xml (.../jboss-deployment-structure.xml) (revision f3fbbb8ec1732de7e5ce51567287b42b55ab33e1) +++ lams_build/conf/j2ee/jboss-deployment-structure.xml (.../jboss-deployment-structure.xml) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -35,6 +35,7 @@ + @@ -52,6 +53,7 @@ + + + + + + + Index: lams_build/lib/xstream/joda-time-2.1.jar =================================================================== diff -u -r4c92d2863f0a9de8d8135bd2f7347375bb1d4b4d -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 Binary files differ Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `lams_build/lib/xstream/joda.module.xml'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_build/lib/xstream/xmlpull-1.1.3.1.jar =================================================================== diff -u Binary files differ Index: lams_build/lib/xstream/xmlpull.module.xml =================================================================== diff -u --- lams_build/lib/xstream/xmlpull.module.xml (revision 0) +++ lams_build/lib/xstream/xmlpull.module.xml (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `lams_build/lib/xstream/xpp.module.xml'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_build/lib/xstream/xpp3-1.1.3.4d_b4_min.jar =================================================================== diff -u -r3c4881947fb505c405de8165f49ebce7c3c674ac -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 Binary files differ Fisheye: Tag c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 refers to a dead (removed) revision in file `lams_build/lib/xstream/xpp3-license.txt'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_build/lib/xstream/xpp3_min-1.1.4c.jar =================================================================== diff -u Binary files differ Index: lams_build/lib/xstream/xstream-1.1.3.jar =================================================================== diff -u -re2e2aa63f31be07287637a2bec159d1574c0ba2c -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 Binary files differ Index: lams_build/lib/xstream/xstream-1.5.0-SNAPSHOT.jar =================================================================== diff -u Binary files differ Index: lams_build/lib/xstream/xstream.module.xml =================================================================== diff -u -r59dec34e8cbb27c683d552094086fa33faa70ff1 -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- lams_build/lib/xstream/xstream.module.xml (.../xstream.module.xml) (revision 59dec34e8cbb27c683d552094086fa33faa70ff1) +++ lams_build/lib/xstream/xstream.module.xml (.../xstream.module.xml) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -24,11 +24,9 @@ - + - - - + \ No newline at end of file Index: lams_build/liblist.txt =================================================================== diff -u -re604030b7b751a1ead9cfd3e01e4e48c42a8ab19 -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- lams_build/liblist.txt (.../liblist.txt) (revision e604030b7b751a1ead9cfd3e01e4e48c42a8ab19) +++ lams_build/liblist.txt (.../liblist.txt) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -35,6 +35,8 @@ jdom jdom.jar 0.7 BSD/Apache style Jason Hunter, Rolf Lear Java representation of an XML document +joda joda-time-2.1.jar 2.1 Apache License 2.0 Joda.org time calculation library + joid joid.jar 2.0 Apache License 2.0 Java Open ID library @@ -74,12 +76,11 @@ xml-commons xml-apis.jar 1.3 xml-apis-ext.jar 1.3 Apache License 2.0 Apache Common code and guidelines for xml projects -xstream joda-time-2.1.jar 2.1 Apache License 2.0 Joda.org Joda Time - xpp3-1.1.3.4d_b4_min.jar 1.1.3.4d_b4_min - xstream-1.1.3.jar 1.1.3 +xstream xmlpull-1.1.3.1.jar 1.1.3.1 + xpp3_min-1.1.4c.jar 1.1.4c + xstream-1.5.0-SNAPSHOT.jar 1.5.0 XML serializer - ******Build Related Libraries****** Folder Library Version License Vendor Description Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java =================================================================== diff -u -r08975c671d19a7f4ee7351a38eaed88c8602d0c3 -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 08975c671d19a7f4ee7351a38eaed88c8602d0c3) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -60,7 +60,6 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; -import org.apache.batik.transcoder.TranscoderException; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; @@ -152,6 +151,12 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; /** * Export tool content service bean. @@ -187,9 +192,9 @@ public static final String TOOL_FILE_NAME = "tool.xml"; public static final String TOOL_FAILED_FILE_NAME = "export_failed.xml"; - + public static final String SVG_IMAGE_FILE_NAME = "learning_design.svg"; - + public static final String PNG_IMAGE_FILE_NAME = "learning_design.png"; private static final String ERROR_TOOL_NOT_FOUND = "error.import.matching.tool.not.found"; @@ -424,88 +429,73 @@ } } - /** - * Proxy class for Default XStream converter. - * - */ - private class FileInvocationHandler implements InvocationHandler { + private class FileConverter implements Converter { + private Converter defaultConverter; + private List fileNodes = new ArrayList(); - private Object obj; + public FileConverter(XStream xstream) { + this.defaultConverter = new ReflectionConverter(xstream.getMapper(), xstream.getReflectionProvider()); + } - private List fileNodes; + public List getFileNodes() { + return fileNodes; + } - private List fileHandleClassList; - - public FileInvocationHandler(Object obj) { - this.obj = obj; - fileNodes = new ArrayList(); + @Override + public boolean canConvert(Class type) { + for (NameInfo info : fileHandleClassList) { + if (info.className.equals(type.getName())) { + log.debug("XStream will handle [" + info.className + "] as file node class."); + return true; + } + } + return false; } - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Object result; - try { - // for export : marshal object to xml - if (StringUtils.equals(method.getName(), "marshal")) { + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + if (source != null) { + String className = source.getClass().getName(); + try { for (NameInfo name : fileHandleClassList) { - if (args[0] != null && name.className.equals(args[0].getClass().getName())) { - Long uuid = NumberUtils.createLong(BeanUtils.getProperty(args[0], name.uuidFieldName)); + if (name.className.equals(className)) { + Long uuid = NumberUtils.createLong(BeanUtils.getProperty(source, name.uuidFieldName)); if (uuid != null) { // version id is optional Long version = null; if (name.versionFieldName != null) { - version = NumberUtils.createLong(BeanUtils.getProperty(args[0], + version = NumberUtils.createLong(BeanUtils.getProperty(source, name.versionFieldName)); } log.debug("XStream get file node [" + uuid + "," + version + "]."); fileNodes.add(ExportToolContentService.this.new ValueInfo(uuid, version)); } } } + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + log.error("Error while marshalling a file", e); } + } - if (StringUtils.equals(method.getName(), "canConvert")) { - boolean canConvert = false; - for (NameInfo info : fileHandleClassList) { - if (args[0] != null && info.className.equals(((Class) args[0]).getName())) { - log.debug("XStream will handle [" + info.className + "] as file node class."); - canConvert = true; - break; - } - } - return canConvert; - } + defaultConverter.marshal(source, writer, context); + } - result = method.invoke(obj, args); - - // for import : unmarshal xml to object - if (StringUtils.equals(method.getName(), "unmarshal") && result != null) { - // During deserialize XML file into object, it will save - // file node into fileNodes - for (NameInfo name : fileHandleClassList) { - if (name.className.equals(result.getClass().getName())) { - fileNodes.add(ExportToolContentService.this.new ValueInfo(name, result)); - break; - } + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + Object result = defaultConverter.unmarshal(reader, context); + if (result != null) { + String className = result.getClass().getName(); + // During deserialize XML file into object, it will save file node into fileNodes + for (NameInfo name : fileHandleClassList) { + if (name.className.equals(className)) { + fileNodes.add(ExportToolContentService.this.new ValueInfo(name, result)); + break; } } - } catch (InvocationTargetException e) { - throw e.getTargetException(); } return result; } - - public List getFileNodes() { - return fileNodes; - } - - public List getFileHandleClassList() { - return fileHandleClassList; - } - - public void setFileHandleClassList(List fileHandleClassList) { - this.fileHandleClassList = fileHandleClassList; - } } /** @@ -532,6 +522,7 @@ /** * @see org.lamsfoundation.lams.authoring.service.IExportToolContentService.exportLearningDesign(Long) */ + @Override public String exportLearningDesign(Long learningDesignId, List toolsErrorMsgs, int format, File xslt) throws ExportToolContentException { try { @@ -595,8 +586,8 @@ int activityTypeID = activity.getActivityTypeID().intValue(); // for teacher chosen and tool based branching activities there // should be no groupings saved to XML - if (activityTypeID == Activity.CHOSEN_BRANCHING_ACTIVITY_TYPE - || activityTypeID == Activity.TOOL_BRANCHING_ACTIVITY_TYPE) { + if ((activityTypeID == Activity.CHOSEN_BRANCHING_ACTIVITY_TYPE) + || (activityTypeID == Activity.TOOL_BRANCHING_ACTIVITY_TYPE)) { Long groupingID = activity.getGroupingID(); if (groupingID != null) { groupingsToSkip.add(groupingID); @@ -653,21 +644,22 @@ XStream designXml = new XStream(); designXml.toXML(ldDto, ldFile); ldFile.close(); - + //generate SVG image if (format != ExportToolContentService.PACKAGE_FORMAT_IMS) { - + String destinationPath = FileUtil.getFullPath(contentDir, ExportToolContentService.SVG_IMAGE_FILE_NAME); - String svgPath = service.createLearningDesignSVG(learningDesignId, SVGGenerator.OUTPUT_FORMAT_SVG_LAMS_COMMUNITY); + String svgPath = service.createLearningDesignSVG(learningDesignId, + SVGGenerator.OUTPUT_FORMAT_SVG_LAMS_COMMUNITY); File svgFile = new File(svgPath); - if (svgFile.canRead()){ + if (svgFile.canRead()) { FileUtils.copyFile(svgFile, new File(destinationPath)); } - + destinationPath = FileUtil.getFullPath(contentDir, ExportToolContentService.PNG_IMAGE_FILE_NAME); String pngPath = service.createLearningDesignSVG(learningDesignId, SVGGenerator.OUTPUT_FORMAT_PNG); File pngFile = new File(pngPath); - if (pngFile.canRead()){ + if (pngFile.canRead()) { FileUtils.copyFile(pngFile, new File(destinationPath)); } } @@ -803,7 +795,8 @@ if (actDto.getActivityTypeID().equals(Activity.SEQUENCE_ACTIVITY_TYPE)) { String attributeValue = ExportToolContentService.IMS_PREFIX_COMPLEX_REF + ExportToolContentService.IMS_TAG_SEQUENCE + "-" + actDto.getActivityID(); - if (actDto.getParentActivityID() != null && branchingActivityIds.contains(actDto.getParentActivityID())) { + if ((actDto.getParentActivityID() != null) + && branchingActivityIds.contains(actDto.getParentActivityID())) { Element[] propertyConditions = generatePropertyCondition(actDto.getActivityID(), attributeValue); propertiesChildren.add(propertyConditions[0]); conditionsChildren.add(propertyConditions[1]); @@ -1023,7 +1016,7 @@ } } - if (actId == null || transList.size() == sortedList.size()) { + if ((actId == null) || (transList.size() == sortedList.size())) { break; } @@ -1119,8 +1112,7 @@ // create a new tools.xml file with toolContentID.xml as // name. File imsToolFile = new File(FileUtil.getFullPath(xsltDir, activity.getToolContentID() - .toString() - + ".xml")); + .toString() + ".xml")); XMLOutputter toolOutput = new XMLOutputter(); toolOutput.output(doc, new FileOutputStream(imsToolFile)); @@ -1181,6 +1173,7 @@ * @throws ExportToolContentException * */ + @Override public void exportToolContent(Long toolContentId, Object toolContentObj, IToolContentHandler toolContentHandler, String rootPath) throws ExportToolContentException { try { @@ -1194,31 +1187,22 @@ // serialize tool xml into local file. XStream toolXml = new XStream(); - // get back Xstream default convert, create proxy then register - // it to XStream parser. - Converter c = toolXml.getConverterLookup().defaultConverter(); - FileInvocationHandler handler = null; + FileConverter fileConverter = null; if (!fileHandleClassList.isEmpty()) { - handler = new FileInvocationHandler(c); - handler.setFileHandleClassList(fileHandleClassList); - Converter myc = (Converter) Proxy.newProxyInstance(c.getClass().getClassLoader(), - new Class[] { Converter.class }, handler); - toolXml.registerConverter(myc); + fileConverter = new FileConverter(toolXml); + toolXml.registerConverter(fileConverter); } // XML to Object toolXml.toXML(toolContentObj, toolFile); toolFile.flush(); toolFile.close(); - // get out the fileNodes - if (handler != null) { - List list = handler.getFileNodes(); - for (ValueInfo fileNode : list) { + if (fileConverter != null) { + for (ValueInfo fileNode : fileConverter.getFileNodes()) { log.debug("Tool attachement file is going to save : " + fileNode.fileUuid); - toolContentHandler.saveFile(fileNode.fileUuid, FileUtil.getFullPath(toolPath, fileNode.fileUuid - .toString())); + toolContentHandler.saveFile(fileNode.fileUuid, + FileUtil.getFullPath(toolPath, fileNode.fileUuid.toString())); } - list.clear(); } } catch (ItemNotFoundException e) { throw new ExportToolContentException(e); @@ -1237,20 +1221,25 @@ } /** - * @see org.lamsfoundation.lams.authoring.service.IExportToolContentService.registerFileHandleClass(String,String,String) + * @see + * org.lamsfoundation.lams.authoring.service.IExportToolContentService.registerFileHandleClass(String,String,String + * ) */ + @Override public void registerFileClassForExport(String fileNodeClassName, String fileUuidFieldName, String fileVersionFieldName) { fileHandleClassList.add(this.new NameInfo(fileNodeClassName, fileUuidFieldName, fileVersionFieldName)); } + @Override public void registerFileClassForImport(String fileNodeClassName, String fileUuidFieldName, String fileVersionFieldName, String fileNameFieldName, String filePropertyFieldName, String mimeTypeFieldName, String initialItemFieldName) { fileHandleClassList.add(this.new NameInfo(fileNodeClassName, fileUuidFieldName, fileVersionFieldName, fileNameFieldName, filePropertyFieldName, mimeTypeFieldName, initialItemFieldName)); } + @Override public void registerImportVersionFilterClass(Class filterClass) { this.filterClass = filterClass; } @@ -1271,21 +1260,23 @@ * * @throws ImportToolContentException */ + @Override public Object[] importLearningDesign(File designFile, User importer, Integer workspaceFolderUid, List toolsErrorMsgs, String customCSV) throws ImportToolContentException { Object[] ldResults = new Object[3]; Long ldId = null; List ldErrorMsgs = new ArrayList(); String filename = designFile.getName(); - String extension = filename != null && filename.length() >= 4 ? filename.substring(filename.length() - 4) : ""; + String extension = (filename != null) && (filename.length() >= 4) ? filename.substring(filename.length() - 4) + : ""; try { if (extension.equalsIgnoreCase(".las")) { // process 1.0.x file. String wddxPacket = getPacket(new FileInputStream(designFile)); - if (wddxPacket == null || !(wddxPacket.startsWith(" valueList = null; try { - // tool.xml full path String toolFilePath = FileUtil.getFullPath(toolContentPath, ExportToolContentService.TOOL_FILE_NAME); - if (filterClass != null && !StringUtils.equals(fromVersion, toVersion)) { + if ((filterClass != null) && !StringUtils.equals(fromVersion, toVersion)) { filterVersion(toolFilePath, fromVersion, toVersion); } // clear and ensure next activity can get correct filter thru @@ -1603,11 +1585,9 @@ // read tool file after transform. toolPOJO = FileUtil.getObjectFromXML(toolXml, toolFilePath); - // upload file node if has - if (handler != null) { - valueList = handler.getFileNodes(); - for (ValueInfo fileNode : valueList) { - + if (fileConverter != null) { + // upload file node if has + for (ValueInfo fileNode : fileConverter.getFileNodes()) { Long uuid = NumberUtils.createLong(BeanUtils.getProperty(fileNode.instance, fileNode.name.uuidFieldName)); // For instance, item class in share resource tool may @@ -1687,9 +1667,6 @@ if (fileHandleClassList != null) { fileHandleClassList.clear(); } - if (valueList != null) { - valueList.clear(); - } } return toolPOJO; @@ -1698,6 +1675,7 @@ // ****************************************************************** // ApplicationContextAware method implementation // ****************************************************************** + @Override public void setApplicationContext(ApplicationContext context) throws BeansException { applicationContext = context; } @@ -1787,7 +1765,7 @@ } break; } - if (mf >= from && mt <= to) { + if ((mf >= from) && (mt <= to)) { methodNeeds.put(mf, method); } } @@ -2002,20 +1980,20 @@ // try to find next available activity // 1000 is failure tolerance: to avoid dead loop. for (int idx = 0; idx < 1000; idx++) { - if (transDtoList == null || transDtoList.isEmpty()) { + if ((transDtoList == null) || transDtoList.isEmpty()) { break; } boolean transitionBreak = true; for (TransitionDTO transDto : transDtoList) { // we deal with progress transitions only - if (transDto.getTransitionType() == null + if ((transDto.getTransitionType() == null) || transDto.getTransitionType().equals(Transition.PROGRESS_TRANSITION_TYPE)) { // find out the transition of current first // activity if (nextActId.equals(transDto.getFromActivityID())) { transitionBreak = false; nextActId = transDto.getToActivityID(); - if (nextActId != null && !removedActMap.containsKey(nextActId)) { + if ((nextActId != null) && !removedActMap.containsKey(nextActId)) { existFirstAct = nextActId; found = true; break; @@ -2060,10 +2038,10 @@ // Any transitions relating with this tool will be removed! Long fromId = transDto.getFromActivityID(); Long toId = transDto.getToActivityID(); - if (fromId != null && removedActMap.containsKey(fromId)) { + if ((fromId != null) && removedActMap.containsKey(fromId)) { continue; } - if (toId != null && removedActMap.containsKey(toId)) { + if ((toId != null) && removedActMap.containsKey(toId)) { continue; } Transition trans = getTransition(transDto, activityMapper); @@ -2110,15 +2088,14 @@ // then read and update the title, then save again. learningDesignDAO.insert(ld); - // add suffix if configuration is not set or is set to true String addSuffix = Configuration.get(ConfigurationKeys.SUFFIX_IMPORTED_LD); - if (addSuffix == null || Boolean.valueOf(addSuffix)) { + if ((addSuffix == null) || Boolean.valueOf(addSuffix)) { ld.setTitle(ImportExportUtil.generateUniqueLDTitle(folder, ld.getTitle(), learningDesignDAO)); learningDesignDAO.update(ld); // persist } - + // Once we have the competences saved, we can save the competence mappings Set allCompetenceMappings = new HashSet(); for (AuthoringActivityDTO actDto : actDtoList) { @@ -2162,7 +2139,7 @@ // there is at least one node parent is // null(root). int failureToleranceCount = 5000; - while (!activities.isEmpty() && failureToleranceCount > 0) { + while (!activities.isEmpty() && (failureToleranceCount > 0)) { Iterator iter = activities.iterator(); while (iter.hasNext()) { AuthoringActivityDTO actDto = iter.next(); @@ -2191,12 +2168,10 @@ } /** - * Get learning design object from this Learning design DTO object. It also following our import rules: - *
  • lams_license - Assume same in all lams system. Import same ID
  • - *
  • lams_copy_type - Set to 1.This indicates it is "normal" design.
  • - *
  • lams_workspace_folder - An input parameters to let user choose import workspace
  • - *
  • User - The person who execute import action
  • - *
  • OriginalLearningDesign - set to null
  • + * Get learning design object from this Learning design DTO object. It also following our import rules:
  • + * lams_license - Assume same in all lams system. Import same ID
  • lams_copy_type - Set to 1.This indicates + * it is "normal" design.
  • lams_workspace_folder - An input parameters to let user choose import workspace
  • + *
  • User - The person who execute import action
  • OriginalLearningDesign - set to null
  • * * @param activityMapper * @@ -2415,7 +2390,7 @@ if (transDto == null) { return trans; } - if (transDto.getTransitionType() != null + if ((transDto.getTransitionType() != null) && transDto.getTransitionType().equals(Transition.DATA_TRANSITION_TYPE)) { trans = new DataTransition(); } else { @@ -2571,7 +2546,7 @@ break; } - if (act.isComplexActivity() && actDto.getDefaultActivityUIID() != null) { + if (act.isComplexActivity() && (actDto.getDefaultActivityUIID() != null)) { defaultActivityToParentActivityMapping.put(actDto.getDefaultActivityUIID(), (ComplexActivity) act); } @@ -2629,12 +2604,12 @@ * Guess missing Learning Library ID based on activity description. Old exported LDs may not contain this value. */ private void fillLearningLibraryID(AuthoringActivityDTO activity) { - if (activity.getLearningLibraryID() == null + if ((activity.getLearningLibraryID() == null) && activity.getActivityTypeID().equals(Activity.PARALLEL_ACTIVITY_TYPE)) { String description = activity.getDescription(); // recognise learning libraries by their word description - for (LearningLibrary library : (List) learningLibraryDAO.getAllLearningLibraries()) { - for (String[] keyWords : COMPLEX_LEARNING_LIBRARY_KEY_WORDS) { + for (LearningLibrary library : learningLibraryDAO.getAllLearningLibraries()) { + for (String[] keyWords : ExportToolContentService.COMPLEX_LEARNING_LIBRARY_KEY_WORDS) { boolean found = false; for (String keyWord : keyWords) { found = description.contains(keyWord) && library.getDescription().contains(keyWord); Index: lams_common/src/java/org/lamsfoundation/lams/util/FileUtil.java =================================================================== diff -u -r5b4307e77743c078a26bb2b953b6f5245b697e26 -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- lams_common/src/java/org/lamsfoundation/lams/util/FileUtil.java (.../FileUtil.java) (revision 5b4307e77743c078a26bb2b953b6f5245b697e26) +++ lams_common/src/java/org/lamsfoundation/lams/util/FileUtil.java (.../FileUtil.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -50,6 +50,7 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.security.AnyTypePermission; /** * General File Utilities @@ -740,6 +741,8 @@ Reader file = null; XStream conversionXml = xStream != null ? xStream : new XStream(); + // allow parsing all classes + conversionXml.addPermission(AnyTypePermission.ANY); ConversionException finalException = null; String lastFieldRemoved = ""; ToolContentVersionFilter contentFilter = null; Index: lams_contentrepository/src/java/org/lamsfoundation/lams/contentrepository/dao/hibernate/CredentialDAO.java =================================================================== diff -u -rccfd66f1abbfc63cd0ed0a044f89914418d67cd1 -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- lams_contentrepository/src/java/org/lamsfoundation/lams/contentrepository/dao/hibernate/CredentialDAO.java (.../CredentialDAO.java) (revision ccfd66f1abbfc63cd0ed0a044f89914418d67cd1) +++ lams_contentrepository/src/java/org/lamsfoundation/lams/contentrepository/dao/hibernate/CredentialDAO.java (.../CredentialDAO.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -24,15 +24,10 @@ /* $$Id$$ */ package org.lamsfoundation.lams.contentrepository.dao.hibernate; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.List; import org.apache.log4j.Logger; -import org.hibernate.HibernateException; -import org.hibernate.ScrollableResults; +import org.hibernate.Query; import org.hibernate.Session; import org.lamsfoundation.lams.contentrepository.CrCredential; import org.lamsfoundation.lams.contentrepository.ICredentials; @@ -49,27 +44,46 @@ * */ public class CredentialDAO extends BaseDAO implements ICredentialDAO { + private Logger log = Logger.getLogger(CredentialDAO.class); - protected Logger log = Logger.getLogger(CredentialDAO.class); + private static final String GET_CREDENTIAL = "FROM " + CrCredential.class.getName() + " AS cr WHERE cr.name = ?"; + private static final String CHECK_CREDENTIAL = "SELECT COUNT(*) FROM " + CrCredential.class.getName() + + " AS cr WHERE cr.name = ? AND cr.password = ?"; + private static final String CHECK_CREDENTIAL_WITH_WORKSPACE = "SELECT COUNT(*) FROM " + + CrCredential.class.getName() + + " AS cr INNER JOIN cr.crWorkspaceCredentials AS wcr WHERE cr.name = ? AND cr.password = ? AND wcr.crWorkspace.workspaceId = ?"; /** * Checks whether a user can login to this workspace. The Credential must include the password. */ + @Override public boolean checkCredential(ICredentials credential, IWorkspace workspace) throws RepositoryRuntimeException { if (log.isDebugEnabled()) { log.debug("Checking credential " + credential + " for workspace " + workspace); } - - if (credential == null || workspace == null || workspace.getWorkspaceId() == null) { + if ((credential == null) || (workspace == null) || (workspace.getWorkspaceId() == null)) { return false; } - return checkCredentialInternal(credential, workspace); + Session hibernateSession = getSessionFactory().getCurrentSession(); + Query query = hibernateSession.createQuery(CredentialDAO.CHECK_CREDENTIAL_WITH_WORKSPACE); + query.setString(0, credential.getName()); + query.setString(1, String.valueOf(credential.getPassword())); + query.setLong(2, workspace.getWorkspaceId()); + + Long count = (Long) query.uniqueResult(); + if (count > 2) { + log.warn("More than one credential found for workspace " + workspace.getWorkspaceId() + " and credential " + + credential.getName()); + } + + return count > 0; } /** * Checks whether a user can login to the repository. The Credential must include the password. */ + @Override public boolean checkCredential(ICredentials credential) throws RepositoryRuntimeException { if (log.isDebugEnabled()) { log.debug("Checking credential " + credential); @@ -79,68 +93,27 @@ return false; } - return checkCredentialInternal(credential, null); - } - - /** - * Checks whether a user can login to the repository. The Credential must include the password. - * - * If workspace defined then checks workspace, otherwise just checks password - */ - public boolean checkCredentialInternal(ICredentials credential, IWorkspace workspace) - throws RepositoryRuntimeException { - - // given the input credential, is there a credential matching - // in the database? why go to so much trouble in this code? I'm trying - // to avoid converting the char[] to a string. - // There will be better ways to do this, but this will do for starters - // until I get more familiar with Spring. - - StringBuffer buf = new StringBuffer(200); - buf.append("select count(*) num from lams_cr_credential c"); - if (workspace != null) { - buf.append(", lams_cr_workspace_credential wc "); - } - buf.append(" where c.name = \""); - buf.append(credential.getName()); - buf.append("\" and c.password = \""); - buf.append(credential.getPassword()); - buf.append("\""); - if (workspace != null) { - buf.append(" and wc.credential_id = c.credential_id "); - buf.append(" and wc.workspace_id = "); - buf.append(workspace.getWorkspaceId()); - } - - boolean credentialMatched = false; Session hibernateSession = getSessionFactory().getCurrentSession(); - ScrollableResults result = hibernateSession.createSQLQuery(buf.toString()).scroll(); - if (result.next()) { - long val = result.getLong(0); - if (val > 0) { - credentialMatched = true; - if (val > 1) { - log.warn("More than one credential found for workspace " + workspace.getWorkspaceId() - + " credential name " + credential.getName()); - } - } - } + Query query = hibernateSession.createQuery(CredentialDAO.CHECK_CREDENTIAL); + query.setString(0, credential.getName()); + query.setString(1, String.valueOf(credential.getPassword())); - return credentialMatched; + Long count = (Long) query.uniqueResult(); + if (count > 2) { + log.warn("More than one credential found for name " + credential.getName()); + } + return count > 0; } + @SuppressWarnings("unchecked") + @Override public CrCredential findByName(String name) { - - log.debug("Getting credential for name " + name); - - String queryString = "from CrCredential as c where c.name = ?"; - List credentials = getHibernateTemplate().find(queryString, name); - - if (credentials.size() == 0) { - log.debug("No credentials found"); - return null; - } else { - return (CrCredential) credentials.get(0); + if (log.isDebugEnabled()) { + log.debug("Getting credential for name " + name); } + + List credentials = (List) getHibernateTemplate().find(CredentialDAO.GET_CREDENTIAL, + name); + return credentials.size() == 0 ? null : credentials.get(0); } -} +} \ No newline at end of file Index: lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/service/MindmapService.java =================================================================== diff -u -r40eb54374e84591563d8b6a679ac719dbc85c8f7 -rc6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8 --- lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/service/MindmapService.java (.../MindmapService.java) (revision 40eb54374e84591563d8b6a679ac719dbc85c8f7) +++ lams_tool_mindmap/src/java/org/lamsfoundation/lams/tool/mindmap/service/MindmapService.java (.../MindmapService.java) (revision c6b29814cfe36cd678a7cdd1d7ed0aab7d0fbec8) @@ -71,6 +71,7 @@ import org.lamsfoundation.lams.util.audit.IAuditService; import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.security.AnyTypePermission; /** * An implementation of the IMindmapService interface. As a requirement, all LAMS tool's service bean must implement @@ -528,6 +529,8 @@ MindmapUser mindmapUser = null; XStream xstream = new XStream(); + // allow parsing all classes + xstream.addPermission(AnyTypePermission.ANY); xstream.alias("branch", NodeModel.class); NodeModel rootNodeModel = (NodeModel) xstream.fromXML(mindmapContent); NodeConceptModel nodeConceptModel = rootNodeModel.getConcept();