Skip to content

Commit 713062f

Browse files
author
JamesWang
committed
Fix FasterXML#2541 (support merge polymorphic property)
1 parent abc6669 commit 713062f

File tree

2 files changed

+73
-5
lines changed

2 files changed

+73
-5
lines changed

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -561,12 +561,16 @@ public final Object deserializeWith(JsonParser p, DeserializationContext ctxt,
561561
}
562562
return _nullProvider.getNullValue(ctxt);
563563
}
564-
// 20-Oct-2016, tatu: Also tricky -- for now, report an error
565564
if (_valueTypeDeserializer != null) {
566-
ctxt.reportBadDefinition(getType(),
567-
String.format("Cannot merge polymorphic property '%s'",
568-
getName()));
569-
// return _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer);
565+
// 25-Oct-2021 Added by James to support merging polymorphic property
566+
// https://github.com/FasterXML/jackson-databind/issues/2541
567+
// Please note we only support merging same type polymorphic property for now,
568+
// merging different type is hard and usually doesn't make sense.
569+
// Please note you need to configure {@link DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES} as false to
570+
// enable this feature otherwise the unknown property exception will be thrown.
571+
JavaType subType = ctxt.getTypeFactory().constructType(toUpdate.getClass());
572+
JsonDeserializer<Object> subTypeValueDeserializer = ctxt.findContextualValueDeserializer(subType, this);
573+
return subTypeValueDeserializer.deserialize(p, ctxt, toUpdate);
570574
}
571575
// 04-May-2018, tatu: [databind#2023] Coercion from String (mostly) can give null
572576
Object value = _valueDeserializer.deserialize(p, ctxt, toUpdate);
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.fasterxml.jackson.databind.deser;
2+
3+
import com.fasterxml.jackson.annotation.JsonMerge;
4+
import com.fasterxml.jackson.annotation.JsonSubTypes;
5+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
6+
import com.fasterxml.jackson.core.JsonProcessingException;
7+
import com.fasterxml.jackson.databind.BaseMapTest;
8+
import com.fasterxml.jackson.databind.DeserializationFeature;
9+
import com.fasterxml.jackson.databind.ObjectMapper;
10+
11+
public class MergePolymorphicTest extends BaseMapTest {
12+
13+
static class Root {
14+
@JsonMerge
15+
public Child child;
16+
}
17+
18+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
19+
@JsonSubTypes({
20+
@JsonSubTypes.Type(value = ChildA.class, name = "ChildA"),
21+
@JsonSubTypes.Type(value = ChildB.class, name = "ChildB")
22+
})
23+
static abstract class Child {
24+
}
25+
26+
static class ChildA extends Child {
27+
public String name;
28+
}
29+
30+
static class ChildB extends Child {
31+
public String code;
32+
}
33+
34+
public void testPolymorphicNewObject() throws JsonProcessingException {
35+
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
36+
Root root = mapper.readValue("{\"child\": { \"@type\": \"ChildA\", \"name\": \"I'm child A\" }}", Root.class);
37+
assertTrue(root.child instanceof ChildA);
38+
assertEquals("I'm child A", ((ChildA) root.child).name);
39+
}
40+
41+
public void testPolymorphicPropertyCanBeMerged() throws JsonProcessingException {
42+
Root root = new Root();
43+
ChildA childA = new ChildA();
44+
childA.name = "I'm child A";
45+
root.child = childA;
46+
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
47+
mapper.readerForUpdating(root).readValue("{\"child\": { \"@type\": \"ChildA\", \"name\": \"I'm the new name\" }}");
48+
assertTrue(root.child instanceof ChildA);
49+
assertEquals("I'm the new name", ((ChildA) root.child).name);
50+
}
51+
52+
public void testPolymorphicPropertyTypeCanNotBeChanged() throws JsonProcessingException {
53+
Root root = new Root();
54+
ChildA childA = new ChildA();
55+
childA.name = "I'm child A";
56+
root.child = childA;
57+
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
58+
mapper.readerForUpdating(root).readValue("{\"child\": { \"@type\": \"ChildB\", \"code\": \"I'm the code\" }}");
59+
// The polymorphic type can't be changed
60+
assertTrue(root.child instanceof ChildA);
61+
assertEquals("I'm child A", ((ChildA) root.child).name);
62+
}
63+
64+
}

0 commit comments

Comments
 (0)