Skip to content

Commit 9a23f81

Browse files
authored
Implement #3394: allow JsonNode valued Fields for @JsonAnySetter (#3563)
1 parent 52ed66a commit 9a23f81

File tree

7 files changed

+306
-75
lines changed

7 files changed

+306
-75
lines changed

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Project: jackson-databind
2020
(reported by lizongbo@github)
2121
#3373: Change `TypeSerializerBase` to skip `generator.writeTypePrefix()`
2222
for `null` typeId
23+
#3394: Allow use of `JsonNode` field for `@JsonAnySetter`
24+
(requested by @sixcorners)
2325
#3405: Create DataTypeFeature abstraction (for JSTEP-7) with placeholder features
2426
#3417: Allow (de)serializing records using Bean(De)SerializerModifier even when
2527
reflection is unavailable

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.fasterxml.jackson.databind.introspect.*;
1313
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
1414
import com.fasterxml.jackson.databind.jsontype.impl.SubTypeValidator;
15+
import com.fasterxml.jackson.databind.node.ObjectNode;
1516
import com.fasterxml.jackson.databind.util.BeanUtil;
1617
import com.fasterxml.jackson.databind.util.ClassUtil;
1718
import com.fasterxml.jackson.databind.util.IgnorePropertiesUtil;
@@ -806,6 +807,7 @@ protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
806807
BeanProperty prop;
807808
JavaType keyType;
808809
JavaType valueType;
810+
final boolean isField = mutator instanceof AnnotatedField;
809811

810812
if (mutator instanceof AnnotatedMethod) {
811813
// we know it's a 2-arg method, second arg is the value
@@ -817,18 +819,39 @@ protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
817819
valueType, null, mutator,
818820
PropertyMetadata.STD_OPTIONAL);
819821

820-
} else if (mutator instanceof AnnotatedField) {
822+
} else if (isField) {
821823
AnnotatedField af = (AnnotatedField) mutator;
822824
// get the type from the content type of the map object
823-
JavaType mapType = af.getType();
824-
mapType = resolveMemberAndTypeAnnotations(ctxt, mutator, mapType);
825-
keyType = mapType.getKeyType();
826-
valueType = mapType.getContentType();
827-
prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
828-
mapType, null, mutator, PropertyMetadata.STD_OPTIONAL);
825+
JavaType fieldType = af.getType();
826+
// 31-Jul-2022, tatu: Not just Maps any more but also JsonNode, so:
827+
if (fieldType.isMapLikeType()) {
828+
fieldType = resolveMemberAndTypeAnnotations(ctxt, mutator, fieldType);
829+
keyType = fieldType.getKeyType();
830+
valueType = fieldType.getContentType();
831+
prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
832+
fieldType, null, mutator, PropertyMetadata.STD_OPTIONAL);
833+
} else if (fieldType.hasRawClass(JsonNode.class)
834+
|| fieldType.hasRawClass(ObjectNode.class)) {
835+
fieldType = resolveMemberAndTypeAnnotations(ctxt, mutator, fieldType);
836+
// Deserialize is individual values of ObjectNode, not full ObjectNode, so:
837+
valueType = ctxt.constructType(JsonNode.class);
838+
prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
839+
fieldType, null, mutator, PropertyMetadata.STD_OPTIONAL);
840+
841+
// Unlike with more complicated types, here we do not allow any annotation
842+
// overrides etc but instead short-cut handling:
843+
return SettableAnyProperty.constructForJsonNodeField(ctxt,
844+
prop, mutator, valueType,
845+
ctxt.findRootValueDeserializer(valueType));
846+
} else {
847+
return ctxt.reportBadDefinition(beanDesc.getType(), String.format(
848+
"Unsupported type for any-setter: %s -- only support `Map`s, `JsonNode` and `ObjectNode` ",
849+
ClassUtil.getTypeDescription(fieldType)));
850+
}
829851
} else {
830852
return ctxt.reportBadDefinition(beanDesc.getType(), String.format(
831-
"Unrecognized mutator type for any setter: %s", mutator.getClass()));
853+
"Unrecognized mutator type for any-setter: %s",
854+
ClassUtil.nameOf(mutator.getClass())));
832855
}
833856
// First: see if there are explicitly specified
834857
// and then possible direct deserializer override on accessor
@@ -853,8 +876,12 @@ protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
853876
deser = (JsonDeserializer<Object>) ctxt.handlePrimaryContextualization(deser, prop, valueType);
854877
}
855878
TypeDeserializer typeDeser = valueType.getTypeHandler();
856-
return new SettableAnyProperty(prop, mutator, valueType,
857-
keyDeser, deser, typeDeser);
879+
if (isField) {
880+
return SettableAnyProperty.constructForMapField(ctxt,
881+
prop, mutator, valueType, keyDeser, deser, typeDeser);
882+
}
883+
return SettableAnyProperty.constructForMethod(ctxt,
884+
prop, mutator, valueType, keyDeser, deser, typeDeser);
858885
}
859886

860887
/**

0 commit comments

Comments
 (0)