Log Message
Private method readResolve() called on base classes (XSTR-762). Fix XStream classes depending on that buggy behavior.
Modified Paths
- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java
- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java
- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java
- trunk/xstream/src/java/com/thoughtworks/xstream/mapper/AbstractAttributeAliasingMapper.java
- trunk/xstream/src/test/com/thoughtworks/acceptance/AbstractReferenceTest.java
- trunk/xstream/src/test/com/thoughtworks/acceptance/SerializationCallbackOrderTest.java
- trunk/xstream-distribution/src/content/changes.html
Diff
Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java (2300 => 2301)
--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java 2014-10-02 18:00:26 UTC (rev 2300)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java 2014-10-30 12:58:59 UTC (rev 2301)
@@ -53,7 +53,7 @@
public AbstractReflectionConverter(final Mapper mapper, final ReflectionProvider reflectionProvider) {
this.mapper = mapper;
this.reflectionProvider = reflectionProvider;
- init();
+ serializationMethodInvoker = new SerializationMethodInvoker();
}
protected boolean canAccess(final Class<?> type) {
@@ -532,12 +532,8 @@
serializationMethodInvoker.flushCache();
}
- protected void init() {
+ protected Object readResolve() {
serializationMethodInvoker = new SerializationMethodInvoker();
- }
-
- private Object readResolve() {
- init();
return this;
}
Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java (2300 => 2301)
--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java 2014-10-02 18:00:26 UTC (rev 2300)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java 2014-10-30 12:58:59 UTC (rev 2301)
@@ -435,8 +435,9 @@
return typeHierarchy;
}
- private Object readResolve() {
- init();
+ @Override
+ protected Object readResolve() {
+ super.readResolve();
fieldCache = new HashMap<String, List<Field>>();
return this;
}
Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java (2300 => 2301)
--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java 2014-10-02 18:00:26 UTC (rev 2300)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java 2014-10-30 12:58:59 UTC (rev 2301)
@@ -6,7 +6,7 @@
* The software in this package is published under 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;
@@ -15,10 +15,11 @@
import java.io.ObjectOutputStream;
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.core.Caching;
@@ -27,7 +28,7 @@
/**
* Convenience wrapper to invoke special serialization methods on objects (and perform reflection caching).
- *
+ *
* @author Joe Walnes
* @author Jörg Schaible
*/
@@ -38,14 +39,20 @@
private void noMethod() {
}
}.getClass().getDeclaredMethods()[0];
- private static final FastField[] OBJECT_TYPE_FIELDS = new FastField[]{
+ 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 final Map<FastField, Method> cache = Collections.synchronizedMap(new HashMap<FastField, Method>());
+ private final ConcurrentMap<FastField, Method> declaredCache = new ConcurrentHashMap<FastField, Method>(
+ new HashMap<FastField, Method>());
+ private final ConcurrentMap<FastField, Method> resRepCache = new ConcurrentHashMap<FastField, Method>(
+ new HashMap<FastField, Method>());
{
for (final FastField element : OBJECT_TYPE_FIELDS) {
- cache.put(element, NO_METHOD);
+ declaredCache.put(element, NO_METHOD);
}
+ for (final FastField element : Arrays.copyOf(OBJECT_TYPE_FIELDS, 2)) {
+ resRepCache.put(element, NO_METHOD);
+ }
}
/**
@@ -55,16 +62,16 @@
if (result == null) {
return null;
} else {
- final Method readResolveMethod = getMethod(result.getClass(), "readResolve", true);
+ final Class<? extends Object> resultType = result.getClass();
+ final Method readResolveMethod = getRRMethod(resultType, "readResolve");
if (readResolveMethod != null) {
try {
return readResolveMethod.invoke(result);
} catch (final IllegalAccessException e) {
- throw new ObjectAccessException("Could not call " + result.getClass().getName() + ".readResolve()",
- e);
+ throw new ObjectAccessException("Could not call " + resultType.getName() + ".readResolve()", e);
} catch (final InvocationTargetException e) {
- throw new ObjectAccessException("Could not call " + result.getClass().getName() + ".readResolve()",
- e.getTargetException());
+ throw new ObjectAccessException("Could not call " + resultType.getName() + ".readResolve()", e
+ .getTargetException());
}
} else {
return result;
@@ -76,16 +83,16 @@
if (object == null) {
return null;
} else {
- final Method writeReplaceMethod = getMethod(object.getClass(), "writeReplace", true);
+ final Class<? extends Object> objectType = object.getClass();
+ final Method writeReplaceMethod = getRRMethod(objectType, "writeReplace");
if (writeReplaceMethod != null) {
try {
return writeReplaceMethod.invoke(object);
} catch (final IllegalAccessException e) {
- throw new ObjectAccessException(
- "Could not call " + object.getClass().getName() + ".writeReplace()", e);
+ throw new ObjectAccessException("Could not call " + objectType.getName() + ".writeReplace()", e);
} catch (final InvocationTargetException e) {
- throw new ObjectAccessException(
- "Could not call " + object.getClass().getName() + ".writeReplace()", e.getTargetException());
+ throw new ObjectAccessException("Could not call " + objectType.getName() + ".writeReplace()", e
+ .getTargetException());
}
} else {
return object;
@@ -136,7 +143,7 @@
return null;
}
final FastField method = new FastField(type, name);
- Method result = cache.get(method);
+ Method result = declaredCache.get(method);
if (result == null) {
try {
@@ -147,13 +154,34 @@
} catch (final NoSuchMethodException e) {
result = getMethod(type.getSuperclass(), name, parameterTypes);
}
- cache.put(method, result);
+ declaredCache.put(method, result);
}
return result;
}
+ private Method getRRMethod(final Class<?> type, final String name) {
+ final FastField method = new FastField(type, name);
+ Method result = resRepCache.get(method);
+ if (result == null) {
+ result = getMethod(type, name, 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.putIfAbsent(method, result);
+ }
+ return result == NO_METHOD ? null : result;
+ }
+
@Override
public void flushCache() {
- cache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+ declaredCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+ resRepCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
}
}
Modified: trunk/xstream/src/java/com/thoughtworks/xstream/mapper/AbstractAttributeAliasingMapper.java (2300 => 2301)
--- trunk/xstream/src/java/com/thoughtworks/xstream/mapper/AbstractAttributeAliasingMapper.java 2014-10-02 18:00:26 UTC (rev 2300)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/mapper/AbstractAttributeAliasingMapper.java 2014-10-30 12:58:59 UTC (rev 2301)
@@ -34,7 +34,7 @@
nameToAlias.put(attributeName, alias);
}
- private Object readResolve() {
+ Object readResolve() {
nameToAlias = new HashMap<String, String>();
for (final Map.Entry<String, String> entry : aliasToName.entrySet()) {
nameToAlias.put(entry.getValue(), entry.getKey());
Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/AbstractReferenceTest.java (2300 => 2301)
--- trunk/xstream/src/test/com/thoughtworks/acceptance/AbstractReferenceTest.java 2014-10-02 18:00:26 UTC (rev 2300)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/AbstractReferenceTest.java 2014-10-30 12:58:59 UTC (rev 2301)
@@ -397,7 +397,7 @@
return true;
}
- private Object writeReplace() {
+ protected Object writeReplace() {
if (getClass() == TreeData.class) {
return this;
}
Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/SerializationCallbackOrderTest.java (2300 => 2301)
--- trunk/xstream/src/test/com/thoughtworks/acceptance/SerializationCallbackOrderTest.java 2014-10-02 18:00:26 UTC (rev 2300)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/SerializationCallbackOrderTest.java 2014-10-30 12:58:59 UTC (rev 2301)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2005 Joe Walnes.
- * Copyright (C) 2006, 2007 XStream Committers.
+ * Copyright (C) 2006, 2007, 2014 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
@@ -26,64 +26,214 @@
// static so it can be accessed by objects under test, without them needing a reference back to the testcase
private static CallLog log = new CallLog();
+ @Override
protected void setUp() throws Exception {
super.setUp();
log.reset();
}
- // --- Sample class hiearchy
+ // --- Sample class hierarchy
- public static class Base implements Serializable{
+ public static class PrivateBase implements Serializable{
private void writeObject(ObjectOutputStream out) throws IOException {
- log.actual("Base.writeObject() start");
+ log.actual("PrivateBase.writeObject() start");
out.defaultWriteObject();
- log.actual("Base.writeObject() end");
+ log.actual("PrivateBase.writeObject() end");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
- log.actual("Base.readObject() start");
+ log.actual("PrivateBase.readObject() start");
in.defaultReadObject();
- log.actual("Base.readObject() end");
+ log.actual("PrivateBase.readObject() end");
}
private Object writeReplace() {
- log.actual("Base.writeReplace()");
+ log.actual("PrivateBase.writeReplace()");
return this;
}
private Object readResolve() {
- log.actual("Base.readResolve()");
+ log.actual("PrivateBase.readResolve()");
return this;
}
}
- public static class Child extends Base implements Serializable{
+ public static class PrivateChildOwnRR extends PrivateBase implements Serializable{
private void writeObject(ObjectOutputStream out) throws IOException {
- log.actual("Child.writeObject() start");
+ log.actual("PrivateChildOwnRR.writeObject() start");
out.defaultWriteObject();
- log.actual("Child.writeObject() end");
+ log.actual("PrivateChildOwnRR.writeObject() end");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
- log.actual("Child.readObject() start");
+ log.actual("PrivateChildOwnRR.readObject() start");
in.defaultReadObject();
- log.actual("Child.readObject() end");
+ log.actual("PrivateChildOwnRR.readObject() end");
}
private Object writeReplace() {
- log.actual("Child.writeReplace()");
+ log.actual("PrivateChildOwnRR.writeReplace()");
return this;
}
private Object readResolve() {
- log.actual("Child.readResolve()");
+ log.actual("PrivateChildOwnRR.readResolve()");
return this;
}
}
+ public static class PrivateChildNoRR extends PrivateBase implements Serializable{
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ log.actual("PrivateChildNoRR.writeObject() start");
+ out.defaultWriteObject();
+ log.actual("PrivateChildNoRR.writeObject() end");
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ log.actual("PrivateChildNoRR.readObject() start");
+ in.defaultReadObject();
+ log.actual("PrivateChildNoRR.readObject() end");
+ }
+ }
+
+ public static class ProtectedBase implements Serializable{
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ log.actual("ProtectedBase.writeObject() start");
+ out.defaultWriteObject();
+ log.actual("ProtectedBase.writeObject() end");
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ log.actual("ProtectedBase.readObject() start");
+ in.defaultReadObject();
+ log.actual("ProtectedBase.readObject() end");
+ }
+
+ protected Object writeReplace() {
+ log.actual("ProtectedBase.writeReplace()");
+ return this;
+ }
+
+ protected Object readResolve() {
+ log.actual("ProtectedBase.readResolve()");
+ return this;
+ }
+ }
+
+ public static class ProtectedChildOwnRR extends ProtectedBase implements Serializable{
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ log.actual("ProtectedChildOwnRR.writeObject() start");
+ out.defaultWriteObject();
+ log.actual("ProtectedChildOwnRR.writeObject() end");
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ log.actual("ProtectedChildOwnRR.readObject() start");
+ in.defaultReadObject();
+ log.actual("ProtectedChildOwnRR.readObject() end");
+ }
+
+ @Override
+ protected Object writeReplace() {
+ log.actual("ProtectedChildOwnRR.writeReplace()");
+ return this;
+ }
+
+ @Override
+ protected Object readResolve() {
+ log.actual("ProtectedChildOwnRR.readResolve()");
+ return this;
+ }
+ }
+
+ public static class ProtectedChildInheritedRR extends ProtectedBase implements Serializable{
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ log.actual("ProtectedChildInheritedRR.writeObject() start");
+ out.defaultWriteObject();
+ log.actual("ProtectedChildInheritedRR.writeObject() end");
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ log.actual("ProtectedChildInheritedRR.readObject() start");
+ in.defaultReadObject();
+ log.actual("ProtectedChildInheritedRR.readObject() end");
+ }
+ }
+
+ public static class PackageBase implements Serializable{
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ log.actual("PackageBase.writeObject() start");
+ out.defaultWriteObject();
+ log.actual("PackageBase.writeObject() end");
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ log.actual("PackageBase.readObject() start");
+ in.defaultReadObject();
+ log.actual("PackageBase.readObject() end");
+ }
+
+ Object writeReplace() {
+ log.actual("PackageBase.writeReplace()");
+ return this;
+ }
+
+ Object readResolve() {
+ log.actual("PackageBase.readResolve()");
+ return this;
+ }
+ }
+
+ public static class PackageChildOwnRR extends PackageBase implements Serializable{
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ log.actual("PackageChildOwnRR.writeObject() start");
+ out.defaultWriteObject();
+ log.actual("PackageChildOwnRR.writeObject() end");
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ log.actual("PackageChildOwnRR.readObject() start");
+ in.defaultReadObject();
+ log.actual("PackageChildOwnRR.readObject() end");
+ }
+
+ @Override
+ Object writeReplace() {
+ log.actual("PackageChildOwnRR.writeReplace()");
+ return this;
+ }
+
+ @Override
+ Object readResolve() {
+ log.actual("PackageChildOwnRR.readResolve()");
+ return this;
+ }
+ }
+
+ public static class PackageChildInheritedRR extends PackageBase implements Serializable{
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ log.actual("PackageChildInheritedRR.writeObject() start");
+ out.defaultWriteObject();
+ log.actual("PackageChildInheritedRR.writeObject() end");
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ log.actual("PackageChildInheritedRR.readObject() start");
+ in.defaultReadObject();
+ log.actual("PackageChildInheritedRR.readObject() end");
+ }
+ }
+
// --- Convenience wrappers around Java Object Serialization
private byte[] javaSerialize(Object object) throws IOException {
@@ -101,47 +251,195 @@
// --- Tests
- public void testJavaSerialization() throws IOException {
+ public void testJavaSerializationOwnPrivateRR() throws IOException {
// expectations
- log.expect("Child.writeReplace()");
- log.expect("Base.writeObject() start");
- log.expect("Base.writeObject() end");
- log.expect("Child.writeObject() start");
- log.expect("Child.writeObject() end");
+ log.expect("PrivateChildOwnRR.writeReplace()");
+ log.expect("PrivateBase.writeObject() start");
+ log.expect("PrivateBase.writeObject() end");
+ log.expect("PrivateChildOwnRR.writeObject() start");
+ log.expect("PrivateChildOwnRR.writeObject() end");
// execute
- javaSerialize(new Child());
+ javaSerialize(new PrivateChildOwnRR());
// verify
log.verify();
}
- public void testXStreamSerialization() {
+ public void testJavaSerializationNoRR() throws IOException {
// expectations
- log.expect("Child.writeReplace()");
- log.expect("Base.writeObject() start");
- log.expect("Base.writeObject() end");
- log.expect("Child.writeObject() start");
- log.expect("Child.writeObject() end");
+ log.expect("PrivateBase.writeObject() start");
+ log.expect("PrivateBase.writeObject() end");
+ log.expect("PrivateChildNoRR.writeObject() start");
+ log.expect("PrivateChildNoRR.writeObject() end");
// execute
- xstream.toXML(new Child());
+ javaSerialize(new PrivateChildNoRR());
// verify
log.verify();
}
- public void testJavaDeserialization() throws IOException, ClassNotFoundException {
+ public void testJavaSerializationOwnProtectedRR() throws IOException {
+ // expectations
+ log.expect("ProtectedChildOwnRR.writeReplace()");
+ log.expect("ProtectedBase.writeObject() start");
+ log.expect("ProtectedBase.writeObject() end");
+ log.expect("ProtectedChildOwnRR.writeObject() start");
+ log.expect("ProtectedChildOwnRR.writeObject() end");
+
+ // execute
+ javaSerialize(new ProtectedChildOwnRR());
+
+ // verify
+ log.verify();
+ }
+
+ public void testJavaSerializationInheritedRR() throws IOException {
+ // expectations
+ log.expect("ProtectedBase.writeReplace()");
+ log.expect("ProtectedBase.writeObject() start");
+ log.expect("ProtectedBase.writeObject() end");
+ log.expect("ProtectedChildInheritedRR.writeObject() start");
+ log.expect("ProtectedChildInheritedRR.writeObject() end");
+
+ // execute
+ javaSerialize(new ProtectedChildInheritedRR());
+
+ // verify
+ log.verify();
+ }
+
+ public void testJavaSerializationOwnPackageRR() throws IOException {
+ // expectations
+ log.expect("PackageChildOwnRR.writeReplace()");
+ log.expect("PackageBase.writeObject() start");
+ log.expect("PackageBase.writeObject() end");
+ log.expect("PackageChildOwnRR.writeObject() start");
+ log.expect("PackageChildOwnRR.writeObject() end");
+
+ // execute
+ javaSerialize(new PackageChildOwnRR());
+
+ // verify
+ log.verify();
+ }
+
+ public void testJavaSerializationInheritedPackageRR() throws IOException {
+ // expectations
+ log.expect("PackageBase.writeReplace()");
+ log.expect("PackageBase.writeObject() start");
+ log.expect("PackageBase.writeObject() end");
+ log.expect("PackageChildInheritedRR.writeObject() start");
+ log.expect("PackageChildInheritedRR.writeObject() end");
+
+ // execute
+ javaSerialize(new PackageChildInheritedRR());
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamSerializationOwnPrivateRR() {
+ // expectations
+ log.expect("PrivateChildOwnRR.writeReplace()");
+ log.expect("PrivateBase.writeObject() start");
+ log.expect("PrivateBase.writeObject() end");
+ log.expect("PrivateChildOwnRR.writeObject() start");
+ log.expect("PrivateChildOwnRR.writeObject() end");
+
+ // execute
+ xstream.toXML(new PrivateChildOwnRR());
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamSerializationNoRR() {
+ // expectations
+ log.expect("PrivateBase.writeObject() start");
+ log.expect("PrivateBase.writeObject() end");
+ log.expect("PrivateChildNoRR.writeObject() start");
+ log.expect("PrivateChildNoRR.writeObject() end");
+
+ // execute
+ xstream.toXML(new PrivateChildNoRR());
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamSerializationOwnProtectedRR() {
+ // expectations
+ log.expect("ProtectedChildOwnRR.writeReplace()");
+ log.expect("ProtectedBase.writeObject() start");
+ log.expect("ProtectedBase.writeObject() end");
+ log.expect("ProtectedChildOwnRR.writeObject() start");
+ log.expect("ProtectedChildOwnRR.writeObject() end");
+
+ // execute
+ xstream.toXML(new ProtectedChildOwnRR());
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamSerializationOwnInheritedRR() {
+ // expectations
+ log.expect("ProtectedBase.writeReplace()");
+ log.expect("ProtectedBase.writeObject() start");
+ log.expect("ProtectedBase.writeObject() end");
+ log.expect("ProtectedChildInheritedRR.writeObject() start");
+ log.expect("ProtectedChildInheritedRR.writeObject() end");
+
+ // execute
+ xstream.toXML(new ProtectedChildInheritedRR());
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamSerializationOwnPackageRR() {
+ // expectations
+ log.expect("PackageChildOwnRR.writeReplace()");
+ log.expect("PackageBase.writeObject() start");
+ log.expect("PackageBase.writeObject() end");
+ log.expect("PackageChildOwnRR.writeObject() start");
+ log.expect("PackageChildOwnRR.writeObject() end");
+
+ // execute
+ xstream.toXML(new PackageChildOwnRR());
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamSerializationOwnInheritedPackageRR() {
+ // expectations
+ log.expect("PackageBase.writeReplace()");
+ log.expect("PackageBase.writeObject() start");
+ log.expect("PackageBase.writeObject() end");
+ log.expect("PackageChildInheritedRR.writeObject() start");
+ log.expect("PackageChildInheritedRR.writeObject() end");
+
+ // execute
+ xstream.toXML(new PackageChildInheritedRR());
+
+ // verify
+ log.verify();
+ }
+
+ public void testJavaDeserializationOwnPrivateRR() throws IOException, ClassNotFoundException {
// setup
- byte[] data = "" Child());
+ byte[] data = "" PrivateChildOwnRR());
log.reset();
// expectations
- log.expect("Base.readObject() start");
- log.expect("Base.readObject() end");
- log.expect("Child.readObject() start");
- log.expect("Child.readObject() end");
- log.expect("Child.readResolve()");
+ log.expect("PrivateBase.readObject() start");
+ log.expect("PrivateBase.readObject() end");
+ log.expect("PrivateChildOwnRR.readObject() start");
+ log.expect("PrivateChildOwnRR.readObject() end");
+ log.expect("PrivateChildOwnRR.readResolve()");
// execute
javaDeserialize(data);
@@ -150,26 +448,213 @@
log.verify();
}
- public void testXStreamDeserialization() {
+ public void testJavaDeserializationNoRR() throws IOException, ClassNotFoundException {
// setup
- String data = "" Child());
+ byte[] data = "" PrivateChildNoRR());
log.reset();
// expectations
- log.expect("Base.readObject() start");
- log.expect("Base.readObject() end");
- log.expect("Child.readObject() start");
- log.expect("Child.readObject() end");
- log.expect("Child.readResolve()");
+ log.expect("PrivateBase.readObject() start");
+ log.expect("PrivateBase.readObject() end");
+ log.expect("PrivateChildNoRR.readObject() start");
+ log.expect("PrivateChildNoRR.readObject() end");
// execute
+ javaDeserialize(data);
+
+ // verify
+ log.verify();
+ }
+
+ public void testJavaDeserializationOwnProtectedRR() throws IOException, ClassNotFoundException {
+ // setup
+ byte[] data = "" ProtectedChildOwnRR());
+ log.reset();
+
+ // expectations
+ log.expect("ProtectedBase.readObject() start");
+ log.expect("ProtectedBase.readObject() end");
+ log.expect("ProtectedChildOwnRR.readObject() start");
+ log.expect("ProtectedChildOwnRR.readObject() end");
+ log.expect("ProtectedChildOwnRR.readResolve()");
+
+ // execute
+ javaDeserialize(data);
+
+ // verify
+ log.verify();
+ }
+
+ public void testJavaDeserializationInheritedRR() throws IOException, ClassNotFoundException {
+ // setup
+ byte[] data = "" ProtectedChildInheritedRR());
+ log.reset();
+
+ // expectations
+ log.expect("ProtectedBase.readObject() start");
+ log.expect("ProtectedBase.readObject() end");
+ log.expect("ProtectedChildInheritedRR.readObject() start");
+ log.expect("ProtectedChildInheritedRR.readObject() end");
+ log.expect("ProtectedBase.readResolve()");
+
+ // execute
+ javaDeserialize(data);
+
+ // verify
+ log.verify();
+ }
+
+ public void testJavaDeserializationOwnPackageRR() throws IOException, ClassNotFoundException {
+ // setup
+ byte[] data = "" PackageChildOwnRR());
+ log.reset();
+
+ // expectations
+ log.expect("PackageBase.readObject() start");
+ log.expect("PackageBase.readObject() end");
+ log.expect("PackageChildOwnRR.readObject() start");
+ log.expect("PackageChildOwnRR.readObject() end");
+ log.expect("PackageChildOwnRR.readResolve()");
+
+ // execute
+ javaDeserialize(data);
+
+ // verify
+ log.verify();
+ }
+
+ public void testJavaDeserializationInheritedPackageRR() throws IOException, ClassNotFoundException {
+ // setup
+ byte[] data = "" PackageChildInheritedRR());
+ log.reset();
+
+ // expectations
+ log.expect("PackageBase.readObject() start");
+ log.expect("PackageBase.readObject() end");
+ log.expect("PackageChildInheritedRR.readObject() start");
+ log.expect("PackageChildInheritedRR.readObject() end");
+ log.expect("PackageBase.readResolve()");
+
+ // execute
+ javaDeserialize(data);
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamDeserializationOwnPrivateRR() {
+ // setup
+ String data = "" PrivateChildOwnRR());
+ log.reset();
+
+ // expectations
+ log.expect("PrivateBase.readObject() start");
+ log.expect("PrivateBase.readObject() end");
+ log.expect("PrivateChildOwnRR.readObject() start");
+ log.expect("PrivateChildOwnRR.readObject() end");
+ log.expect("PrivateChildOwnRR.readResolve()");
+
+ // execute
xstream.fromXML(data);
// verify
log.verify();
}
+ public void testXStreamDeserializationNoRR() {
+ // setup
+ String data = "" PrivateChildNoRR());
+ log.reset();
+ // expectations
+ log.expect("PrivateBase.readObject() start");
+ log.expect("PrivateBase.readObject() end");
+ log.expect("PrivateChildNoRR.readObject() start");
+ log.expect("PrivateChildNoRR.readObject() end");
+
+ // execute
+ xstream.fromXML(data);
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamDeserializationOwnProtectedRR() {
+ // setup
+ String data = "" ProtectedChildOwnRR());
+ log.reset();
+
+ // expectations
+ log.expect("ProtectedBase.readObject() start");
+ log.expect("ProtectedBase.readObject() end");
+ log.expect("ProtectedChildOwnRR.readObject() start");
+ log.expect("ProtectedChildOwnRR.readObject() end");
+ log.expect("ProtectedChildOwnRR.readResolve()");
+
+ // execute
+ xstream.fromXML(data);
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamDeserializationInheritedRR() {
+ // setup
+ String data = "" ProtectedChildInheritedRR());
+ log.reset();
+
+ // expectations
+ log.expect("ProtectedBase.readObject() start");
+ log.expect("ProtectedBase.readObject() end");
+ log.expect("ProtectedChildInheritedRR.readObject() start");
+ log.expect("ProtectedChildInheritedRR.readObject() end");
+ log.expect("ProtectedBase.readResolve()");
+
+ // execute
+ xstream.fromXML(data);
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamDeserializationOwnPackageRR() {
+ // setup
+ String data = "" PackageChildOwnRR());
+ log.reset();
+
+ // expectations
+ log.expect("PackageBase.readObject() start");
+ log.expect("PackageBase.readObject() end");
+ log.expect("PackageChildOwnRR.readObject() start");
+ log.expect("PackageChildOwnRR.readObject() end");
+ log.expect("PackageChildOwnRR.readResolve()");
+
+ // execute
+ xstream.fromXML(data);
+
+ // verify
+ log.verify();
+ }
+
+ public void testXStreamDeserializationInheritedPackageRR() {
+ // setup
+ String data = "" PackageChildInheritedRR());
+ log.reset();
+
+ // expectations
+ log.expect("PackageBase.readObject() start");
+ log.expect("PackageBase.readObject() end");
+ log.expect("PackageChildInheritedRR.readObject() start");
+ log.expect("PackageChildInheritedRR.readObject() end");
+ log.expect("PackageBase.readResolve()");
+
+ // execute
+ xstream.fromXML(data);
+
+ // verify
+ log.verify();
+ }
+
public static class ParentNotTransient implements Serializable {
public int somethingNotTransient;
Modified: trunk/xstream-distribution/src/content/changes.html (2300 => 2301)
--- trunk/xstream-distribution/src/content/changes.html 2014-10-02 18:00:26 UTC (rev 2300)
+++ trunk/xstream-distribution/src/content/changes.html 2014-10-30 12:58:59 UTC (rev 2301)
@@ -60,6 +60,7 @@
<h2>Minor changes</h2>
<ul>
+ <li>XSTR-762: Private method readResolve() called on base classes.</li>
<li>XSTR-755: ExternalizableConverter does not respect writeReplace and readResolve.</li>
<li>XSTR-757: Deserialized TreeSet does not honor remove(Object) return value contract.</li>
<li>Fix: DateConverter ignores provided locale.</li>
@@ -71,6 +72,8 @@
<h2>API changes</h2>
<ul>
+ <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.io.AttributeNameIterator, it is an internal helper class.</li>
<li>Deprecated c.t.x.XStream.useXStream11XmlFriendlyMapper(), corresponding
To unsubscribe from this list please visit:
