Skip to content

Commit

Permalink
Fix #942 (slightly differently)
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Sep 30, 2015
1 parent 04cb084 commit 30b5469
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 27 deletions.
4 changes: 4 additions & 0 deletions release-notes/CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,7 @@ Andreas Pieber (anpieber@github)
Jesse Wilson (swankjesse@github)
* Contributed #949: Report the offending substring when number parsing fails
(2.6.3)

Warren Bloomer (stormboy@github)
* Reported #942: Handle null type id for polymorphic values that use external type id
(2.6.3)
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Project: jackson-databind
(contributed by Sergio M)
#941: Deserialization from "{}" to ObjectNode field causes "out of END_OBJECT token" error
(reported by Sadayuki F)
#942: Handle null type id for polymorphic values that use external type id
(reported by Warren B, stormboy@github)
#943: Incorrect serialization of enum map key
(reported by Benson M)
#944: Failure to use custom deserializer for key deserializer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,13 @@ public boolean handlePropertyValue(JsonParser jp, DeserializationContext ctxt,
}
return true;
}


/**
* Method called after JSON Object closes, and has to ensure that all external
* type ids have been handled.
*/
@SuppressWarnings("resource")
public Object complete(JsonParser jp, DeserializationContext ctxt, Object bean)
public Object complete(JsonParser p, DeserializationContext ctxt, Object bean)
throws IOException
{
for (int i = 0, len = _properties.length; i < len; ++i) {
Expand All @@ -135,20 +139,19 @@ public Object complete(JsonParser jp, DeserializationContext ctxt, Object bean)
if (tokens == null) {
continue;
}
/* [Issue#118]: Need to mind natural types, for which no type id
* will be included.
*/
// [databind#118]: Need to mind natural types, for which no type id
// will be included.
JsonToken t = tokens.firstToken();
if (t != null && t.isScalarValue()) {
JsonParser buffered = tokens.asParser(jp);
JsonParser buffered = tokens.asParser(p);
buffered.nextToken();
SettableBeanProperty extProp = _properties[i].getProperty();
Object result = TypeDeserializer.deserializeIfNatural(buffered, ctxt, extProp.getType());
if (result != null) {
extProp.set(bean, result);
continue;
}
// 26-Oct-2012, tatu: As per [Issue#94], must allow use of 'defaultImpl'
// 26-Oct-2012, tatu: As per [databind#94], must allow use of 'defaultImpl'
if (!_properties[i].hasDefaultType()) {
throw ctxt.mappingException("Missing external type id property '%s'",
_properties[i].getTypePropertyName());
Expand All @@ -160,7 +163,7 @@ public Object complete(JsonParser jp, DeserializationContext ctxt, Object bean)
throw ctxt.mappingException("Missing property '%s' for external type id '%s'",
prop.getName(), _properties[i].getTypePropertyName());
}
_deserializeAndSet(jp, ctxt, bean, i, typeId);
_deserializeAndSet(p, ctxt, bean, i, typeId);
}
return bean;
}
Expand Down Expand Up @@ -216,41 +219,52 @@ public Object complete(JsonParser jp, DeserializationContext ctxt,
}

@SuppressWarnings("resource")
protected final Object _deserialize(JsonParser jp, DeserializationContext ctxt,
protected final Object _deserialize(JsonParser p, DeserializationContext ctxt,
int index, String typeId) throws IOException
{
TokenBuffer merged = new TokenBuffer(jp);
JsonParser p2 = _tokens[index].asParser(p);
JsonToken t = p2.nextToken();
// 29-Sep-2015, tatu: As per [databind#942], nulls need special support
if (t == JsonToken.VALUE_NULL) {
return null;
}

TokenBuffer merged = new TokenBuffer(p);
merged.writeStartArray();
merged.writeString(typeId);
JsonParser p2 = _tokens[index].asParser(jp);
p2.nextToken();
merged.copyCurrentStructure(p2);
merged.writeEndArray();

// needs to point to START_OBJECT (or whatever first token is)
p2 = merged.asParser(jp);
p2.nextToken();
return _properties[index].getProperty().deserialize(p2, ctxt);
JsonParser mp = merged.asParser(p);
mp.nextToken();
return _properties[index].getProperty().deserialize(mp, ctxt);
}

@SuppressWarnings("resource")
protected final void _deserializeAndSet(JsonParser jp, DeserializationContext ctxt,
protected final void _deserializeAndSet(JsonParser p, DeserializationContext ctxt,
Object bean, int index, String typeId) throws IOException
{
/* Ok: time to mix type id, value; and we will actually use "wrapper-array"
* style to ensure we can handle all kinds of JSON constructs.
*/
TokenBuffer merged = new TokenBuffer(jp);
JsonParser p2 = _tokens[index].asParser(p);
JsonToken t = p2.nextToken();
// 29-Sep-2015, tatu: As per [databind#942], nulls need special support
if (t == JsonToken.VALUE_NULL) {
_properties[index].getProperty().set(bean, null);
return;
}
TokenBuffer merged = new TokenBuffer(p);
merged.writeStartArray();
merged.writeString(typeId);
JsonParser p2 = _tokens[index].asParser(jp);
p2.nextToken();

merged.copyCurrentStructure(p2);
merged.writeEndArray();
// needs to point to START_OBJECT (or whatever first token is)
p2 = merged.asParser(jp);
p2.nextToken();
_properties[index].getProperty().deserializeAndSet(p2, ctxt, bean);
JsonParser mp = merged.asParser(p);
mp.nextToken();
_properties[index].getProperty().deserializeAndSet(mp, ctxt, bean);
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public ExternalBean(int v) {
}
}

// for [Issue#96]
// for [databind#96]
static class ExternalBeanWithDefault
{
@JsonTypeInfo(use=Id.CLASS, include=As.EXTERNAL_PROPERTY, property="extType",
Expand Down Expand Up @@ -158,8 +158,6 @@ public BaseContainer(@JsonProperty("baseContainerProperty") String bcp, @JsonPro
public Base getBase() { return base; }
}

// [JACKSON-831]: should allow a property to map id to as well

interface Pet {}

static class Dog implements Pet {
Expand All @@ -182,7 +180,7 @@ public void setPetType(String petType) {
}
}

// for [Issue#118]
// for [databind#118]
static class ExternalTypeWithNonPOJO {
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
property = "type",
Expand All @@ -199,7 +197,7 @@ public ExternalTypeWithNonPOJO() { }
public ExternalTypeWithNonPOJO(Object o) { value = o; }
}

// for [Issue#119]
// for [databind#119]
static class AsValueThingy {
public long rawDate;

Expand Down Expand Up @@ -281,6 +279,20 @@ public void testImproperExternalIdSerialization() throws Exception
mapper.writeValueAsString(new FunkyExternalBean()));
}

// for [databind#942]
public void testExternalTypeIdWithNull() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.registerSubtypes(ValueBean.class);
ExternalBean b;
b = mapper.readValue(aposToQuotes("{'bean':null,'extType':'vbean'}"),
ExternalBean.class);
assertNotNull(b);
b = mapper.readValue(aposToQuotes("{'extType':'vbean','bean':null}"),
ExternalBean.class);
assertNotNull(b);
}

/*
/**********************************************************
/* Unit tests, deserialization
Expand Down

0 comments on commit 30b5469

Please sign in to comment.