Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ public abstract class BeanDeserializerBase
* to be used for deserializing from JSON Object.
*/
protected JsonDeserializer<Object> _delegateDeserializer;

/**
* Deserializer that is used iff array-delegate-based creator
* is to be used for deserializing from JSON Object.
*/
protected JsonDeserializer<Object> _arrayDelegateDeserializer;

/**
* If the bean needs to be instantiated using constructor
Expand Down Expand Up @@ -526,22 +532,20 @@ public void resolve(DeserializationContext ctxt)
+": value instantiator ("+_valueInstantiator.getClass().getName()
+") returned true for 'canCreateUsingDelegate()', but null for 'getDelegateType()'");
}
AnnotatedWithParams delegateCreator = _valueInstantiator.getDelegateCreator();
// Need to create a temporary property to allow contextual deserializers:
BeanProperty.Std property = new BeanProperty.Std(TEMP_PROPERTY_NAME,
delegateType, null, _classAnnotations, delegateCreator,
PropertyMetadata.STD_OPTIONAL);

TypeDeserializer td = delegateType.getTypeHandler();
if (td == null) {
td = ctxt.getConfig().findTypeDeserializer(delegateType);
}
JsonDeserializer<Object> dd = findDeserializer(ctxt, delegateType, property);
if (td != null) {
td = td.forProperty(property);
dd = new TypeWrappedDeserializer(td, dd);
_delegateDeserializer = _findDelegateDeserializer(ctxt, delegateType,
_valueInstantiator.getDelegateCreator());
}

// and array-delegate-based constructor:
if (_valueInstantiator.canCreateUsingArrayDelegate()) {
JavaType delegateType = _valueInstantiator.getArrayDelegateType(ctxt.getConfig());
if (delegateType == null) {
throw new IllegalArgumentException("Invalid array-delegate-creator definition for "+_beanType
+": value instantiator ("+_valueInstantiator.getClass().getName()
+") returned true for 'canCreateUsingArrayDelegate()', but null for 'getArrayDelegateType()'");
}
_delegateDeserializer = dd;
_arrayDelegateDeserializer = _findDelegateDeserializer(ctxt, delegateType,
_valueInstantiator.getArrayDelegateCreator());
}

// And now that we know CreatorProperty instances are also resolved can finally create the creator:
Expand All @@ -564,6 +568,26 @@ public void resolve(DeserializationContext ctxt)
_vanillaProcessing = _vanillaProcessing && !_nonStandardCreation;
}

private JsonDeserializer<Object> _findDelegateDeserializer(DeserializationContext ctxt, JavaType delegateType,
AnnotatedWithParams delegateCreator) throws JsonMappingException {
// Need to create a temporary property to allow contextual deserializers:
BeanProperty.Std property = new BeanProperty.Std(TEMP_PROPERTY_NAME,
delegateType, null, _classAnnotations, delegateCreator,
PropertyMetadata.STD_OPTIONAL);

TypeDeserializer td = delegateType.getTypeHandler();
if (td == null) {
td = ctxt.getConfig().findTypeDeserializer(delegateType);
}
JsonDeserializer<Object> dd = findDeserializer(ctxt, delegateType, property);
if (td != null) {
td = td.forProperty(property);
return new TypeWrappedDeserializer(td, dd);
}
return dd;
}


/**
* Helper method that can be used to see if specified property is annotated
* to indicate use of a converter for property value (in case of container types,
Expand Down Expand Up @@ -1223,6 +1247,18 @@ public Object deserializeFromBoolean(JsonParser p, DeserializationContext ctxt)

public Object deserializeFromArray(JsonParser p, DeserializationContext ctxt) throws IOException
{
if (_arrayDelegateDeserializer != null) {
try {
Object bean = _valueInstantiator.createUsingArrayDelegate(ctxt, _arrayDelegateDeserializer.deserialize(p, ctxt));
if (_injectables != null) {
injectValues(ctxt, bean);
}
return bean;
} catch (Exception e) {
wrapInstantiationProblem(e, ctxt);
}
}
// fallback to non-array delegate
if (_delegateDeserializer != null) {
try {
Object bean = _valueInstantiator.createUsingArrayDelegate(ctxt, _delegateDeserializer.deserialize(p, ctxt));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ public boolean canInstantiate() {
*/
public boolean canCreateUsingDelegate() { return false; }

