-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
BeanDeserializer assigns the current value before walking the objects fields.
If the objects fields value is a nested object / collection the deserialiser invoked for these values follows the same pattern invoking setCurrentValue. Similairy any custom serialiser for a field may invoke setCurrentValue.
As the currentValue is not reset after deserialisng the nested object or collection. The parsers current value remains the value of traversed nested object or collection.
This is a issue for any custom serializer which might invoke the getCurrentValue as the value is now out of sync with the currentContext and is pointing to some object outside its tree.
This pattern is used throughout BeanDeserializer and CollectionDeserializer and from the comments introduced via ticket: #631
This is present in the current release 2.9.2
/**
* Streamlined version that is only used when no "special"
* features are enabled.
*/
private final Object vanillaDeserialize(JsonParser p,
DeserializationContext ctxt, JsonToken t)
throws IOException
{
final Object bean = _valueInstantiator.createUsingDefault(ctxt);
// [databind#631]: Assign current value, to be accessible by custom serializers
p.setCurrentValue(bean);
if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
String propName = p.getCurrentName();
do {
p.nextToken();
SettableBeanProperty prop = _beanProperties.find(propName);
if (prop != null) { // normal case
try {
prop.deserializeAndSet(p, ctxt, bean);
} catch (Exception e) {
wrapAndThrow(e, bean, propName, ctxt);
}
continue;
}
handleUnknownVanilla(p, ctxt, bean, propName);
} while ((propName = p.nextFieldName()) != null);
}
return bean;
}
Example scenario vanillaDeserialize sets the current value as the object walking(ObjA), the field to serialise is an empty ArrayList the deserialiser invoked for example is CollectionDeserializer which follows this patten and sets the current value in the parser as the ArrayList.
CollectionDeserializer returns setting the value of the field in ObjA to the deserialised ArrayList but the parsers current value remains as the ArrayList.
Fix would be in all deserialisers following this pattern to save a reference to the previousValue and before exiting reset the currentValue
@Override
public Collection<Object> deserialize(JsonParser p, DeserializationContext ctxt,
Collection<Object> result)
throws IOException
{
// Ok: must point to START_ARRAY (or equivalent)
if (!p.isExpectedStartArrayToken()) {
return handleNonArray(p, ctxt, result);
}
Object prevVal = p.getCurrentValue(); // Keep reference to parents value
p.setCurrentValue(result);
JsonDeserializer<Object> valueDes = _valueDeserializer;
final TypeDeserializer typeDeser = _valueTypeDeserializer;
CollectionReferringAccumulator referringAccumulator =
(valueDes.getObjectIdReader() == null) ? null :
new CollectionReferringAccumulator(_containerType.getContentType().getRawClass(), result);
JsonToken t;
while ((t = p.nextToken()) != JsonToken.END_ARRAY) {
// Process elements
}
p.setCurrentValue(prevValue); // reset value to the parent before returning to it
return result;
}