Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -623,10 +623,10 @@ protected SettableBeanProperty constructCreatorProperty(DeserializationContext c
}

/**
* Helper method copied from {@code POJOPropertyBuilder} since that won't be
* applied to creator parameters.
* Helper method copied from {@code POJOPropertyBuilder} for synthetic
* properties that do not go through regular property collection.
*/
private PropertyMetadata _getSetterInfo(MapperConfig<?> config,
final PropertyMetadata _getSetterInfo(MapperConfig<?> config,
BeanProperty prop, PropertyMetadata metadata)
{
final AnnotationIntrospector intr = config.getAnnotationIntrospector();
Expand All @@ -635,8 +635,8 @@ private PropertyMetadata _getSetterInfo(MapperConfig<?> config,
Nulls valueNulls = null;
Nulls contentNulls = null;

// NOTE: compared to `POJOPropertyBuilder`, we only have access to creator
// parameter, not other accessors, so code bit simpler
// NOTE: compared to `POJOPropertyBuilder`, synthetic properties only
// have the primary member, not other accessors, so code bit simpler
AnnotatedMember prim = prop.getMember();

if (prim != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -877,9 +877,7 @@ protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
valueType = am.getParameterType(1);
// Need to resolve for possible generic types (like Maps, Collections)
valueType = resolveMemberAndTypeAnnotations(ctxt, mutator, valueType);
prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
valueType, null, mutator,
PropertyMetadata.STD_OPTIONAL);
prop = _constructAnySetterProperty(ctxt, mutator, valueType);

} else if (isField) {
AnnotatedField af = (AnnotatedField) mutator;
Expand All @@ -890,15 +888,13 @@ protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
fieldType = resolveMemberAndTypeAnnotations(ctxt, mutator, fieldType);
keyType = fieldType.getKeyType();
valueType = fieldType.getContentType();
prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
fieldType, null, mutator, PropertyMetadata.STD_OPTIONAL);
prop = _constructAnySetterProperty(ctxt, mutator, fieldType);
} else if (fieldType.hasRawClass(JsonNode.class)
|| fieldType.hasRawClass(ObjectNode.class)) {
fieldType = resolveMemberAndTypeAnnotations(ctxt, mutator, fieldType);
// Deserialize is individual values of ObjectNode, not full ObjectNode, so:
valueType = ctxt.constructType(JsonNode.class);
prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
fieldType, null, mutator, PropertyMetadata.STD_OPTIONAL);
prop = _constructAnySetterProperty(ctxt, mutator, fieldType);

// Unlike with more complicated types, here we do not allow any annotation
// overrides etc but instead short-cut handling:
Expand All @@ -919,14 +915,12 @@ protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
paramType = resolveMemberAndTypeAnnotations(ctxt, mutator, paramType);
keyType = paramType.getKeyType();
valueType = paramType.getContentType();
prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
paramType, null, mutator, PropertyMetadata.STD_OPTIONAL);
prop = _constructAnySetterProperty(ctxt, mutator, paramType);
} else if (paramType.hasRawClass(JsonNode.class) || paramType.hasRawClass(ObjectNode.class)) {
paramType = resolveMemberAndTypeAnnotations(ctxt, mutator, paramType);
// Deserialize is individual values of ObjectNode, not full ObjectNode, so:
valueType = ctxt.constructType(JsonNode.class);
prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
paramType, null, mutator, PropertyMetadata.STD_OPTIONAL);
prop = _constructAnySetterProperty(ctxt, mutator, paramType);

// Unlike with more complicated types, here we do not allow any annotation
// overrides etc but instead short-cut handling:
Expand Down Expand Up @@ -980,6 +974,19 @@ protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
prop, mutator, valueType, keyDeser, deser, typeDeser);
}

private BeanProperty.Std _constructAnySetterProperty(DeserializationContext ctxt,
AnnotatedMember mutator, JavaType propType)
{
PropertyName name = PropertyName.construct(mutator.getName());
BeanProperty.Std prop = new BeanProperty.Std(name, propType, null, mutator,
PropertyMetadata.STD_OPTIONAL);
PropertyMetadata metadata = _getSetterInfo(ctxt.getConfig(), prop, prop.getMetadata());
if (metadata != prop.getMetadata()) {
prop = new BeanProperty.Std(name, propType, null, mutator, metadata);
}
return prop;
}

