Skip to content

Commit 30b5469

Browse files
committed
Fix #942 (slightly differently)
1 parent 04cb084 commit 30b5469

File tree

4 files changed

+59
-27
lines changed

4 files changed

+59
-27
lines changed

release-notes/CREDITS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,7 @@ Andreas Pieber (anpieber@github)
336336
Jesse Wilson (swankjesse@github)
337337
* Contributed #949: Report the offending substring when number parsing fails
338338
(2.6.3)
339+
340+
Warren Bloomer (stormboy@github)
341+
* Reported #942: Handle null type id for polymorphic values that use external type id
342+
(2.6.3)

release-notes/VERSION

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Project: jackson-databind
1616
(contributed by Sergio M)
1717
#941: Deserialization from "{}" to ObjectNode field causes "out of END_OBJECT token" error
1818
(reported by Sadayuki F)
19+
#942: Handle null type id for polymorphic values that use external type id
20+
(reported by Warren B, stormboy@github)
1921
#943: Incorrect serialization of enum map key
2022
(reported by Benson M)
2123
#944: Failure to use custom deserializer for key deserializer

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

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,13 @@ public boolean handlePropertyValue(JsonParser jp, DeserializationContext ctxt,
121121
}
122122
return true;
123123
}
124-
124+
125+
/**
126+
* Method called after JSON Object closes, and has to ensure that all external
127+
* type ids have been handled.
128+
*/
125129
@SuppressWarnings("resource")
126-
public Object complete(JsonParser jp, DeserializationContext ctxt, Object bean)
130+
public Object complete(JsonParser p, DeserializationContext ctxt, Object bean)
127131
throws IOException
128132
{
129133
for (int i = 0, len = _properties.length; i < len; ++i) {
@@ -135,20 +139,19 @@ public Object complete(JsonParser jp, DeserializationContext ctxt, Object bean)
135139
if (tokens == null) {
136140
continue;
137141
}
138-
/* [Issue#118]: Need to mind natural types, for which no type id
139-
* will be included.
140-
*/
142+
// [databind#118]: Need to mind natural types, for which no type id
143+
// will be included.
141144
JsonToken t = tokens.firstToken();
142145
if (t != null && t.isScalarValue()) {
143-
JsonParser buffered = tokens.asParser(jp);
146+
JsonParser buffered = tokens.asParser(p);
144147
buffered.nextToken();
145148
SettableBeanProperty extProp = _properties[i].getProperty();
146149
Object result = TypeDeserializer.deserializeIfNatural(buffered, ctxt, extProp.getType());
147150
if (result != null) {
148151
extProp.set(bean, result);
149152
continue;
150153
}
151-
// 26-Oct-2012, tatu: As per [Issue#94], must allow use of 'defaultImpl'
154+
// 26-Oct-2012, tatu: As per [databind#94], must allow use of 'defaultImpl'
152155
if (!_properties[i].hasDefaultType()) {
153156
throw ctxt.mappingException("Missing external type id property '%s'",
154157
_properties[i].getTypePropertyName());
@@ -160,7 +163,7 @@ public Object complete(JsonParser jp, DeserializationContext ctxt, Object bean)
160163
throw ctxt.mappingException("Missing property '%s' for external type id '%s'",
161164
prop.getName(), _properties[i].getTypePropertyName());
162165
}
163-
_deserializeAndSet(jp, ctxt, bean, i, typeId);
166+
_deserializeAndSet(p, ctxt, bean, i, typeId);
164167
}
165168
return bean;
166169
}
@@ -216,41 +219,52 @@ public Object complete(JsonParser jp, DeserializationContext ctxt,
216219
}
217220

218221
@SuppressWarnings("resource")
219-
protected final Object _deserialize(JsonParser jp, DeserializationContext ctxt,
222+
protected final Object _deserialize(JsonParser p, DeserializationContext ctxt,
220223
int index, String typeId) throws IOException
221224
{
222-
TokenBuffer merged = new TokenBuffer(jp);
225+
JsonParser p2 = _tokens[index].asParser(p);
226+
JsonToken t = p2.nextToken();
227+
// 29-Sep-2015, tatu: As per [databind#942], nulls need special support
228+
if (t == JsonToken.VALUE_NULL) {
229+
return null;
230+
}
231+
232+
TokenBuffer merged = new TokenBuffer(p);
223233
merged.writeStartArray();
224234
merged.writeString(typeId);
225-
JsonParser p2 = _tokens[index].asParser(jp);
226-
p2.nextToken();
227235
merged.copyCurrentStructure(p2);
228236
merged.writeEndArray();
229237

230238
// needs to point to START_OBJECT (or whatever first token is)
231-
p2 = merged.asParser(jp);
232-
p2.nextToken();
233-
return _properties[index].getProperty().deserialize(p2, ctxt);
239+
JsonParser mp = merged.asParser(p);
240+
mp.nextToken();
241+
return _properties[index].getProperty().deserialize(mp, ctxt);
234242
}
235243

236244
@SuppressWarnings("resource")
237-
protected final void _deserializeAndSet(JsonParser jp, DeserializationContext ctxt,
245+
protected final void _deserializeAndSet(JsonParser p, DeserializationContext ctxt,
238246
Object bean, int index, String typeId) throws IOException
239247
{
240248
/* Ok: time to mix type id, value; and we will actually use "wrapper-array"
241249
* style to ensure we can handle all kinds of JSON constructs.
242250
*/
243-
TokenBuffer merged = new TokenBuffer(jp);
251+
JsonParser p2 = _tokens[index].asParser(p);
252+
JsonToken t = p2.nextToken();
253+
// 29-Sep-2015, tatu: As per [databind#942], nulls need special support
254+
if (t == JsonToken.VALUE_NULL) {
255+
_properties[index].getProperty().set(bean, null);
256+
return;
257+
}
258+
TokenBuffer merged = new TokenBuffer(p);
244259
merged.writeStartArray();
245260
merged.writeString(typeId);
246-
JsonParser p2 = _tokens[index].asParser(jp);
247-
p2.nextToken();
261+
248262
merged.copyCurrentStructure(p2);
249263
merged.writeEndArray();
250264
// needs to point to START_OBJECT (or whatever first token is)
251-
p2 = merged.asParser(jp);
252-
p2.nextToken();
253-
_properties[index].getProperty().deserializeAndSet(p2, ctxt, bean);
265+
JsonParser mp = merged.asParser(p);
266+
mp.nextToken();
267+
_properties[index].getProperty().deserializeAndSet(mp, ctxt, bean);
254268
}
255269

256270
/*

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

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public ExternalBean(int v) {
2323
}
2424
}
2525

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

161-
// [JACKSON-831]: should allow a property to map id to as well
162-
163161
interface Pet {}
164162

165163
static class Dog implements Pet {
@@ -182,7 +180,7 @@ public void setPetType(String petType) {
182180
}
183181
}
184182

185-
// for [Issue#118]
183+
// for [databind#118]
186184
static class ExternalTypeWithNonPOJO {
187185
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
188186
property = "type",
@@ -199,7 +197,7 @@ public ExternalTypeWithNonPOJO() { }
199197
public ExternalTypeWithNonPOJO(Object o) { value = o; }
200198
}
201199

202-
// for [Issue#119]
200+
// for [databind#119]
203201
static class AsValueThingy {
204202
public long rawDate;
205203

@@ -281,6 +279,20 @@ public void testImproperExternalIdSerialization() throws Exception
281279
mapper.writeValueAsString(new FunkyExternalBean()));
282280
}
283281

282+
// for [databind#942]
283+
public void testExternalTypeIdWithNull() throws Exception
284+
{
285+
ObjectMapper mapper = new ObjectMapper();
286+
mapper.registerSubtypes(ValueBean.class);
287+
ExternalBean b;
288+
b = mapper.readValue(aposToQuotes("{'bean':null,'extType':'vbean'}"),
289+
ExternalBean.class);
290+
assertNotNull(b);
291+
b = mapper.readValue(aposToQuotes("{'extType':'vbean','bean':null}"),
292+
ExternalBean.class);
293+
assertNotNull(b);
294+
}
295+
284296
/*
285297
/**********************************************************
286298
/* Unit tests, deserialization

0 commit comments

Comments
 (0)