Log Message
Merge deprecation of SerializationMethodInvoker from trunk.
Modified Paths
- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java
- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java
- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java
- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java
- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java
- branches/v-1.4.x/xstream-distribution/src/content/changes.html
Added Paths
Property Changed
Diff
Property changes: branches/v-1.4.x
Modified: svn:mergeinfo
Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java (2333 => 2334)
--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java 2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java 2015-02-15 02:37:22 UTC (rev 2334)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2004, 2005, 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
@@ -22,6 +22,7 @@
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.core.util.SerializationMembers;
import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
@@ -47,13 +48,19 @@
protected final ReflectionProvider reflectionProvider;
protected final Mapper mapper;
+ /**
+ * @deprecated As of upcoming, use {@link #serializationMembers}.
+ */
+ @Deprecated
protected transient SerializationMethodInvoker serializationMethodInvoker;
+ protected transient SerializationMembers serializationMembers;
private transient ReflectionProvider pureJavaReflectionProvider;
public AbstractReflectionConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
this.mapper = mapper;
this.reflectionProvider = reflectionProvider;
serializationMethodInvoker = new SerializationMethodInvoker();
+ serializationMembers = serializationMethodInvoker.serializationMembers;
}
protected boolean canAccess(Class type) {
@@ -68,7 +75,7 @@
public void marshal(Object original, final HierarchicalStreamWriter writer,
final MarshallingContext context) {
- final Object source = serializationMethodInvoker.callWriteReplace(original);
+ final Object source = serializationMembers.callWriteReplace(original);
if (source != original && context instanceof ReferencingMarshallingContext) {
((ReferencingMarshallingContext)context).replace(original, source);
@@ -255,7 +262,7 @@
final UnmarshallingContext context) {
Object result = instantiateNewInstance(reader, context);
result = doUnmarshal(result, reader, context);
- return serializationMethodInvoker.callReadResolve(result);
+ return serializationMembers.callReadResolve(result);
}
public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader,
@@ -560,6 +567,7 @@
protected Object readResolve() {
serializationMethodInvoker = new SerializationMethodInvoker();
+ serializationMembers = serializationMethodInvoker.serializationMembers;
return this;
}
Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java (2333 => 2334)
--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java 2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java 2015-02-15 02:37:22 UTC (rev 2334)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
@@ -407,7 +407,7 @@
if (result == null) {
result = create(enhancer, callbacks, useFactory);
}
- return serializationMethodInvoker.callReadResolve(result);
+ return serializationMembers.callReadResolve(result);
}
private void readCallback(HierarchicalStreamReader reader, UnmarshallingContext context,
Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java (2333 => 2334)
--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java 2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java 2015-02-15 02:37:22 UTC (rev 2334)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2004, 2005, 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
@@ -21,9 +21,10 @@
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.core.util.SerializationMembers;
+import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
import com.thoughtworks.xstream.mapper.Mapper;
import java.io.Externalizable;
@@ -44,7 +45,7 @@
private Mapper mapper;
private final ClassLoaderReference classLoaderReference;
- private transient SerializationMethodInvoker serializationMethodInvoker;
+ private transient SerializationMembers serializationMembers;
/**
* Construct an ExternalizableConverter.
@@ -56,7 +57,7 @@
public ExternalizableConverter(Mapper mapper, ClassLoaderReference classLoaderReference) {
this.mapper = mapper;
this.classLoaderReference = classLoaderReference;
- serializationMethodInvoker = new SerializationMethodInvoker();
+ serializationMembers = new SerializationMembers();
}
/**
@@ -78,7 +79,7 @@
}
public void marshal(final Object original, final HierarchicalStreamWriter writer, final MarshallingContext context) {
- final Object source = serializationMethodInvoker.callWriteReplace(original);
+ final Object source = serializationMembers.callWriteReplace(original);
if (source != original && context instanceof ReferencingMarshallingContext) {
((ReferencingMarshallingContext)context).replace(original, source);
}
@@ -165,7 +166,7 @@
CustomObjectInputStream objectInput = CustomObjectInputStream.getInstance(context, callback, classLoaderReference);
externalizable.readExternal(objectInput);
objectInput.popCallback();
- return serializationMethodInvoker.callReadResolve(externalizable);
+ return serializationMembers.callReadResolve(externalizable);
} catch (NoSuchMethodException e) {
throw new ConversionException("Cannot construct " + type.getClass() + ", missing default constructor", e);
} catch (InvocationTargetException e) {
@@ -182,7 +183,7 @@
}
private Object readResolve() {
- serializationMethodInvoker = new SerializationMethodInvoker();
+ serializationMembers = new SerializationMembers();
return this;
}
}
Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java (2333 => 2334)
--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java 2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java 2015-02-15 02:37:22 UTC (rev 2334)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2004, 2005, 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014, 2015 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
@@ -33,9 +33,9 @@
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.io.ExtendedHierarchicalStreamWriterHelper;
import com.thoughtworks.xstream.mapper.Mapper;
/**
@@ -75,6 +75,7 @@
/**
* 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
@@ -107,7 +108,7 @@
if (type != null
&& Serializable.class.isAssignableFrom(type)
&& !type.isInterface()
- && (serializationMethodInvoker.supportsReadObject(type, true) || serializationMethodInvoker
+ && (serializationMembers.supportsReadObject(type, true) || serializationMembers
.supportsWriteObject(type, true))) {
for (Iterator iter = hierarchyFor(type).iterator(); iter.hasNext();) {
if (!Serializable.class.isAssignableFrom((Class)iter.next())) {
@@ -246,7 +247,7 @@
marshalUnserializableParent(writer, context, source);
mustHandleUnserializableParent = false;
}
- if (serializationMethodInvoker.supportsWriteObject(currentType[0], false)) {
+ if (serializationMembers.supportsWriteObject(currentType[0], false)) {
writtenClassWrapper[0] = true;
writer.startNode(mapper.serializedClass(currentType[0]));
if (currentType[0] != mapper.defaultImplementationOf(currentType[0])) {
@@ -256,10 +257,10 @@
}
}
CustomObjectOutputStream objectOutputStream = CustomObjectOutputStream.getInstance(context, callback);
- serializationMethodInvoker.callWriteObject(currentType[0], source, objectOutputStream);
+ serializationMembers.callWriteObject(currentType[0], source, objectOutputStream);
objectOutputStream.popCallback();
writer.endNode();
- } else if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) {
+ } else if (serializationMembers.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.
@@ -390,7 +391,7 @@
}
public void defaultReadObject() {
- if (serializationMethodInvoker.getSerializablePersistentFields(currentType[0]) != null) {
+ if (serializationMembers.getSerializablePersistentFields(currentType[0]) != null) {
readFieldsFromStream();
return;
}
@@ -452,10 +453,10 @@
} else {
currentType[0] = mapper.realClass(classAttribute);
}
- if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) {
+ if (serializationMembers.supportsReadObject(currentType[0], false)) {
CustomObjectInputStream objectInputStream =
CustomObjectInputStream.getInstance(context, callback, classLoaderReference);
- serializationMethodInvoker.callReadObject(currentType[0], result, objectInputStream);
+ serializationMembers.callReadObject(currentType[0], result, objectInputStream);
objectInputStream.popCallback();
} else {
try {
Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java (2333 => 2334)
--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java 2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java 2015-02-15 02:37:22 UTC (rev 2334)
@@ -11,22 +11,11 @@
*/
package com.thoughtworks.xstream.converters.reflection;
-import com.thoughtworks.xstream.converters.ConversionException;
-import com.thoughtworks.xstream.core.Caching;
-import com.thoughtworks.xstream.core.util.FastField;
-
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.ObjectStreamField;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import com.thoughtworks.xstream.core.Caching;
+import com.thoughtworks.xstream.core.util.SerializationMembers;
/**
* Convenience wrapper to invoke special serialization methods on objects (and perform
@@ -34,211 +23,60 @@
*
* @author Joe Walnes
* @author Jörg Schaible
+ * @deprecated As of upcoming, moved into internal util package.
*/
public class SerializationMethodInvoker implements Caching {
- private static final Method NO_METHOD = (new Object() {
- private void noMethod() {
- }
- }).getClass().getDeclaredMethods()[0];
- private static final Object[] EMPTY_ARGS = new Object[0];
- private static final Class[] EMPTY_CLASSES = new Class[0];
- private static final Map NO_FIELDS = Collections.EMPTY_MAP;
- private static final int PERSISTENT_FIELDS_MODIFIER = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
- private static final FastField[] OBJECT_TYPE_FIELDS = {
- new FastField(Object.class, "readResolve"),
- new FastField(Object.class, "writeReplace"),
- new FastField(Object.class, "readObject"),
- new FastField(Object.class, "writeObject")
- };
- private Map declaredCache = Collections.synchronizedMap(new HashMap());
- private Map resRepCache = Collections.synchronizedMap(new HashMap());
- private final Map fieldCache = Collections.synchronizedMap(new HashMap());
- {
- for(int i = 0; i < OBJECT_TYPE_FIELDS.length; ++i) {
- declaredCache.put(OBJECT_TYPE_FIELDS[i], NO_METHOD);
- }
- for(int i = 0; i < 2; ++i) {
- resRepCache.put(OBJECT_TYPE_FIELDS[i], NO_METHOD);
- }
- }
+ SerializationMembers serializationMembers = new SerializationMembers();
/**
* Resolves an object as native serialization does by calling readResolve(), if available.
+ *
+ * @deprecated As of upcoming, moved into internal util package.
*/
public Object callReadResolve(Object result) {
- if (result == null) {
- return null;
- } else {
- final Class resultType = result.getClass();
- final Method readResolveMethod = getRRMethod(resultType, "readResolve");
- if (readResolveMethod != null) {
- try {
- return readResolveMethod.invoke(result, EMPTY_ARGS);
- } catch (IllegalAccessException e) {
- throw new ObjectAccessException("Could not call "
- + resultType.getName()
- + ".readResolve()", e);
- } catch (InvocationTargetException e) {
- throw new ObjectAccessException("Could not call "
- + resultType.getName()
- + ".readResolve()", e.getTargetException());
- }
- } else {
- return result;
- }
- }
+ return serializationMembers.callReadResolve(result);
}
+ /**
+ * @deprecated As of upcoming, moved into internal util package.
+ */
public Object callWriteReplace(Object object) {
- if (object == null) {
- return null;
- } else {
- final Class objectType = object.getClass();
- final Method writeReplaceMethod = getRRMethod(objectType, "writeReplace");
- if (writeReplaceMethod != null) {
- try {
- return writeReplaceMethod.invoke(object, EMPTY_ARGS);
- } catch (IllegalAccessException e) {
- throw new ObjectAccessException("Could not call "
- + objectType.getName()
- + ".writeReplace()", e);
- } catch (InvocationTargetException e) {
- throw new ObjectAccessException("Could not call "
- + objectType.getName()
- + ".writeReplace()", e.getTargetException());
- }
- } else {
- return object;
- }
- }
+ return serializationMembers.callWriteReplace(object);
}
+ /**
+ * @deprecated As of upcoming, moved into internal util package.
+ */
public boolean supportsReadObject(Class type, boolean includeBaseClasses) {
- return getMethod(
- type, "readObject", new Class[]{ObjectInputStream.class}, includeBaseClasses) != null;
+ return serializationMembers.supportsReadObject(type, includeBaseClasses);
}
+ /**
+ * @deprecated As of upcoming, moved into internal util package.
+ */
public void callReadObject(Class type, Object object, ObjectInputStream stream) {
- try {
- Method readObjectMethod = getMethod(
- type, "readObject", new Class[]{ObjectInputStream.class}, false);
- readObjectMethod.invoke(object, new Object[]{stream});
- } catch (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.getTargetException());
- }
+ serializationMembers.callReadObject(type, object, stream);
}
+ /**
+ * @deprecated As of upcoming, moved into internal util package.
+ */
public boolean supportsWriteObject(Class type, boolean includeBaseClasses) {
- return getMethod(
- type, "writeObject", new Class[]{ObjectOutputStream.class}, includeBaseClasses) != null;
+ return serializationMembers.supportsWriteObject(type, includeBaseClasses);
}
+ /**
+ * @deprecated As of upcoming, moved into internal util package.
+ */
public void callWriteObject(Class type, Object instance, ObjectOutputStream stream) {
- try {
- Method readObjectMethod = getMethod(
- type, "writeObject", new Class[]{ObjectOutputStream.class}, false);
- readObjectMethod.invoke(instance, new Object[]{stream});
- } catch (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.getTargetException());
- }
+ serializationMembers.callWriteObject(type, instance, stream);
}
- private Method getMethod(Class type, String name, Class[] parameterTypes,
- boolean includeBaseclasses) {
- Method method = getMethod(type, name, parameterTypes);
- return method == NO_METHOD
- || (!includeBaseclasses && !method.getDeclaringClass().equals(type))
- ? null
- : method;
- }
-
- private Method getMethod(Class type, String name, Class[] parameterTypes) {
- if (type == null) {
- return null;
- }
- FastField method = new FastField(type, name);
- Method result = (Method)declaredCache.get(method);
- if (result == null) {
- try {
- result = type.getDeclaredMethod(name, parameterTypes);
- if (!result.isAccessible()) {
- result.setAccessible(true);
- }
- } catch (NoSuchMethodException e) {
- result = getMethod(type.getSuperclass(), name, parameterTypes);
- }
- declaredCache.put(method, result);
- }
- return result;
- }
-
- private Method getRRMethod(final Class type, final String name) {
- final FastField method = new FastField(type, name);
- Method result = (Method)resRepCache.get(method);
- if (result == null) {
- result = getMethod(type, name, EMPTY_CLASSES, true);
- if (result != null && result.getDeclaringClass() != type) {
- if ((result.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0) {
- if ((result.getModifiers() & Modifier.PRIVATE) > 0
- || type.getPackage() != result.getDeclaringClass().getPackage()) {
- result = NO_METHOD;
- }
- }
- } else if (result == null) {
- result = NO_METHOD;
- }
- resRepCache.put(method, result);
- }
- return result == NO_METHOD ? null : result;
- }
-
- public Map getSerializablePersistentFields(final Class type) {
- if (type == null) {
- return null;
- }
- Map result = (Map)fieldCache.get(type.getName());
- if (result == null) {
- try {
- final Field field = type.getDeclaredField("serialPersistentFields");
- if ((field.getModifiers() & PERSISTENT_FIELDS_MODIFIER) == PERSISTENT_FIELDS_MODIFIER) {
- field.setAccessible(true);
- final ObjectStreamField[] fields = (ObjectStreamField[])field.get(null);
- if (fields != null) {
- result = new HashMap();
- for (int i = 0; i < fields.length; ++i) {
- result.put(fields[i].getName(), fields[i]);
- }
- }
- }
- } catch (final NoSuchFieldException e) {
- } catch (final IllegalAccessException e) {
- throw new ObjectAccessException("Cannot get " + type.getName() + ".serialPersistentFields.", e);
- } catch (final ClassCastException e) {
- throw new ObjectAccessException("Cannot get " + type.getName() + ".serialPersistentFields.", e);
- }
- if (result == null) {
- result = NO_FIELDS;
- }
- fieldCache.put(type.getName(), result);
- }
- return result == NO_FIELDS ? null : result;
- }
-
+ /**
+ * @deprecated As of upcoming, moved into internal util package.
+ */
public void flushCache() {
- declaredCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
- resRepCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+ serializationMembers.flushCache();
}
}
Copied: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java (from rev 2333, trunk/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java) (0 => 2334)
--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java (rev 0)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java 2015-02-15 02:37:22 UTC (rev 2334)
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2004, 2005 Joe Walnes.
+ * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2014, 2015 XStream Committers.
+ * All rights reserved.
+ *
+ * The software in this package is published under 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 2015 by Joerg Schaible, copied from c.t.x.converters.reflection.SerializationMemberInvoker.
+ */
+package com.thoughtworks.xstream.core.util;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import com.thoughtworks.xstream.converters.ConversionException;
+import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
+import com.thoughtworks.xstream.core.Caching;
+
+
+/**
+ * Convenience wrapper to invoke special serialization methods on objects (and perform reflection caching).
+ *
+ * @author Joe Walnes
+ * @author Jörg Schaible
+ */
+public class SerializationMembers implements Caching {
+
+ private static final Method NO_METHOD = (new Object() {
+ private void noMethod() {
+ }
+ }).getClass().getDeclaredMethods()[0];
+ private static final Object[] EMPTY_ARGS = new Object[0];
+ private static final Class[] EMPTY_CLASSES = new Class[0];
+ private static final Map NO_FIELDS = Collections.EMPTY_MAP;
+ private static final int PERSISTENT_FIELDS_MODIFIER = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
+ private static final FastField[] OBJECT_TYPE_FIELDS = {
+ new FastField(Object.class, "readResolve"),
+ new FastField(Object.class, "writeReplace"),
+ new FastField(Object.class, "readObject"),
+ new FastField(Object.class, "writeObject")
+ };
+ private Map declaredCache = Collections.synchronizedMap(new HashMap());
+ private Map resRepCache = Collections.synchronizedMap(new HashMap());
+ private final Map fieldCache = Collections.synchronizedMap(new HashMap());
+ {
+ for(int i = 0; i < OBJECT_TYPE_FIELDS.length; ++i) {
+ declaredCache.put(OBJECT_TYPE_FIELDS[i], NO_METHOD);
+ }
+ for(int i = 0; i < 2; ++i) {
+ resRepCache.put(OBJECT_TYPE_FIELDS[i], NO_METHOD);
+ }
+ }
+
+ /**
+ * Resolves an object as native serialization does by calling readResolve(), if available.
+ */
+ public Object callReadResolve(final Object result) {
+ if (result == null) {
+ return null;
+ } else {
+ final Class resultType = result.getClass();
+ final Method readResolveMethod = getRRMethod(resultType, "readResolve");
+ if (readResolveMethod != null) {
+ try {
+ return readResolveMethod.invoke(result, EMPTY_ARGS);
+ } catch (IllegalAccessException e) {
+ throw new ObjectAccessException("Could not call "
+ + resultType.getName()
+ + ".readResolve()", e);
+ } catch (InvocationTargetException e) {
+ throw new ObjectAccessException("Could not call "
+ + resultType.getName()
+ + ".readResolve()", e.getTargetException());
+ }
+ } else {
+ return result;
+ }
+ }
+ }
+
+ public Object callWriteReplace(final Object object) {
+ if (object == null) {
+ return null;
+ } else {
+ final Class objectType = object.getClass();
+ final Method writeReplaceMethod = getRRMethod(objectType, "writeReplace");
+ if (writeReplaceMethod != null) {
+ try {
+ return writeReplaceMethod.invoke(object, EMPTY_ARGS);
+ } catch (IllegalAccessException e) {
+ throw new ObjectAccessException("Could not call "
+ + objectType.getName()
+ + ".writeReplace()", e);
+ } catch (InvocationTargetException e) {
+ throw new ObjectAccessException("Could not call "
+ + objectType.getName()
+ + ".writeReplace()", e.getTargetException());
+ }
+ } else {
+ return object;
+ }
+ }
+ }
+
+ public boolean supportsReadObject(final Class type, final boolean includeBaseClasses) {
+ return getMethod(
+ type, "readObject", new Class[]{ObjectInputStream.class}, includeBaseClasses) != null;
+ }
+
+ 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) {
+ 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.getTargetException());
+ }
+ }
+
+ public boolean supportsWriteObject(final Class type, final boolean includeBaseClasses) {
+ return getMethod(
+ type, "writeObject", new Class[]{ObjectOutputStream.class}, includeBaseClasses) != null;
+ }
+
+ 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) {
+ 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.getTargetException());
+ }
+ }
+
+ private Method getMethod(Class type, String name, Class[] parameterTypes,
+ boolean includeBaseclasses) {
+ Method method = getMethod(type, name, parameterTypes);
+ return method == NO_METHOD
+ || (!includeBaseclasses && !method.getDeclaringClass().equals(type))
+ ? null
+ : method;
+ }
+
+ private Method getMethod(Class type, String name, Class[] parameterTypes) {
+ if (type == null) {
+ return null;
+ }
+ FastField method = new FastField(type, name);
+ Method result = (Method)declaredCache.get(method);
+ if (result == null) {
+ try {
+ result = type.getDeclaredMethod(name, parameterTypes);
+ if (!result.isAccessible()) {
+ result.setAccessible(true);
+ }
+ } catch (NoSuchMethodException e) {
+ result = getMethod(type.getSuperclass(), name, parameterTypes);
+ }
+ declaredCache.put(method, result);
+ }
+ return result;
+ }
+
+ private Method getRRMethod(final Class type, final String name) {
+ final FastField method = new FastField(type, name);
+ Method result = (Method)resRepCache.get(method);
+ if (result == null) {
+ result = getMethod(type, name, EMPTY_CLASSES, true);
+ if (result != null && result.getDeclaringClass() != type) {
+ if ((result.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0) {
+ if ((result.getModifiers() & Modifier.PRIVATE) > 0
+ || type.getPackage() != result.getDeclaringClass().getPackage()) {
+ result = NO_METHOD;
+ }
+ }
+ } else if (result == null) {
+ result = NO_METHOD;
+ }
+ resRepCache.put(method, result);
+ }
+ return result == NO_METHOD ? null : result;
+ }
+
+ public Map getSerializablePersistentFields(final Class type) {
+ if (type == null) {
+ return null;
+ }
+ Map result = (Map)fieldCache.get(type.getName());
+ if (result == null) {
+ try {
+ final Field field = type.getDeclaredField("serialPersistentFields");
+ if ((field.getModifiers() & PERSISTENT_FIELDS_MODIFIER) == PERSISTENT_FIELDS_MODIFIER) {
+ field.setAccessible(true);
+ final ObjectStreamField[] fields = (ObjectStreamField[])field.get(null);
+ if (fields != null) {
+ result = new HashMap();
+ for (int i = 0; i < fields.length; ++i) {
+ result.put(fields[i].getName(), fields[i]);
+ }
+ }
+ }
+ } catch (final NoSuchFieldException e) {
+ } catch (final IllegalAccessException e) {
+ throw new ObjectAccessException("Cannot get " + type.getName() + ".serialPersistentFields.", e);
+ } catch (final ClassCastException e) {
+ throw new ObjectAccessException("Cannot get " + type.getName() + ".serialPersistentFields.", e);
+ }
+ if (result == null) {
+ result = NO_FIELDS;
+ }
+ fieldCache.put(type.getName(), result);
+ }
+ return result == NO_FIELDS ? null : result;
+ }
+
+ public void flushCache() {
+ declaredCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+ resRepCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+ }
+}
Modified: branches/v-1.4.x/xstream-distribution/src/content/changes.html (2333 => 2334)
--- branches/v-1.4.x/xstream-distribution/src/content/changes.html 2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream-distribution/src/content/changes.html 2015-02-15 02:37:22 UTC (rev 2334)
@@ -61,6 +61,7 @@
<li>c.t.x.converters.reflection.AbstractReflectionConverter.readResolve() is protected now.</li>
<li>c.t.x.mapper.AbstractAttributeAliasingMapper.readResolve() is protected now.</li>
<li>Deprecated c.t.x.converters.extended.StackTraceElementFactory, it is an internal helper class.</li>
+ <li>Deprecated c.t.x.converters.reflection.SerializationMethodInvoker, it is an internal helper class.</li>
<li>Deprecated c.t.x.io.AttributeNameIterator, it is an internal helper class.</li>
<li>Deprecated c.t.x.XStream.useXStream11XmlFriendlyMapper(), corresponding
c.t.x.mapper.XStream11XmlFriendlyMapper has been deprecated long ago.</li>
To unsubscribe from this list please visit:
