diff --git a/src/main/java/com/ankurm/jackson3/part2modernjava/C02OptionalFields.java b/src/main/java/com/ankurm/jackson3/part2modernjava/C02OptionalFields.java new file mode 100644 index 0000000..d682b29 --- /dev/null +++ b/src/main/java/com/ankurm/jackson3/part2modernjava/C02OptionalFields.java @@ -0,0 +1,51 @@ +package com.ankurm.jackson3.part2modernjava; + +import com.fasterxml.jackson.annotation.JsonInclude; +import tools.jackson.databind.json.JsonMapper; + +import java.util.Optional; + +/** + * Post: Jackson with Records, Optionals, Sealed Classes + * https://ankurm.com/jackson-java-records-optionals/ + * Section: "Jackson with Optional" + * + * Jackson 3 handles Optional natively. There is no jackson-datatype-jdk8 + * dependency in the pom and no registerModule(new Jdk8Module()) call — those are + * Jackson 2 requirements, and the Jdk8Module class does not exist under + * tools.jackson at all. + */ +public class C02OptionalFields { + + public record CustomerProfile(String customerName, Optional middleName) { } + + /** NON_ABSENT is the inclusion value that understands Optional.empty(). */ + @JsonInclude(JsonInclude.Include.NON_ABSENT) + public record CompactProfile(String customerName, Optional middleName) { } + + public static void main(String[] args) { + JsonMapper mapper = JsonMapper.builder().build(); + + // Present value: the Optional is unwrapped, not wrapped in {"present":true}. + System.out.println("present : " + + mapper.writeValueAsString(new CustomerProfile("Alice", Optional.of("Marie")))); + + // Empty Optional: serialises as null by default. + System.out.println("empty : " + + mapper.writeValueAsString(new CustomerProfile("Bob", Optional.empty()))); + + // NON_ABSENT omits the property entirely instead of writing null. + System.out.println("absent : " + + mapper.writeValueAsString(new CompactProfile("Bob", Optional.empty()))); + + // Deserialise back. + String json = "{\"customerName\":\"Alice\",\"middleName\":\"Marie\"}"; + CustomerProfile restored = mapper.readValue(json, CustomerProfile.class); + System.out.println("isPresent: " + restored.middleName().isPresent()); + + // A missing property deserialises to Optional.empty(), never to null. + CustomerProfile missing = mapper.readValue("{\"customerName\":\"Carol\"}", CustomerProfile.class); + System.out.println("missing -> " + missing.middleName() + " (null? " + + (missing.middleName() == null) + ")"); + } +}