From 439bc33e7d457462b8efe6dfd7bd331c89a21c9b Mon Sep 17 00:00:00 2001 From: asmhatre Date: Tue, 4 Aug 2026 17:32:58 +0000 Subject: [PATCH] Part 5: all four @JsonTypeInfo include strategies, executed --- .../F03IncludeStrategies.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/main/java/com/ankurm/jackson3/part5polymorphic/F03IncludeStrategies.java diff --git a/src/main/java/com/ankurm/jackson3/part5polymorphic/F03IncludeStrategies.java b/src/main/java/com/ankurm/jackson3/part5polymorphic/F03IncludeStrategies.java new file mode 100644 index 0000000..75025f0 --- /dev/null +++ b/src/main/java/com/ankurm/jackson3/part5polymorphic/F03IncludeStrategies.java @@ -0,0 +1,54 @@ +package com.ankurm.jackson3.part5polymorphic; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import tools.jackson.databind.json.JsonMapper; + +/** + * Post: Polymorphic Deserialisation — https://ankurm.com/jackson-polymorphic-deserialization/ + * Section: "@JsonTypeInfo Placement Options" + * + * The post gives a table of the four include strategies. This runs all four so you + * can see the actual wire format instead of trusting the table. + */ +public class F03IncludeStrategies { + + // ---- As.PROPERTY: discriminator is an ordinary field inside the object ---- + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "kind") + @JsonSubTypes(@JsonSubTypes.Type(value = PropCard.class, name = "card")) + public interface PropBase { } + public record PropCard(double amountDue) implements PropBase { } + + // ---- As.WRAPPER_OBJECT: object wrapped in a single-key envelope ---- + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) + @JsonSubTypes(@JsonSubTypes.Type(value = WrapObjCard.class, name = "card")) + public interface WrapObjBase { } + public record WrapObjCard(double amountDue) implements WrapObjBase { } + + // ---- As.WRAPPER_ARRAY: two-element [name, object] array ---- + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_ARRAY) + @JsonSubTypes(@JsonSubTypes.Type(value = WrapArrCard.class, name = "card")) + public interface WrapArrBase { } + public record WrapArrCard(double amountDue) implements WrapArrBase { } + + // ---- As.EXISTING_PROPERTY: reuses a field the class already declares ---- + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, + property = "kind", visible = true) + @JsonSubTypes(@JsonSubTypes.Type(value = ExistingCard.class, name = "card")) + public interface ExistingBase { String kind(); } + public record ExistingCard(String kind, double amountDue) implements ExistingBase { } + + public static void main(String[] args) { + JsonMapper mapper = JsonMapper.builder().build(); + + System.out.println("PROPERTY : " + mapper.writeValueAsString((PropBase) new PropCard(99.0))); + System.out.println("WRAPPER_OBJECT : " + mapper.writeValueAsString((WrapObjBase) new WrapObjCard(99.0))); + System.out.println("WRAPPER_ARRAY : " + mapper.writeValueAsString((WrapArrBase) new WrapArrCard(99.0))); + System.out.println("EXISTING_PROPERTY : " + mapper.writeValueAsString((ExistingBase) new ExistingCard("card", 99.0))); + + // Each form reads back to the correct concrete type. + System.out.println("read PROPERTY -> " + mapper.readValue("{\"kind\":\"card\",\"amountDue\":99.0}", PropBase.class)); + System.out.println("read WRAPPER_OBJECT -> " + mapper.readValue("{\"card\":{\"amountDue\":99.0}}", WrapObjBase.class)); + System.out.println("read WRAPPER_ARRAY -> " + mapper.readValue("[\"card\",{\"amountDue\":99.0}]", WrapArrBase.class)); + } +}