Skip to content

Commit 32eee1b

Browse files
committed
Fix #3271
1 parent 6789471 commit 32eee1b

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

release-notes/VERSION-2.x

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ Project: jackson-databind
7373
(reported by saneksanek@github)
7474
#3259: Support for BCP 47 `java.util.Locale` serialization/deserialization
7575
(contributed by Abishek R)
76+
#3271: String property deserializes null as "null" for JsonTypeInfo.As.EXISTING_PROPERTY
77+
(reported by jonc2@github)
7678
- Fix to avoid problem with `BigDecimalNode`, scale of `Integer.MIN_VALUE` (see
7779
[dataformats-binary#264] for details)
7880
- Extend handling of `FAIL_ON_NULL_FOR_PRIMITIVES` to cover coercion from (Empty) String

src/main/java/com/fasterxml/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,11 @@ public Object deserializeTypedFromObject(JsonParser p, DeserializationContext ct
104104
p.nextToken(); // to point to the value
105105
if (name.equals(_typePropertyName)
106106
|| (ignoreCase && name.equalsIgnoreCase(_typePropertyName))) { // gotcha!
107-
return _deserializeTypedForId(p, ctxt, tb, p.getText());
107+
// 09-Sep-2021, tatu: [databind#3271]: Avoid converting null to "null"
108+
String typeId = p.getValueAsString();
109+
if (typeId != null) {
110+
return _deserializeTypedForId(p, ctxt, tb, typeId);
111+
}
108112
}
109113
if (tb == null) {
110114
tb = ctxt.bufferForInputBuffering(p);
@@ -116,7 +120,8 @@ public Object deserializeTypedFromObject(JsonParser p, DeserializationContext ct
116120
}
117121

118122
protected Object _deserializeTypedForId(JsonParser p, DeserializationContext ctxt,
119-
TokenBuffer tb, String typeId) throws IOException {
123+
TokenBuffer tb, String typeId) throws IOException
124+
{
120125
JsonDeserializer<Object> deser = _findDeserializer(ctxt, typeId);
121126
if (_typeIdVisible) { // need to merge id back in JSON input?
122127
if (tb == null) {

src/test/java/com/fasterxml/jackson/databind/jsontype/ExistingPropertyTest.java

+38-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
77
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
88
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
9-
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
109

1110
import com.fasterxml.jackson.core.type.TypeReference;
1211

@@ -192,10 +191,26 @@ static class Bean1635A extends Bean1635 {
192191

193192
static class Bean1635Default extends Bean1635 { }
194193

194+
// [databind#3271]
195+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY,
196+
visible = true, property = "type", defaultImpl = DefaultShape3271.class)
197+
@JsonSubTypes({@JsonSubTypes.Type(value = Square3271.class, name = "square")})
198+
static abstract class Shape3271 {
199+
public String type;
200+
201+
public String getType() { return this.type; }
202+
203+
public void setType(String type) { this.type = type; }
204+
}
205+
206+
static class Square3271 extends Shape3271 {}
207+
208+
static class DefaultShape3271 extends Shape3271 {}
209+
195210
/*
196-
/**********************************************************
211+
/**********************************************************************
197212
/* Mock data
198-
/**********************************************************
213+
/**********************************************************************
199214
*/
200215

201216
private static final Orange mandarin = new Orange("Mandarin Orange", "orange");
@@ -226,12 +241,12 @@ static class Bean1635Default extends Bean1635 { }
226241
private static final String carListJson = "[" + camryJson + "," + accordJson + "]";
227242

228243
/*
229-
/**********************************************************
244+
/**********************************************************************
230245
/* Test methods
231-
/**********************************************************
246+
/**********************************************************************
232247
*/
233248

234-
private final ObjectMapper MAPPER = new ObjectMapper();
249+
private final ObjectMapper MAPPER = newJsonMapper();
235250

236251
/**
237252
* Fruits - serialization tests for simple property on sub-classes
@@ -443,4 +458,21 @@ public void testExistingEnumTypeIdViaDefault() throws Exception
443458
assertEquals(Bean1635Default.class, result.getClass());
444459
assertEquals(ABC.C, result.type);
445460
}
461+
462+
// [databind#3271]: verify that `null` token does not become "null" String
463+
464+
public void testDeserializationWithValidType() throws Exception {
465+
Shape3271 deserShape = MAPPER.readValue("{\"type\":\"square\"}", Shape3271.class);
466+
assertEquals("square", deserShape.getType());
467+
}
468+
469+
public void testDeserializationWithInvalidType() throws Exception {
470+
Shape3271 deserShape = MAPPER.readValue("{\"type\":\"invalid\"}", Shape3271.class);
471+
assertEquals("invalid", deserShape.getType());
472+
}
473+
474+
public void testDeserializationNull() throws Exception {
475+
Shape3271 deserShape = MAPPER.readValue("{\"type\":null}", Shape3271.class);
476+
assertNull(deserShape.getType()); // error: "expected null, but was:<null>"
477+
}
446478
}

0 commit comments

Comments
 (0)