diff --git a/src/main/java/com/ankurm/jackson3/part6streaming/G03TreeModelNavigation.java b/src/main/java/com/ankurm/jackson3/part6streaming/G03TreeModelNavigation.java new file mode 100644 index 0000000..3f9c684 --- /dev/null +++ b/src/main/java/com/ankurm/jackson3/part6streaming/G03TreeModelNavigation.java @@ -0,0 +1,50 @@ +package com.ankurm.jackson3.part6streaming; + +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.json.JsonMapper; + +/** + * Post: Streaming API and JsonNode — https://ankurm.com/jackson-streaming-api-jsonnode/ + * Sections: "The Tree Model" and "Mixing Tree Model with Data Binding" + * + * Jackson 3 difference: JsonNode.asText() is now asString(). asInt() survives. + */ +public class G03TreeModelNavigation { + + public record CustomerRecord(String name, String tier) { } + + private static final String JSON = "{" + + "\"orderId\":1001," + + "\"customer\":{\"name\":\"Alice\",\"tier\":\"gold\"}," + + "\"items\":[{\"sku\":\"KB-01\",\"qty\":2},{\"sku\":\"MS-42\",\"qty\":1}]" + + "}"; + + public static void main(String[] args) { + JsonMapper mapper = JsonMapper.builder().build(); + + JsonNode rootNode = mapper.readTree(JSON); + + // path() never returns null — a missing node is a MissingNode. + String customerName = rootNode.path("customer").path("name").asString(); + System.out.println("Customer: " + customerName); + + for (JsonNode itemNode : rootNode.path("items")) { + System.out.println(itemNode.path("sku").asString() + " x" + itemNode.path("qty").asInt()); + } + + System.out.println("Has discount: " + rootNode.has("discountCode")); + + // path() vs get() on an absent field — the difference that causes NPEs. + System.out.println("path(missing) : " + rootNode.path("nope") + + " (class " + rootNode.path("nope").getClass().getSimpleName() + ")"); + System.out.println("get(missing) : " + rootNode.get("nope")); + + // Deep navigation stays null-safe all the way down. + System.out.println("deep path : '" + + rootNode.path("a").path("b").path("c").asString("") + "'"); + + // Switch from tree to data binding at any node. + CustomerRecord customer = mapper.treeToValue(rootNode.path("customer"), CustomerRecord.class); + System.out.println("treeToValue : " + customer); + } +}