Skip to content

Commit 9f45530

Browse files
authored
fix issue where unexpected properties can cause deserialization issues (#3911)
1 parent 40b4e2a commit 9f45530

File tree

4 files changed

+118
-6
lines changed

4 files changed

+118
-6
lines changed

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ protected Object _deserializeUsingPropertyBased(final JsonParser p, final Deseri
454454

455455
// polymorphic?
456456
if (bean.getClass() != _beanType.getRawClass()) {
457-
return handlePolymorphic(p, ctxt, bean, unknown);
457+
return handlePolymorphic(p, ctxt, p.streamReadConstraints(), bean, unknown);
458458
}
459459
if (unknown != null) { // nope, just extra unknown stuff...
460460
bean = handleUnknownProperties(ctxt, bean, unknown);
@@ -538,7 +538,7 @@ protected Object _deserializeUsingPropertyBased(final JsonParser p, final Deseri
538538
if (unknown != null) {
539539
// polymorphic?
540540
if (bean.getClass() != _beanType.getRawClass()) { // lgtm [java/dereferenced-value-may-be-null]
541-
return handlePolymorphic(null, ctxt, bean, unknown);
541+
return handlePolymorphic(null, ctxt, p.streamReadConstraints(), bean, unknown);
542542
}
543543
// no, just some extra unknown properties
544544
return handleUnknownProperties(ctxt, bean, unknown);

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

+24-1
Original file line numberDiff line numberDiff line change
@@ -1735,18 +1735,41 @@ protected void handleIgnoredProperty(JsonParser p, DeserializationContext ctxt,
17351735
* @param p (optional) If not null, parser that has more properties to handle
17361736
* (in addition to buffered properties); if null, all properties are passed
17371737
* in buffer
1738+
* @deprecated use {@link #handlePolymorphic(JsonParser, DeserializationContext, StreamReadConstraints, Object, TokenBuffer)}
17381739
*/
1740+
@Deprecated
17391741
protected Object handlePolymorphic(JsonParser p, DeserializationContext ctxt,
17401742
Object bean, TokenBuffer unknownTokens)
17411743
throws IOException
1744+
{
1745+
final StreamReadConstraints streamReadConstraints = p == null ?
1746+
StreamReadConstraints.defaults() : p.streamReadConstraints();
1747+
return handlePolymorphic(p, ctxt, streamReadConstraints, bean, unknownTokens);
1748+
}
1749+
1750+
/**
1751+
* Method called in cases where we may have polymorphic deserialization
1752+
* case: that is, type of Creator-constructed bean is not the type
1753+
* of deserializer itself. It should be a sub-class or implementation
1754+
* class; either way, we may have more specific deserializer to use
1755+
* for handling it.
1756+
*
1757+
* @param p (optional) If not null, parser that has more properties to handle
1758+
* (in addition to buffered properties); if null, all properties are passed
1759+
* in buffer
1760+
* @since 2.15.1
1761+
*/
1762+
protected Object handlePolymorphic(JsonParser p, DeserializationContext ctxt,
1763+
StreamReadConstraints streamReadConstraints, Object bean, TokenBuffer unknownTokens)
1764+
throws IOException
17421765
{
17431766
// First things first: maybe there is a more specific deserializer available?
17441767
JsonDeserializer<Object> subDeser = _findSubclassDeserializer(ctxt, bean, unknownTokens);
17451768
if (subDeser != null) {
17461769
if (unknownTokens != null) {
17471770
// need to add END_OBJECT marker first
17481771
unknownTokens.writeEndObject();
1749-
JsonParser p2 = unknownTokens.asParser(p.streamReadConstraints());
1772+
JsonParser p2 = unknownTokens.asParser(streamReadConstraints);
17501773
p2.nextToken(); // to get to first data field
17511774
bean = subDeser.deserialize(p2, ctxt, bean);
17521775
}

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ protected Object _deserializeUsingPropertyBased(final JsonParser p,
395395
}
396396
// polymorphic?
397397
if (builder.getClass() != _beanType.getRawClass()) {
398-
return handlePolymorphic(p, ctxt, builder, unknown);
398+
return handlePolymorphic(p, ctxt, p.streamReadConstraints(), builder, unknown);
399399
}
400400
if (unknown != null) { // nope, just extra unknown stuff...
401401
builder = handleUnknownProperties(ctxt, builder, unknown);
@@ -440,7 +440,7 @@ protected Object _deserializeUsingPropertyBased(final JsonParser p,
440440
if (unknown != null) {
441441
// polymorphic?
442442
if (builder.getClass() != _beanType.getRawClass()) {
443-
return handlePolymorphic(null, ctxt, builder, unknown);
443+
return handlePolymorphic(null, ctxt, p.streamReadConstraints(), builder, unknown);
444444
}
445445
// no, just some extra unknown properties
446446
return handleUnknownProperties(ctxt, builder, unknown);
@@ -669,7 +669,7 @@ protected Object deserializeUsingPropertyBasedWithUnwrapped(JsonParser p,
669669
continue; // never gets here
670670
}
671671
if (builder.getClass() != _beanType.getRawClass()) {
672-
return handlePolymorphic(p, ctxt, builder, tokens);
672+
return handlePolymorphic(p, ctxt, p.streamReadConstraints(), builder, tokens);
673673
}
674674
return deserializeWithUnwrapped(p, ctxt, builder, tokens);
675675
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.fasterxml.jackson.databind.deser;
2+
3+
import com.fasterxml.jackson.annotation.JsonCreator;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import com.fasterxml.jackson.core.JsonProcessingException;
6+
import com.fasterxml.jackson.databind.BaseMapTest;
7+
import com.fasterxml.jackson.databind.DeserializationFeature;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
10+
import java.util.List;
11+
12+
public class Issue1009Test extends BaseMapTest {
13+
14+
public void testDeserialization() throws JsonProcessingException {
15+
String rawResponse = "{\"list\":[{\"type\":\"impl\",\"unmappedKey\":\"unusedValue\"}]}";
16+
MyResponse myResponse = objectMapper().readValue(rawResponse, MyResponse.class);
17+
assertNotNull(myResponse);
18+
assertEquals(1, myResponse.list.size());
19+
assertEquals("impl", myResponse.list.get(0).getType());
20+
assertNull(myResponse.list.get(0).getMissingInJson());
21+
}
22+
23+
protected ObjectMapper objectMapper() {
24+
ObjectMapper om = new ObjectMapper();
25+
om.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
26+
return om;
27+
}
28+
29+
static class MyResponse {
30+
private List<Base> list;
31+
32+
public List<Base> getList() {
33+
return list;
34+
}
35+
36+
public void setList(List<Base> list) {
37+
this.list = list;
38+
}
39+
}
40+
41+
interface Base {
42+
43+
String getType();
44+
45+
String getMissingInJson();
46+
47+
@JsonCreator
48+
static Base unmarshall(
49+
@JsonProperty("missingInJson") String missingInJson,
50+
@JsonProperty("type") String type
51+
) {
52+
switch (type) {
53+
case "impl":
54+
return new Impl(type, missingInJson);
55+
default:
56+
return null;
57+
}
58+
}
59+
}
60+
61+
final static class Impl implements Base {
62+
private String type;
63+
private String missingInJson;
64+
65+
public Impl() {
66+
}
67+
68+
public Impl(String type, String missingInJson) {
69+
this.type = type;
70+
this.missingInJson = missingInJson;
71+
}
72+
73+
@Override public String getType() {
74+
return type;
75+
}
76+
77+
@Override public String getMissingInJson() {
78+
return missingInJson;
79+
}
80+
81+
public void setType(String type) {
82+
this.type = type;
83+
}
84+
85+
public void setMissingInJson(String missingInJson) {
86+
this.missingInJson = missingInJson;
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)