/**
* Method that will construct a regular bean property setter using
* the given setter method.
Expand Down
136 changes: 126 additions & 10 deletions src/main/java/tools/jackson/databind/deser/SettableAnyProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import tools.jackson.core.*;
import tools.jackson.databind.*;
import tools.jackson.databind.deser.ReadableObjectId.Referring;
import tools.jackson.databind.deser.impl.NullsConstantProvider;
import tools.jackson.databind.deser.jdk.JDKValueInstantiators;
import tools.jackson.databind.introspect.AnnotatedField;
import tools.jackson.databind.introspect.AnnotatedMember;
Expand Down Expand Up @@ -44,6 +45,14 @@ public abstract class SettableAnyProperty
protected final TypeDeserializer _valueTypeDeserializer;
protected final KeyDeserializer _keyDeserializer;

/**
* Entity used for possible translation from explicit JSON {@code null}
* into non-null value, or for skipping the any-setter call.
*/
protected final NullValueProvider _nullProvider;

protected final boolean _skipNulls;

/*
/**********************************************************************
/* Life-cycle
Expand All @@ -53,6 +62,14 @@ public abstract class SettableAnyProperty
public SettableAnyProperty(BeanProperty property, AnnotatedMember setter, JavaType type,
KeyDeserializer keyDeser,
ValueDeserializer<Object> valueDeser, TypeDeserializer typeDeser)
{
this(property, setter, type, keyDeser, valueDeser, typeDeser, valueDeser);
}

protected SettableAnyProperty(BeanProperty property, AnnotatedMember setter, JavaType type,
KeyDeserializer keyDeser,
ValueDeserializer<Object> valueDeser, TypeDeserializer typeDeser,
NullValueProvider nullProvider)
{
_property = property;
_setter = setter;
Expand All @@ -61,6 +78,8 @@ public SettableAnyProperty(BeanProperty property, AnnotatedMember setter, JavaTy
_valueTypeDeserializer = typeDeser;
_keyDeserializer = keyDeser;
_setterIsField = setter instanceof AnnotatedField;
_nullProvider = nullProvider;
_skipNulls = NullsConstantProvider.isSkipper(nullProvider);
}

public static SettableAnyProperty constructForMethod(DeserializationContext ctxt,
Expand Down Expand Up @@ -127,6 +146,8 @@ public static SettableAnyProperty constructForJsonNodeParameter(DeserializationC
// Abstract @since 2.14
public abstract SettableAnyProperty withValueDeserializer(ValueDeserializer<Object> deser);

public abstract SettableAnyProperty withNullProvider(NullValueProvider nullProvider);

public void fixAccess(DeserializationConfig config) {
_setter.fixAccess(
config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
Expand All @@ -142,10 +163,16 @@ public void fixAccess(DeserializationConfig config) {

public boolean hasValueDeserializer() { return (_valueDeserializer != null); }

public ValueDeserializer<Object> getValueDeserializer() { return _valueDeserializer; }

public JavaType getType() { return _type; }

public String getPropertyName() { return _property.getName(); }

public boolean shouldSkipNullValue(JsonParser p) {
return _skipNulls && p.hasToken(JsonToken.VALUE_NULL);
}

/**
* Accessor for parameterIndex.
* @return -1 if not a parameterized setter, otherwise index of parameter
Expand Down Expand Up @@ -192,6 +219,9 @@ public void deserializeAndSet(JsonParser p, DeserializationContext ctxt,
throws JacksonException
{
try {
if (shouldSkipNullValue(p)) {
return;
}
Object key = (_keyDeserializer == null) ? propName
: _keyDeserializer.deserializeKey(propName, ctxt);
set(ctxt, instance, key, deserialize(p, ctxt));
Expand All @@ -209,7 +239,7 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws Jack
{
JsonToken t = p.currentToken();
if (t == JsonToken.VALUE_NULL) {
return _valueDeserializer.getNullValue(ctxt);
return _nullProvider.getNullValue(ctxt);
}
if (_valueTypeDeserializer != null) {
return _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer);
Expand Down Expand Up @@ -314,8 +344,16 @@ public MethodAnyProperty(BeanProperty property,
AnnotatedMember field, JavaType valueType,
KeyDeserializer keyDeser,
ValueDeserializer<Object> valueDeser, TypeDeserializer typeDeser) {
this(property, field, valueType, keyDeser, valueDeser, typeDeser, valueDeser);
}

protected MethodAnyProperty(BeanProperty property,
AnnotatedMember field, JavaType valueType,
KeyDeserializer keyDeser,
ValueDeserializer<Object> valueDeser, TypeDeserializer typeDeser,
NullValueProvider nullProvider) {
super(property, field, valueType,
keyDeser, valueDeser, typeDeser);
keyDeser, valueDeser, typeDeser, nullProvider);
}

@Override
Expand All @@ -328,8 +366,15 @@ protected void _set(DeserializationContext ctxt, Object instance, Object propNam

@Override
public SettableAnyProperty withValueDeserializer(ValueDeserializer<Object> deser) {
NullValueProvider nvp = (_valueDeserializer == _nullProvider) ? deser : _nullProvider;
return new MethodAnyProperty(_property, _setter, _type,
_keyDeserializer, deser, _valueTypeDeserializer, nvp);
}

@Override
public SettableAnyProperty withNullProvider(NullValueProvider nullProvider) {
return new MethodAnyProperty(_property, _setter, _type,
_keyDeserializer, deser, _valueTypeDeserializer);
_keyDeserializer, _valueDeserializer, _valueTypeDeserializer, nullProvider);
}
}

Expand All @@ -345,16 +390,32 @@ public MapFieldAnyProperty(BeanProperty property,
KeyDeserializer keyDeser,
ValueDeserializer<Object> valueDeser, TypeDeserializer typeDeser,
ValueInstantiator inst) {
this(property, field, valueType, keyDeser, valueDeser, typeDeser, inst, valueDeser);
}

protected MapFieldAnyProperty(BeanProperty property,
AnnotatedMember field, JavaType valueType,
KeyDeserializer keyDeser,
ValueDeserializer<Object> valueDeser, TypeDeserializer typeDeser,
ValueInstantiator inst, NullValueProvider nullProvider) {
super(property, field, valueType,
keyDeser, valueDeser, typeDeser);
keyDeser, valueDeser, typeDeser, nullProvider);
_valueInstantiator = inst;
}

@Override
public SettableAnyProperty withValueDeserializer(ValueDeserializer<Object> deser) {
NullValueProvider nvp = (_valueDeserializer == _nullProvider) ? deser : _nullProvider;
return new MapFieldAnyProperty(_property, _setter, _type,
_keyDeserializer, deser, _valueTypeDeserializer,
_valueInstantiator);
_valueInstantiator, nvp);
}

@Override
public SettableAnyProperty withNullProvider(NullValueProvider nullProvider) {
return new MapFieldAnyProperty(_property, _setter, _type,
_keyDeserializer, _valueDeserializer, _valueTypeDeserializer,
_valueInstantiator, nullProvider);
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -396,7 +457,14 @@ public JsonNodeFieldAnyProperty(BeanProperty property,
AnnotatedMember field, JavaType valueType,
ValueDeserializer<Object> valueDeser,
JsonNodeFactory nodeFactory) {
super(property, field, valueType, null, valueDeser, null);
this(property, field, valueType, valueDeser, nodeFactory, valueDeser);
}

protected JsonNodeFieldAnyProperty(BeanProperty property,
AnnotatedMember field, JavaType valueType,
ValueDeserializer<Object> valueDeser,
JsonNodeFactory nodeFactory, NullValueProvider nullProvider) {
super(property, field, valueType, null, valueDeser, null, nullProvider);
_nodeFactory = nodeFactory;
}

Expand All @@ -406,13 +474,19 @@ public void deserializeAndSet(JsonParser p, DeserializationContext ctxt,
Object instance, String propName)
throws JacksonException
{
if (shouldSkipNullValue(p)) {
return;
}
setProperty(instance, propName, (JsonNode) deserialize(p, ctxt));
}

// Let's override since this is much simpler with JsonNodes
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException
{
if (p.hasToken(JsonToken.VALUE_NULL)) {
return _nullProvider.getNullValue(ctxt);
}
return _valueDeserializer.deserialize(p, ctxt);
}

Expand Down Expand Up @@ -445,7 +519,18 @@ protected void setProperty(Object instance, String propName, JsonNode value)
// Should not get called but...
@Override
public SettableAnyProperty withValueDeserializer(ValueDeserializer<Object> deser) {
return this;
if (_valueDeserializer == deser) {
return this;
}
NullValueProvider nvp = (_valueDeserializer == _nullProvider) ? deser : _nullProvider;
return new JsonNodeFieldAnyProperty(_property, _setter, _type,
deser, _nodeFactory, nvp);
}

@Override
public SettableAnyProperty withNullProvider(NullValueProvider nullProvider) {
return new JsonNodeFieldAnyProperty(_property, _setter, _type,
_valueDeserializer, _nodeFactory, nullProvider);
}
}

Expand All @@ -462,16 +547,31 @@ public MapParameterAnyProperty(BeanProperty property, AnnotatedMember field, Jav
KeyDeserializer keyDeser, ValueDeserializer<Object> valueDeser, TypeDeserializer typeDeser,
ValueInstantiator inst, int parameterIndex)
{
super(property, field, valueType, keyDeser, valueDeser, typeDeser);
this(property, field, valueType, keyDeser, valueDeser, typeDeser, inst, parameterIndex, valueDeser);
}

protected MapParameterAnyProperty(BeanProperty property, AnnotatedMember field, JavaType valueType,
KeyDeserializer keyDeser, ValueDeserializer<Object> valueDeser, TypeDeserializer typeDeser,
ValueInstantiator inst, int parameterIndex, NullValueProvider nullProvider)
{
super(property, field, valueType, keyDeser, valueDeser, typeDeser, nullProvider);
_valueInstantiator = Objects.requireNonNull(inst, "ValueInstantiator for MapParameterAnyProperty cannot be `null`");
_parameterIndex = parameterIndex;
}

@Override
public SettableAnyProperty withValueDeserializer(ValueDeserializer<Object> deser)
{
NullValueProvider nvp = (_valueDeserializer == _nullProvider) ? deser : _nullProvider;
return new MapParameterAnyProperty(_property, _setter, _type, _keyDeserializer, deser,
_valueTypeDeserializer, _valueInstantiator, _parameterIndex);
_valueTypeDeserializer, _valueInstantiator, _parameterIndex, nvp);
}

@Override
public SettableAnyProperty withNullProvider(NullValueProvider nullProvider)
{
return new MapParameterAnyProperty(_property, _setter, _type, _keyDeserializer, _valueDeserializer,
_valueTypeDeserializer, _valueInstantiator, _parameterIndex, nullProvider);
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -500,7 +600,14 @@ protected static class JsonNodeParameterAnyProperty extends SettableAnyProperty
public JsonNodeParameterAnyProperty(BeanProperty property, AnnotatedMember field, JavaType valueType,
ValueDeserializer<Object> valueDeser, JsonNodeFactory nodeFactory, int parameterIndex)
{
super(property, field, valueType, null, valueDeser, null);
this(property, field, valueType, valueDeser, nodeFactory, parameterIndex, valueDeser);
}

protected JsonNodeParameterAnyProperty(BeanProperty property, AnnotatedMember field, JavaType valueType,
ValueDeserializer<Object> valueDeser, JsonNodeFactory nodeFactory, int parameterIndex,
NullValueProvider nullProvider)
{
super(property, field, valueType, null, valueDeser, null, nullProvider);
_nodeFactory = nodeFactory;
_parameterIndex = parameterIndex;
}
Expand All @@ -510,6 +617,9 @@ public JsonNodeParameterAnyProperty(BeanProperty property, AnnotatedMember field
public Object deserialize(JsonParser p, DeserializationContext ctxt)
throws JacksonException
{
if (p.hasToken(JsonToken.VALUE_NULL)) {
return _nullProvider.getNullValue(ctxt);
}
return _valueDeserializer.deserialize(p, ctxt);
}

Expand All @@ -526,6 +636,12 @@ public SettableAnyProperty withValueDeserializer(ValueDeserializer<Object> deser
throw new UnsupportedOperationException("Cannot call withValueDeserializer() on " + getClass().getName());
}

@Override
public SettableAnyProperty withNullProvider(NullValueProvider nullProvider) {
return new JsonNodeParameterAnyProperty(_property, _setter, _type,
_valueDeserializer, _nodeFactory, _parameterIndex, nullProvider);
}

@Override
public int getParameterIndex() { return _parameterIndex; }

Expand Down
Loading
Loading