Log Message
Support ignored serialPersistentField at deserialization time (XSTR-761).
Modified Paths
- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java
- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java
- trunk/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java
- trunk/xstream/src/test/com/thoughtworks/acceptance/CustomSerializationTest.java
- trunk/xstream-distribution/src/content/changes.html
Diff
Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java (2328 => 2329)
--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java 2015-02-11 23:57:37 UTC (rev 2328)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java 2015-02-12 22:40:06 UTC (rev 2329)
@@ -416,6 +416,10 @@
@Override
public void defaultReadObject() {
+ if (serializationMethodInvoker.getSerializablePersistentFields(currentType[0]) != null) {
+ readFieldsFromStream();
+ return;
+ }
if (!reader.hasMoreChildren()) {
return;
}
Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java (2328 => 2329)
--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java 2015-02-11 23:57:37 UTC (rev 2328)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java 2015-02-12 22:40:06 UTC (rev 2329)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2004, 2005 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2014 XStream Committers.
+ * 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
@@ -13,11 +13,15 @@
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;
@@ -39,13 +43,14 @@
private void noMethod() {
}
}.getClass().getDeclaredMethods()[0];
+ private static final Map<String, ObjectStreamField> NO_FIELDS = Collections.emptyMap();
+ 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 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>());
+ private final ConcurrentMap<FastField, Method> declaredCache = new ConcurrentHashMap<FastField, Method>();
+ private final ConcurrentMap<FastField, Method> resRepCache = new ConcurrentHashMap<FastField, Method>();
+ private final ConcurrentMap<String, Map<String, ObjectStreamField>> fieldCache = new ConcurrentHashMap<String, Map<String, ObjectStreamField>>();
{
for (final FastField element : OBJECT_TYPE_FIELDS) {
declaredCache.put(element, NO_METHOD);
@@ -179,6 +184,38 @@
return result == NO_METHOD ? null : result;
}
+ public Map<String, ObjectStreamField> getSerializablePersistentFields(final Class<?> type) {
+ if (type == null) {
+ return null;
+ }
+ Map<String, ObjectStreamField> result = 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<String, ObjectStreamField>();
+ for (final ObjectStreamField f : fields) {
+ result.put(f.getName(), f);
+ }
+ }
+ }
+ } 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.putIfAbsent(type.getName(), result);
+ }
+ return result == NO_FIELDS ? null : result;
+ }
+
@Override
public void flushCache() {
declaredCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java (2328 => 2329)
--- trunk/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java 2015-02-11 23:57:37 UTC (rev 2328)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java 2015-02-12 22:40:06 UTC (rev 2329)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 XStream Committers.
+ * Copyright (C) 2012, 2015 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
@@ -10,16 +10,20 @@
*/
package com.thoughtworks.acceptance;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import com.thoughtworks.xstream.core.JVM;
+
+
public class Concurrent15TypesTest extends AbstractAcceptanceTest {
-
+
public void testConcurrentHashMap() {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
map.put("walnes", "joe");
String xml = xstream.toXML(map);
- String expected =
- "<concurrent-hash-map>\n"
+ String expected = ""
+ + "<concurrent-hash-map>\n"
+ " <entry>\n"
+ " <string>walnes</string>\n"
+ " <string>joe</string>\n"
@@ -27,7 +31,36 @@
+ "</concurrent-hash-map>";
assertEquals(xml, expected);
@SuppressWarnings("unchecked")
- ConcurrentHashMap<String, String> out = (ConcurrentHashMap<String, String>) xstream.fromXML(xml);
+ ConcurrentHashMap<String, String> out = (ConcurrentHashMap<String, String>)xstream.fromXML(xml);
assertEquals("{walnes=joe}", out.toString());
}
+
+ public static class DerivedConcurrentHashMap extends ConcurrentHashMap<Object, Object> {
+ private static final long serialVersionUID = 1L;
+ }
+
+ public void testDerivedConcurrentHashMap() {
+ if (JVM.is18()) {
+ xstream.alias("derived-map", DerivedConcurrentHashMap.class);
+
+ Map<Object, Object> map = new DerivedConcurrentHashMap();
+ map.put("test", "JUnit");
+
+ String xml = ""
+ + "<derived-map serialization=\"custom\">\n"
+ + " <unserializable-parents/>\n"
+ + " <concurrent-hash-map>\n"
+ + " <default>\n"
+ + " <segmentMask>15</segmentMask>\n"
+ + " </default>\n"
+ + " <string>test</string>\n"
+ + " <string>JUnit</string>\n"
+ + " <null/>\n"
+ + " <null/>\n"
+ + " </concurrent-hash-map>\n"
+ + "</derived-map>";
+
+ assertBothWays(map, xml);
+ }
+ }
}
Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/CustomSerializationTest.java (2328 => 2329)
--- trunk/xstream/src/test/com/thoughtworks/acceptance/CustomSerializationTest.java 2015-02-11 23:57:37 UTC (rev 2328)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/CustomSerializationTest.java 2015-02-12 22:40:06 UTC (rev 2329)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2004, 2005 Joe Walnes.
- * Copyright (C) 2006, 2007 XStream Committers.
+ * Copyright (C) 2006, 2007, 2015 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
@@ -519,4 +519,42 @@
assertBothWays(input, expectedXml);
}
+
+ public static class ObjectThatWritesCustomFieldsButDoesNotReadThem extends StandardObject implements Serializable {
+
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("number", int.class),
+ new ObjectStreamField("name", String.class),
+ };
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ ObjectOutputStream.PutField fields = out.putFields();
+ fields.put("name", "test");
+ fields.put("number", 42);
+ out.writeFields();
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ }
+
+ }
+
+ public void testSupportsPutFieldsWithoutGetFields() {
+ xstream.alias("an-object", ObjectThatWritesCustomFieldsButDoesNotReadThem.class);
+
+ ObjectThatWritesCustomFieldsButDoesNotReadThem input = new ObjectThatWritesCustomFieldsButDoesNotReadThem();
+
+ String expectedXml = ""
+ + "<an-object serialization=\"custom\">\n"
+ + " <an-object>\n"
+ + " <default>\n"
+ + " <name>test</name>\n"
+ + " <number>42</number>\n"
+ + " </default>\n"
+ + " </an-object>\n"
+ + "</an-object>";
+
+ assertBothWays(input, expectedXml);
+ }
}
Modified: trunk/xstream-distribution/src/content/changes.html (2328 => 2329)
--- trunk/xstream-distribution/src/content/changes.html 2015-02-11 23:57:37 UTC (rev 2328)
+++ trunk/xstream-distribution/src/content/changes.html 2015-02-12 22:40:06 UTC (rev 2329)
@@ -67,6 +67,7 @@
<li>Detect Java 9 runtime.</li>
<li>XSTR-767: Deserialization of referenced lambda expressions fail.</li>
<li>XSTR-762: Private method readResolve() called on base classes.</li>
+ <li>XSTR-761: Support ignored serialPersistentField at deserialization time.</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>
To unsubscribe from this list please visit:
