Skip to content

Commit

Permalink
Fix #2567 (wrong target type for failed null check)
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Dec 10, 2019
1 parent a9017ec commit f760b6d
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 26 deletions.
2 changes: 2 additions & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,8 @@ João Guerra (joca-bt@github)
* Reported #2473: Array index missing in path of `JsonMappingException` for `Collection<String>`,
with custom deserializer
(2.10.1)
* Reported #2567: Incorrect target type for arrays when providing nulls and nulls are disabled
(2.10.2)
Ryan Bohn (bohnman@github)
* Reported #2475: `StringCollectionSerializer` calls `JsonGenerator.setCurrentValue(value)`,
Expand Down
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Project: jackson-databind
(reported by Fabian L)
#2560: Check `WRAP_EXCEPTIONS` in `CollectionDeserializer.handleNonArray()`
(reported by Stefan W)
#2567: Incorrect target type for arrays when providing nulls and nulls are disabled
(reported by João G)

2.10.1 (09-Nov-2019)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ protected NullsFailProvider(PropertyName name, JavaType type) {
}

public static NullsFailProvider constructForProperty(BeanProperty prop) {
return new NullsFailProvider(prop.getFullName(), prop.getType());
return constructForProperty(prop, prop.getType());
}

// @since 2.10.2
public static NullsFailProvider constructForProperty(BeanProperty prop, JavaType type) {
return new NullsFailProvider(prop.getFullName(), type);
}

public static NullsFailProvider constructForRootValue(JavaType t) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,11 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
nuller = NullsConstantProvider.skipper();
} else if (nullStyle == Nulls.FAIL) {
if (property == null) {
nuller = NullsFailProvider.constructForRootValue(ctxt.constructType(_valueClass));
// 09-Dec-2019, tatu: [databind#2567] need to ensure correct target type
nuller = NullsFailProvider.constructForRootValue(ctxt.constructType(_valueClass.getComponentType()));
} else {
nuller = NullsFailProvider.constructForProperty(property);
// 09-Dec-2019, tatu: [databind#2567] need to ensure correct target type
nuller = NullsFailProvider.constructForProperty(property, property.getType().getContentType());
}
}
if ((unwrapSingle == _unwrapSingle) && (nuller == _nuller)) {
Expand Down Expand Up @@ -198,29 +200,7 @@ public T deserialize(JsonParser p, DeserializationContext ctxt, T existing) thro
/* Helper methods for sub-classes
/********************************************************
*/

/*
* Convenience method that constructs a concatenation of two arrays,
* with the type they have.
*
* @since 2.9
@SuppressWarnings("unchecked")
public static <T> T concatArrays(T array1, T array2)
{
int len1 = Array.getLength(array1);
if (len1 == 0) {
return array2;
}
int len2 = Array.getLength(array2);
if (len2 == 0) {
return array1;
}
Object result = Arrays.copyOf((Object[]) array1, len1 + len2);
System.arraycopy(array2, 0, result, len1, len2);
return (T) result;
}
*/


@SuppressWarnings("unchecked")
protected T handleNonArray(JsonParser p, DeserializationContext ctxt) throws IOException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,20 @@ protected NullValueProvider findContentNullProvider(DeserializationContext ctxt,
if (nulls == Nulls.SKIP) {
return NullsConstantProvider.skipper();
}
// 09-Dec-2019, tatu: [databind#2567] need to ensure correct target type (element,
// not container), so inlined here before calling _findNullProvider
if (nulls == Nulls.FAIL) {
if (prop == null) {
JavaType type = ctxt.constructType(valueDeser.handledType());
// should always be container? But let's double-check just in case:
if (type.isContainerType()) {
type = type.getContentType();
}
return NullsFailProvider.constructForRootValue(type);
}
return NullsFailProvider.constructForProperty(prop, prop.getType().getContentType());
}

NullValueProvider prov = _findNullProvider(ctxt, prop, nulls, valueDeser);
if (prov != null) {
return prov;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public void testFailOnNullFromDefaults() throws Exception
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"values\"");
assertEquals(String.class, e.getTargetType());
}

// or configured for type:
Expand All @@ -73,6 +74,7 @@ public void testFailOnNullFromDefaults() throws Exception
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"values\"");
assertEquals(String.class, e.getTargetType());
}
}

Expand All @@ -96,6 +98,7 @@ public void testFailOnNullWithCollections() throws Exception
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"noNulls\"");
assertEquals(Integer.class, e.getTargetType());
}

// List<String>
Expand All @@ -104,6 +107,7 @@ public void testFailOnNullWithCollections() throws Exception
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"noNulls\"");
assertEquals(String.class, e.getTargetType());
}
}

Expand All @@ -116,6 +120,7 @@ public void testFailOnNullWithArrays() throws Exception
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"noNulls\"");
assertEquals(Object.class, e.getTargetType());
}

// String[]
Expand All @@ -124,6 +129,7 @@ public void testFailOnNullWithArrays() throws Exception
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"noNulls\"");
assertEquals(String.class, e.getTargetType());
}
}

Expand All @@ -137,20 +143,23 @@ public void testFailOnNullWithPrimitiveArrays() throws Exception
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"noNulls\"");
assertEquals(Boolean.TYPE, e.getTargetType());
}
// int[]
try {
MAPPER.readValue(JSON, new TypeReference<NullContentFail<int[]>>() { });
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"noNulls\"");
assertEquals(Integer.TYPE, e.getTargetType());
}
// double[]
try {
MAPPER.readValue(JSON, new TypeReference<NullContentFail<double[]>>() { });
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"noNulls\"");
assertEquals(Double.TYPE, e.getTargetType());
}
}

Expand All @@ -163,6 +172,7 @@ public void testFailOnNullWithMaps() throws Exception
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"noNulls\"");
assertEquals(String.class, e.getTargetType());
}

// Then: EnumMap<Enum,String>
Expand All @@ -172,6 +182,7 @@ public void testFailOnNullWithMaps() throws Exception
fail("Should not pass");
} catch (InvalidNullException e) {
verifyException(e, "property \"noNulls\"");
assertEquals(String.class, e.getTargetType());
}
}

Expand Down

0 comments on commit f760b6d

Please sign in to comment.