/**
* Method that can be called to check whether a array-delegate-based creator
* (single-arg constructor or factory method)
* is available for this instantiator
*/
public boolean canCreateUsingArrayDelegate() { return false; }

/**
* Method that can be called to check whether a property-based creator
* (argument-taking constructor or factory method)
Expand Down Expand Up @@ -127,6 +134,15 @@ public SettableBeanProperty[] getFromObjectArguments(DeserializationConfig confi
* pass that to instantiator.
*/
public JavaType getDelegateType(DeserializationConfig config) { return null; }

/**
* Method that can be used to determine what is the type of array delegate
* type to use, if any; if no delegates are used, will return null. If
* non-null type is returned, deserializer will bind JSON into specified
* type (using standard deserializer for that type), and pass that to
* instantiator.
*/
public JavaType getArrayDelegateType(DeserializationConfig config) { return null; }

/*
/**********************************************************
Expand Down Expand Up @@ -239,6 +255,16 @@ public Object createFromBoolean(DeserializationContext ctxt, boolean value) thro
*/
public AnnotatedWithParams getDelegateCreator() { return null; }

/**
* Method that can be called to try to access member (constructor,
* static factory method) that is used as the "array delegate creator".
* Note that implementations not required to return actual object
* they use (or, they may use some other instantiation) method.
* That is, even if {@link #canCreateUsingArrayDelegate()} returns true,
* this method may return null .
*/
public AnnotatedWithParams getArrayDelegateCreator() { return null; }

/**
* Method that can be called to try to access member (constructor,
* static factory method) that is used as the "non-default creator"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ public boolean canCreateUsingDefault() {
public boolean canCreateUsingDelegate() {
return _delegateType != null;
}

@Override
public boolean canCreateUsingArrayDelegate() {
return _arrayDelegateType != null;
}

@Override
public boolean canCreateFromObjectWith() {
Expand All @@ -212,6 +217,11 @@ public JavaType getDelegateType(DeserializationConfig config) {
return _delegateType;
}

@Override
public JavaType getArrayDelegateType(DeserializationConfig config) {
return _arrayDelegateType;
}

@Override
public SettableBeanProperty[] getFromObjectArguments(DeserializationConfig config) {
return _constructorArguments;
Expand Down Expand Up @@ -359,6 +369,11 @@ public AnnotatedWithParams getDelegateCreator() {
return _delegateCreator;
}

@Override
public AnnotatedWithParams getArrayDelegateCreator() {
return _arrayDelegateCreator;
}

@Override
public AnnotatedWithParams getDefaultCreator() {
return _defaultCreator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,22 @@

public class TestObjectOrArrayDeserialization extends BaseMapTest
{
public static class SomeObject {
public String someField;
}

public static class ArrayOrObject {
private final List<Object> objects;
private final Object object;
private final List<SomeObject> objects;
private final SomeObject object;

@JsonCreator
public ArrayOrObject(List<Object> objects) {
public ArrayOrObject(List<SomeObject> objects) {
this.objects = objects;
this.object = null;
}

@JsonCreator
public ArrayOrObject(Object object) {
public ArrayOrObject(SomeObject object) {
this.objects = null;
this.object = object;
}
Expand All @@ -45,4 +48,5 @@ public void testNotEmptyArrayCase() throws Exception {
assertEquals("expected objects field to have size 2", 2, arrayOrObject.objects.size());
assertNull("expected object field to be null", arrayOrObject.object);
}

}