diff --git a/src/main/java/com/ankurm/jackson3/part2modernjava/C04SealedAutoDiscovery.java b/src/main/java/com/ankurm/jackson3/part2modernjava/C04SealedAutoDiscovery.java new file mode 100644 index 0000000..675b596 --- /dev/null +++ b/src/main/java/com/ankurm/jackson3/part2modernjava/C04SealedAutoDiscovery.java @@ -0,0 +1,40 @@ +package com.ankurm.jackson3.part2modernjava; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import tools.jackson.databind.json.JsonMapper; + +/** + * BEYOND THE POST — the Jackson-3-only shortcut. + * + * Jackson 3 introspects the `permits` clause of a sealed type, so @JsonSubTypes + * can be dropped as long as each permitted type carries @JsonTypeName. That + * removes the parallel registry which, in Jackson 2, silently drifts out of sync + * with `permits` whenever someone adds a subtype. + * + * Note there is NO @JsonSubTypes anywhere in this file. + */ +public class C04SealedAutoDiscovery { + + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "shapeType") + public sealed interface Shape permits Circle, Rectangle, Triangle { } + + @JsonTypeName("circle") public record Circle(double radius) implements Shape { } + @JsonTypeName("rectangle") public record Rectangle(double width, double height) implements Shape { } + // Added later. In Jackson 2 this line alone would break deserialisation until + // someone remembered to also add it to @JsonSubTypes. Here it just works. + @JsonTypeName("triangle") public record Triangle(double base, double height) implements Shape { } + + public static void main(String[] args) { + JsonMapper mapper = JsonMapper.builder().build(); + + for (Shape original : new Shape[] { + new Circle(5.0), new Rectangle(10.0, 4.0), new Triangle(3.0, 6.0) }) { + + String json = mapper.writeValueAsString(original); + Shape restored = mapper.readValue(json, Shape.class); + System.out.printf("%-24s -> %-52s -> %s%n", + original.getClass().getSimpleName(), json, restored); + } + } +}