Skip to content

Commit

Permalink
Fix #3005
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Feb 20, 2021
1 parent 2c85bd6 commit b2e92b6
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 3 deletions.
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Project: jackson-databind

2.12.2 (not yet released)

#3005: String property deserializes null as "null" for
`JsonTypeInfo.As.EXTERNAL_PROPERTY`
#3022: Property ignorals cause `BeanDeserializer `to forget how to read
from arrays (not copying `_arrayDelegateDeserializer`)
(reported by Gian M)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ public boolean handlePropertyValue(JsonParser p, DeserializationContext ctxt,
ExtTypedProperty prop = _properties[index];
boolean canDeserialize;
if (prop.hasTypePropertyName(propName)) {
_typeIds[index] = p.getText();
// 19-Feb-2021, tatu: as per [databind#3005], don't use "getText()"
// since that'll coerce null value into String "null"...
_typeIds[index] = p.getValueAsString();
p.skipChildren();
canDeserialize = (bean != null) && (_tokens[index] != null);
} else {
Expand Down Expand Up @@ -270,7 +272,12 @@ public Object complete(JsonParser p, DeserializationContext ctxt,
final ExtTypedProperty extProp = _properties[i];
if (typeId == null) {
// let's allow missing both type and property (may already have been set, too)
if (_tokens[i] == null) {
TokenBuffer tb = _tokens[i];
if ((tb == null)
// 19-Feb-2021, tatu: Both missing value and explicit `null`
// should be accepted...
|| (tb.firstToken() == JsonToken.VALUE_NULL)
) {
continue;
}
// but not just one
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/fasterxml/jackson/databind/util/TokenBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,17 @@ public JsonToken firstToken() {
return _first.type(0);
}

/**
* Accessor for checking whether this buffer has one or more tokens
* or not.
*
* @return True if this buffer instance has no tokens
*
* @since 2.13
*/
public boolean isEmpty() {
return (_appendAt == 0) && (_first == _last);
}
/*
/**********************************************************
/* Other custom methods not needed for implementing interfaces
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.json.JsonMapper;

// Tests for External type id, one that exists at same level as typed Object,
Expand Down Expand Up @@ -537,4 +538,40 @@ public void testBigDecimal965() throws Exception
w.value.getClass().getSimpleName(), w.value.toString(), w2.value.getClass().getSimpleName(), w2.value.toString()),
w.value.equals(w2.value));
}

static class Box3008 {
public String type;
public Fruit3008 fruit;

public Box3008(@JsonProperty("type") String type,
@JsonTypeInfo(use = Id.NAME, include = As.EXTERNAL_PROPERTY, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = Orange.class, name = "orange")})
@JsonProperty("fruit")
Fruit3008 fruit) {
this.type = type;
this.fruit = fruit;
}
}

// [databind#3008]: allow
interface Fruit3008 {}

static class Orange implements Fruit3008 {
public String name;
public String color;

public Orange(@JsonProperty("name") String name, @JsonProperty("name") String color) {
this.name = name;
this.color = color;
}
}

// for [databind#3008]
public void testIssue3008() throws Exception
{
ObjectReader r = MAPPER.readerFor(Box3008.class);
Box3008 deserOrangeBox = r.readValue("{\"type\":null,\"fruit\":null}}");
assertNull(deserOrangeBox.fruit);
assertNull(deserOrangeBox.type); // error: "expected null, but was:<null>"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public void testBasicConfig() throws IOException
assertSame(MAPPER, buf.getCodec());
assertNotNull(buf.getOutputContext());
assertFalse(buf.isClosed());
assertTrue(buf.isEmpty());

buf.setCodec(null);
assertNull(buf.getCodec());
Expand All @@ -57,7 +58,8 @@ public void testBasicConfig() throws IOException
public void testSimpleWrites() throws IOException
{
TokenBuffer buf = new TokenBuffer(null, false); // no ObjectCodec

assertTrue(buf.isEmpty());

// First, with empty buffer
JsonParser p = buf.asParser();
assertNull(p.currentToken());
Expand All @@ -66,6 +68,7 @@ public void testSimpleWrites() throws IOException

// Then with simple text
buf.writeString("abc");
assertFalse(buf.isEmpty());

p = buf.asParser();
assertNull(p.currentToken());
Expand Down Expand Up @@ -657,6 +660,7 @@ public void testEmbeddedObjectCoerceCheck() throws Exception
TokenBuffer buf = new TokenBuffer(null, false);
Object inputPojo = new Sub1730();
buf.writeEmbeddedObject(inputPojo);
assertEquals(JsonToken.VALUE_EMBEDDED_OBJECT, buf.firstToken());

// first: raw value won't be transformed in any way:
JsonParser p = buf.asParser();
Expand All @@ -666,4 +670,19 @@ public void testEmbeddedObjectCoerceCheck() throws Exception
p.close();
buf.close();
}

public void testIsEmpty() throws Exception
{
// Let's check that segment boundary won't ruin it
try (TokenBuffer buf = new TokenBuffer(null, false)) {
assertTrue(buf.isEmpty());

for (int i = 0; i < 100; ++i) {
buf.writeNumber(i);
assertFalse(buf.isEmpty());
}

assertEquals(JsonToken.VALUE_NUMBER_INT, buf.firstToken());
}
}
}

0 comments on commit b2e92b6

Please sign in to comment.