Skip to content

(complete #4858): actually change default FAIL_ON_NULL_FOR_PRIMITIVES to true #4890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jan 9, 2025
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public enum DeserializationFeature implements ConfigFeature
*<p>
* Feature is enabled by default as of Jackson 3.0 (in 2.x it was disabled).
*/
FAIL_ON_NULL_FOR_PRIMITIVES(false),
FAIL_ON_NULL_FOR_PRIMITIVES(true),

/**
* Feature that determines whether JSON integer numbers are valid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ public BooleanWrapper(@JsonProperty("ctor") Boolean foo) {
public void setPrimitive(boolean v) { primitive = v; }
}

private final ObjectMapper DEFAULT_MAPPER = newJsonMapper();
private final ObjectMapper DEFAULT_MAPPER = jsonMapperBuilder()
Copy link
Member

@cowtowncoder cowtowncoder Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test failure for boolean[] looks suspicious; I am not sure it should fail. Others in this package were legit, merged change in 2.19 to ensure consistent test code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is the only odd case, I think that's ok -- can investigate in future if necessary but good enough for now.

.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.build();

private final ObjectMapper LEGACY_NONCOERCING_MAPPER = jsonMapperBuilder()
.disable(MapperFeature.ALLOW_COERCION_OF_SCALARS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;

import tools.jackson.databind.*;
import tools.jackson.databind.annotation.JsonDeserialize;
import tools.jackson.databind.testutil.DatabindTestUtil;

import static org.junit.jupiter.api.Assertions.assertNotNull;

//first for [databind#1978] but follow up for [databind#1979]
public class BuilderInfiniteLoop1979Test
extends DatabindTestUtil
{
static class Builder
{
Expand Down Expand Up @@ -93,8 +94,7 @@ static class SubBean
public void testInfiniteLoop1978() throws Exception
{
String json = "{\"sub.el1\":34,\"sub.el2\":\"some text\"}";
ObjectMapper mapper = new ObjectMapper();
Bean bean = mapper.readValue( json, Bean.class );
Bean bean = sharedMapper().readValue( json, Bean.class );
assertNotNull(bean);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ public Person(@JsonProperty(value="name") String name,
}
}

private final ObjectReader PERSON_READER = sharedMapper().readerFor(Person.class);
private final ObjectReader PERSON_READER = sharedMapper()
.readerFor(Person.class)
.without(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);

@Test
public void testRequiredNonNullParam() throws Exception
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public MyBeanValue deserialize(JsonParser jp, DeserializationContext ctxt)
/**********************************************************************
*/

private final ObjectMapper MAPPER = new ObjectMapper();
private final ObjectMapper MAPPER = newJsonMapper();

@Test
public void testNaN() throws Exception
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ public void testCanonicalConstructor2ArgPropertiesCreator() throws Exception
assertEquals(POJO4584.factoryString(null),
readerWith(new PrimaryCreatorFindingIntrospector(JsonCreator.Mode.PROPERTIES,
String.class, Integer.TYPE))
.without(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.readValue(a2q("{}")));
.without(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.readValue(a2q("{}")));
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,11 @@ public static Orange getOrange(@JsonProperty("name") String name, @JsonProperty(
{
final ObjectMapper mapper = new ObjectMapper();
BOX_READER_PASS = mapper.readerFor(Box.class)
.without(DeserializationFeature.FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY);
.without(DeserializationFeature.FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY)
.without(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
BOX_READER_FAIL = mapper.readerFor(Box.class)
.with(DeserializationFeature.FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY);
.with(DeserializationFeature.FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY)
.without(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public class SimpleModuleTest extends DatabindTestUtil
final static class CustomBean
{
protected String str;
protected int num;
protected Integer num;

public CustomBean(String s, int i) {
public CustomBean(String s, Integer i) {
str = s;
num = i;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.PropertyAccessor;

import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.cfg.MapperConfig;
import tools.jackson.databind.introspect.AnnotatedClass;
Expand Down Expand Up @@ -60,7 +61,8 @@ private record PrivateRecord3906(String string, int integer) {
@Test
public void testEmptyJsonToRecordWorkAround() throws Exception {
ObjectMapper mapper = jsonMapperBuilder()
.changeDefaultVisibility(vc ->
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.changeDefaultVisibility(vc ->
vc.withVisibility(PropertyAccessor.ALL, Visibility.NONE)
.withVisibility(PropertyAccessor.CREATOR, Visibility.ANY))
.build();
Expand All @@ -72,7 +74,8 @@ public void testEmptyJsonToRecordWorkAround() throws Exception {
@Test
public void testEmptyJsonToRecordCreatorsVisible() throws Exception {
ObjectMapper mapper = jsonMapperBuilder()
.changeDefaultVisibility(vc ->
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.changeDefaultVisibility(vc ->
vc.withVisibility(PropertyAccessor.CREATOR, Visibility.NON_PRIVATE))
.build();

Expand All @@ -97,23 +100,29 @@ public VisibilityChecker findAutoDetectVisibility(MapperConfig<?> cfg,
}
});
}
}).build();
})
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.build();

Record3906 recordDeser = mapper.readValue("{}", Record3906.class);
assertEquals(new Record3906(null, 0), recordDeser);
}

@Test
public void testEmptyJsonToRecordDirectAutoDetectConfig() throws Exception {
ObjectMapper mapper = newJsonMapper();
ObjectMapper mapper = jsonMapperBuilder()
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.build();

Record3906Annotated recordDeser = mapper.readValue("{}", Record3906Annotated.class);
assertEquals(new Record3906Annotated(null, 0), recordDeser);
}

@Test
public void testEmptyJsonToRecordJsonCreator() throws Exception {
ObjectMapper mapper = newJsonMapper();
ObjectMapper mapper = jsonMapperBuilder()
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.build();

Record3906Creator recordDeser = mapper.readValue("{}", Record3906Creator.class);
assertEquals(new Record3906Creator(null, 0), recordDeser);
Expand Down Expand Up @@ -143,6 +152,7 @@ public VisibilityChecker findAutoDetectVisibility(MapperConfig<?> cfg,
});
}
})
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.build();

assertEquals(new Record3906(null, 0),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public static RecordWithExplicitFactoryMethod valueOf(String value) {
private final ObjectMapper MAPPER = jsonMapperBuilder()
.disable(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS) // So that test cases don't have to assert weird error messages
.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.build();

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.Nulls;

import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.cfg.CoercionAction;
import tools.jackson.databind.cfg.CoercionInputShape;
Expand Down Expand Up @@ -43,6 +44,10 @@ public record FixedRecord(@JsonProperty("field_name") String fieldName) {}
.withCoercionConfigDefaults(config -> config.setCoercion(CoercionInputShape.String, CoercionAction.Fail))
.build();

private final ObjectMapper DEFAULT_MAPPER = jsonMapperBuilder()
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.build();

@Test
public void testPojoNullHandlingValid() throws Exception {
Pojo3847 pojo = NULL_MAPPER.readValue(a2q("{'fieldName': 'value'}"), Pojo3847.class); // expected
Expand Down Expand Up @@ -118,13 +123,14 @@ public void testRecordFixerNullHandlingEmptyJson() throws Exception {

@Test
public void testRecordDefaultNullDeserialization() throws Exception {
PlainRecord pr = new ObjectMapper().readValue("{}", PlainRecord.class);
PlainRecord pr = DEFAULT_MAPPER.readValue("{}", PlainRecord.class);
assertNull(pr.fieldName);
}

@Test
public void testIntRecordDefaultNullDeserialization() throws Exception {
IntRecord ir = new ObjectMapper().readValue("{}", IntRecord.class);
IntRecord ir = DEFAULT_MAPPER.readerFor(IntRecord.class)
.readValue("{}");
assertNull(ir.description);
assertEquals(0, ir.value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.testutil.DatabindTestUtil;

Expand Down Expand Up @@ -104,7 +105,10 @@ public void testSerializeJsonIgnorePrimitiveTypeRecord() throws Exception {

@Test
public void testDeserializeJsonIgnorePrimitiveTypeRecord() throws Exception {
RecordWithIgnorePrimitiveType value = MAPPER.readValue("{\"id\":123,\"name\":\"Bob\"}", RecordWithIgnorePrimitiveType.class);
RecordWithIgnorePrimitiveType value = jsonMapperBuilder()
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.build()
.readValue("{\"id\":123,\"name\":\"Bob\"}", RecordWithIgnorePrimitiveType.class);
assertEquals(new RecordWithIgnorePrimitiveType(0, "Bob"), value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;

import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.testutil.DatabindTestUtil;

Expand Down Expand Up @@ -52,7 +53,9 @@ public RecordWithReadOnlyAllAndNoArgConstructor() {
}
}

private final ObjectMapper MAPPER = newJsonMapper();
private final ObjectMapper MAPPER = jsonMapperBuilder()
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.build();

/*
/**********************************************************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public void testWithCreator() throws Exception
{
ObjectReader r = MAPPER.readerFor(CreatorValue.class)
.without(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);

CreatorValue value = r.readValue("[1,2,3]");
assertEquals(1, value.a);
assertEquals(2, value.b);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public void testBooleanPrimitiveArrayUnwrap() throws Exception
// [databind#381]
ObjectMapper mapper = jsonMapperBuilder()
.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)
.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
.build();
BooleanBean result = mapper.readValue(new StringReader("{\"v\":[true]}"), BooleanBean.class);
assertTrue(result._v);
Expand Down