Christian Danner created XSTR-690:
-------------------------------------
Summary: Broken deserialization of singleton references using
custom readResolve method returning null
Key: XSTR-690
URL: https://jira.codehaus.org/browse/XSTR-690
Project: XStream
Issue Type: Bug
Components: Converters
Affects Versions: 1.3.1
Reporter: Christian Danner
Assignee: Joerg Schaible
Attachments: corruptSerializationTest.xml
We have our own abstract Enum base class implementation for which a custom
readResolve method has been implemented that ensures that singleton instances
are returned upon deserialization (with our without XStream) that looks like
this:
public Object readResolve() throws java.io.ObjectStreamException {
try {
Class clazz = getClassWithFields();
Field f = clazz.getField(_fieldName);
return f.get(null);
} catch (NoSuchFieldException ex) {
return null;
}
}
Additionally according readObject and writeObject implementations ensure that
the name of the Enum field is (de)serialized:
private void readObject(java.io.ObjectInputStream in) throws
java.io.IOException {
try {
_fieldName = (String) in.readObject();
} catch (ClassNotFoundException ex) {
throw new java.io.IOException(ex.getMessage(), ex);
}
}
Now instead of throwing an Exception in case a value is being read that is not
yet available (in case a newer file is being read by an application using an
older Enum implementation where the field is not available) we want to
initialize such missing Enum values with null - hence null is returned in case
the field with the deserialized name cannot be found in readResolve.
XStream does currently not support this because the
AbstractReferenceUnmarshaller does not cache null values (line 63):
result = super.convert(parent, type, converter);
if (currentReferenceKey != null && result != null) {
values.put(currentReferenceKey, result);
}
What's making things worse is that the AbstractReflectionConverter (line 165)
calls readResolve after the Object that has been created by default
deserialization has already been cached:
public Object unmarshal(final HierarchicalStreamReader reader, final
UnmarshallingContext context) {
Object result = instantiateNewInstance(reader, context);
// after this call the Object returned by readObject has been cached:
result = doUnmarshal(result, reader, context);
return serializationMethodInvoker.callReadResolve(result);
}
So in case multiple references to the Enum singleton are stored in a file the
behaviour is as follows:
* Upon first deserialization null is returned (as desired) because readResolve
is called
* For all successive references the cached Object deserialized using
readObject() is returned
The attached .xml file contains an ArrayList with multiple Objects referencing
such a (non-existing) Enum value.
While this may seem like a very specific use case it makes me wonder if missing
support for null return values in readResolve implementations is really desired.
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators:
https://jira.codehaus.org/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira
<hr/>
<p>
To unsubscribe from this list please visit:
</p>
<p>
<a
href="http://xircles.codehaus.org/manage_email">http://xircles.codehaus.org/manage_email</a>
</p>