Skip to content

Commit 8889cbe

Browse files
committed
Merge branch '2.13'
2 parents afdc512 + 330e919 commit 8889cbe

File tree

6 files changed

+91
-12
lines changed

6 files changed

+91
-12
lines changed

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ Project: jackson-databind
2121

2222
2.12.2 (not yet released)
2323

24+
#3008: String property deserializes null as "null" for
25+
`JsonTypeInfo.As.EXTERNAL_PROPERTY`
2426
#3022: Property ignorals cause `BeanDeserializer `to forget how to read
2527
from arrays (not copying `_arrayDelegateDeserializer`)
2628
(reported by Gian M)

src/main/java/com/fasterxml/jackson/databind/deser/impl/ExternalTypeHandler.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ public boolean handlePropertyValue(JsonParser p, DeserializationContext ctxt,
171171
ExtTypedProperty prop = _properties[index];
172172
boolean canDeserialize;
173173
if (prop.hasTypePropertyName(propName)) {
174-
_typeIds[index] = p.getText();
174+
// 19-Feb-2021, tatu: as per [databind#3008], don't use "getText()"
175+
// since that'll coerce null value into String "null"...
176+
_typeIds[index] = p.getValueAsString();
175177
p.skipChildren();
176178
canDeserialize = (bean != null) && (_tokens[index] != null);
177179
} else {
@@ -269,7 +271,12 @@ public Object complete(JsonParser p, DeserializationContext ctxt,
269271
final ExtTypedProperty extProp = _properties[i];
270272
if (typeId == null) {
271273
// let's allow missing both type and property (may already have been set, too)
272-
if (_tokens[i] == null) {
274+
TokenBuffer tb = _tokens[i];
275+
if ((tb == null)
276+
// 19-Feb-2021, tatu: Both missing value and explicit `null`
277+
// should be accepted...
278+
|| (tb.firstToken() == JsonToken.VALUE_NULL)
279+
) {
273280
continue;
274281
}
275282
// but not just one

src/main/java/com/fasterxml/jackson/databind/util/TokenBuffer.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,17 @@ public JsonToken firstToken() {
343343
return _first.type(0);
344344
}
345345

346+
/**
347+
* Accessor for checking whether this buffer has one or more tokens
348+
* or not.
349+
*
350+
* @return True if this buffer instance has no tokens
351+
*
352+
* @since 2.13
353+
*/
354+
public boolean isEmpty() {
355+
return (_appendAt == 0) && (_first == _last);
356+
}
346357
/*
347358
/**********************************************************************
348359
/* Other custom methods not needed for implementing interfaces

src/test/java/com/fasterxml/jackson/databind/jsontype/ext/ExternalTypeIdTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.fasterxml.jackson.databind.DeserializationFeature;
1111
import com.fasterxml.jackson.databind.MapperFeature;
1212
import com.fasterxml.jackson.databind.ObjectMapper;
13+
import com.fasterxml.jackson.databind.ObjectReader;
1314
import com.fasterxml.jackson.databind.json.JsonMapper;
1415
import com.fasterxml.jackson.databind.testutil.NoCheckSubTypeValidator;
1516

@@ -545,4 +546,40 @@ public void testBigDecimal965() throws Exception
545546
w.value.getClass().getSimpleName(), w.value.toString(), w2.value.getClass().getSimpleName(), w2.value.toString()),
546547
w.value.equals(w2.value));
547548
}
549+
550+
static class Box3008 {
551+
public String type;
552+
public Fruit3008 fruit;
553+
554+
public Box3008(@JsonProperty("type") String type,
555+
@JsonTypeInfo(use = Id.NAME, include = As.EXTERNAL_PROPERTY, property = "type")
556+
@JsonSubTypes({@JsonSubTypes.Type(value = Orange.class, name = "orange")})
557+
@JsonProperty("fruit")
558+
Fruit3008 fruit) {
559+
this.type = type;
560+
this.fruit = fruit;
561+
}
562+
}
563+
564+
// [databind#3008]: allow
565+
interface Fruit3008 {}
566+
567+
static class Orange implements Fruit3008 {
568+
public String name;
569+
public String color;
570+
571+
public Orange(@JsonProperty("name") String name, @JsonProperty("name") String color) {
572+
this.name = name;
573+
this.color = color;
574+
}
575+
}
576+
577+
// for [databind#3008]
578+
public void testIssue3008() throws Exception
579+
{
580+
ObjectReader r = MAPPER.readerFor(Box3008.class);
581+
Box3008 deserOrangeBox = r.readValue("{\"type\":null,\"fruit\":null}}");
582+
assertNull(deserOrangeBox.fruit);
583+
assertNull(deserOrangeBox.type); // error: "expected null, but was:<null>"
584+
}
548585
}

src/test/java/com/fasterxml/jackson/databind/util/TestTokenBuffer.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ static class Base1730 { }
2323
static class Sub1730 extends Base1730 { }
2424

2525
/*
26-
/**********************************************************
26+
/**********************************************************************
2727
/* Basic TokenBuffer tests
28-
/**********************************************************
28+
/**********************************************************************
2929
*/
3030

3131
public void testBasicConfig() throws IOException
@@ -36,6 +36,7 @@ public void testBasicConfig() throws IOException
3636
assertEquals(MAPPER.version(), buf.version());
3737
assertNotNull(buf.streamWriteContext());
3838
assertFalse(buf.isClosed());
39+
assertTrue(buf.isEmpty());
3940

4041
assertFalse(buf.isEnabled(StreamWriteFeature.WRITE_BIGDECIMAL_AS_PLAIN));
4142
buf.configure(StreamWriteFeature.WRITE_BIGDECIMAL_AS_PLAIN, true);
@@ -52,7 +53,8 @@ public void testBasicConfig() throws IOException
5253
public void testSimpleWrites() throws IOException
5354
{
5455
TokenBuffer buf = TokenBuffer.forGeneration();
55-
56+
assertTrue(buf.isEmpty());
57+
5658
// First, with empty buffer
5759
JsonParser p = buf.asParser(ObjectReadContext.empty());
5860
assertNull(p.currentToken());
@@ -61,6 +63,7 @@ public void testSimpleWrites() throws IOException
6163

6264
// Then with simple text
6365
buf.writeString("abc");
66+
assertFalse(buf.isEmpty());
6467

6568
p = buf.asParser(ObjectReadContext.empty());
6669
assertNull(p.currentToken());
@@ -655,6 +658,7 @@ public void testEmbeddedObjectCoerceCheck() throws Exception
655658
TokenBuffer buf = TokenBuffer.forGeneration();
656659
Object inputPojo = new Sub1730();
657660
buf.writeEmbeddedObject(inputPojo);
661+
assertEquals(JsonToken.VALUE_EMBEDDED_OBJECT, buf.firstToken());
658662

659663
// first: raw value won't be transformed in any way:
660664
JsonParser p = buf.asParser(ObjectReadContext.empty());
@@ -664,4 +668,19 @@ public void testEmbeddedObjectCoerceCheck() throws Exception
664668
p.close();
665669
buf.close();
666670
}
671+
672+
public void testIsEmpty() throws Exception
673+
{
674+
// Let's check that segment boundary won't ruin it
675+
try (TokenBuffer buf = new TokenBuffer(null, false)) {
676+
assertTrue(buf.isEmpty());
677+
678+
for (int i = 0; i < 100; ++i) {
679+
buf.writeNumber(i);
680+
assertFalse(buf.isEmpty());
681+
}
682+
683+
assertEquals(JsonToken.VALUE_NUMBER_INT, buf.firstToken());
684+
}
685+
}
667686
}

src/test/java/com/fasterxml/jackson/failing/EnumDeserializationFromInt1850Test.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,19 @@ enum Example2 {
2121
Example2(int x) { this.x = x; }
2222
}
2323

24-
public void testEnumFromInt1850() throws Exception
24+
private final ObjectMapper MAPPER = newJsonMapper();
25+
26+
public void testEnumFromInt1850Method() throws Exception
2527
{
26-
final ObjectMapper mapper = newJsonMapper();
27-
28-
String json = mapper.writeValueAsString(Example1.A);
29-
Example1 e1 = mapper.readValue(json, Example1.class);
28+
String json = MAPPER.writeValueAsString(Example1.A);
29+
Example1 e1 = MAPPER.readValue(json, Example1.class);
3030
assertEquals(Example1.A, e1);
31+
}
3132

32-
json = mapper.writeValueAsString(Example2.A);
33-
Example2 e2 = mapper.readValue(json, Example2.class);
33+
public void testEnumFromInt1850Field() throws Exception
34+
{
35+
String json = MAPPER.writeValueAsString(Example2.A);
36+
Example2 e2 = MAPPER.readValue(json, Example2.class);
3437
assertEquals(Example2.A, e2);
3538
}
3639
}

0 commit comments

Comments
 (0)