-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Closed
Labels
3.0Issue planned for initial 3.0 releaseIssue planned for initial 3.0 release
Milestone
Description
Search before asking
- I searched in the issues and found nothing similar.
Describe the bug
Optional handling differs between Jackson 2.x and 3.0 despite the information that Jdk8 module was pulled in to core.
Version Information
3.0
Reproduction
I have a record class with an Optional field. When I use JsonMapper from Jackson 3.0, I'm unable to configure it in a way that will inject Optional.empty if either value is null or absent in the JSON.
Works in Jackson 2.x:
public class TestOptional
{
public static void main(String[] args) throws JsonProcessingException {
JsonMapper.Builder builder = JsonMapper.builder();
builder.addModule(new Jdk8Module());
builder.defaultPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.NON_ABSENT, JsonInclude.Include.ALWAYS));
Person person = new Person("Alice", Optional.empty());
ObjectMapper mapper = builder.build();
System.out.println(mapper.writeValueAsString(person));
System.out.println(mapper.readValue(mapper.writeValueAsString(person), Person.class));
System.out.println(mapper.readValue("{\"name\": \"Alice\"}}", Person.class));
System.out.println(mapper.readValue("{\"name\": \"Alice\", \"nickname\": null}}", Person.class));
}
record Person(String name, Optional<String> nickname)
{
public Person {
requireNonNull(name, "name is null");
requireNonNull(nickname, "nickname is null");
}
}
}
Doesn't work in Jackson 3:
public class TestOptional
{
public static void main(String[] args)
{
JsonMapper.Builder builder = JsonMapper.builder();
builder.changeDefaultPropertyInclusion(_ -> JsonInclude.Value.construct(JsonInclude.Include.NON_ABSENT, JsonInclude.Include.ALWAYS));
Person person = new Person("Alice", Optional.empty());
ObjectMapper mapper = builder.build();
System.out.println(mapper.writeValueAsString(person));
System.out.println(mapper.readValue(mapper.writeValueAsString(person), Person.class));
System.out.println(mapper.readValue("{\"name\": \"Alice\"}}", Person.class));
System.out.println(mapper.readValue("{\"name\": \"Alice\", \"nickname\": null}}", Person.class));
}
record Person(String name, Optional<String> nickname)
{
public Person {
requireNonNull(name, "name is null");
requireNonNull(nickname, "nickname is null");
}
}
}
Result:
{"name":"Alice"}
Exception in thread "main" tools.jackson.databind.exc.ValueInstantiationException: Cannot construct instance of `io.airlift.json.TestOptional$Person`, problem: nickname is null
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); byte offset: #UNKNOWN]
at tools.jackson.databind.exc.ValueInstantiationException.from(ValueInstantiationException.java:44)
at tools.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:2076)
at tools.jackson.databind.deser.std.StdValueInstantiator.wrapAsDatabindException(StdValueInstantiator.java:581)
at tools.jackson.databind.deser.std.StdValueInstantiator.rewrapCtorProblem(StdValueInstantiator.java:602)
at tools.jackson.databind.deser.std.StdValueInstantiator.createFromObjectWith(StdValueInstantiator.java:289)
at tools.jackson.databind.deser.ValueInstantiator.createFromObjectWith(ValueInstantiator.java:270)
at tools.jackson.databind.deser.bean.PropertyBasedCreator.build(PropertyBasedCreator.java:252)
at tools.jackson.databind.deser.bean.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:697)
at tools.jackson.databind.deser.bean.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1417)
at tools.jackson.databind.deser.bean.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:480)
at tools.jackson.databind.deser.bean.BeanDeserializer.deserialize(BeanDeserializer.java:200)
at tools.jackson.databind.deser.DeserializationContextExt.readRootValue(DeserializationContextExt.java:265)
at tools.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2610)
at tools.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1522)
at io.airlift.json.TestOptional.main(TestOptional.java:22)
Caused by: java.lang.NullPointerException: nickname is null
at java.base/java.util.Objects.requireNonNull(Objects.java:246)
at io.airlift.json.TestOptional$Person.<init>(TestOptional.java:31)
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:735)
at tools.jackson.databind.introspect.AnnotatedConstructor.call(AnnotatedConstructor.java:113)
at tools.jackson.databind.deser.std.StdValueInstantiator.createFromObjectWith(StdValueInstantiator.java:287)
... 10 more
Process finished with exit code 1
Expected behavior
Optionals should work :)
Additional context
No response
Metadata
Metadata
Assignees
Labels
3.0Issue planned for initial 3.0 releaseIssue planned for initial 3.0 release