From 1f45c66dcd85944d91aa80e3e6c03507e3163bbe Mon Sep 17 00:00:00 2001 From: Jan Bernitt Date: Wed, 13 May 2026 14:45:42 +0200 Subject: [PATCH 1/3] fix: consider @Validation#type in Property NodeType --- .../hisp/dhis/jsontree/JsonAbstractArray.java | 2 +- .../hisp/dhis/jsontree/JsonVirtualTree.java | 7 +++--- .../org/hisp/dhis/jsontree/Validation.java | 14 +++++++---- .../org/hisp/dhis/jsontree/JsonNodeTest.java | 24 +++++++++++++++++++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/hisp/dhis/jsontree/JsonAbstractArray.java b/src/main/java/org/hisp/dhis/jsontree/JsonAbstractArray.java index 493eb95..b7e270e 100644 --- a/src/main/java/org/hisp/dhis/jsontree/JsonAbstractArray.java +++ b/src/main/java/org/hisp/dhis/jsontree/JsonAbstractArray.java @@ -83,7 +83,7 @@ default boolean containsAll(Function toValue, Collection values) { */ @TerminalOp(canBeUndefined = true, mustBeArray = true) default boolean contains(Function toValue, Predicate test) { - return count(toValue, test) > 0; + return stream().anyMatch(e -> test.test(toValue.apply(e))); } /** diff --git a/src/main/java/org/hisp/dhis/jsontree/JsonVirtualTree.java b/src/main/java/org/hisp/dhis/jsontree/JsonVirtualTree.java index c89eb74..a71afce 100644 --- a/src/main/java/org/hisp/dhis/jsontree/JsonVirtualTree.java +++ b/src/main/java/org/hisp/dhis/jsontree/JsonVirtualTree.java @@ -505,12 +505,11 @@ private static List componentProperties(Class of) { .map( c -> { - Class jsonType = Validation.NodeType.toJsonType(c.getType()); return new Property( of, Text.of(c.getName()), - jsonType, - Validation.NodeType.ofJsonType(jsonType), + Validation.NodeType.toJsonType(c.getType()), + Validation.NodeType.of(c.getType()), c.getName(), c.getAnnotatedType(), c); @@ -541,7 +540,7 @@ private static List captureProperties(Class of) in, name, type, - Validation.NodeType.ofJsonType(type), + Validation.NodeType.of(type), method.getName(), method.getAnnotatedReturnType(), method)); diff --git a/src/main/java/org/hisp/dhis/jsontree/Validation.java b/src/main/java/org/hisp/dhis/jsontree/Validation.java index 4efc9b7..b8dcfef 100644 --- a/src/main/java/org/hisp/dhis/jsontree/Validation.java +++ b/src/main/java/org/hisp/dhis/jsontree/Validation.java @@ -168,10 +168,14 @@ public static NodeType of(@CheckNull JsonNodeType type) { @NotNull @SuppressWarnings("unchecked") public static Set of(@NotNull Class type) { - return ofJsonType( - JsonValue.class.isAssignableFrom(type) - ? (Class) type - : toJsonType(type)); + if (type.isAnnotationPresent(Validation.class)) { + Validation validation = type.getAnnotation(Validation.class); + NodeType[] types = validation.type(); + if (types.length > 0) return EnumSet.of(types[0], types); + } + if (JsonValue.class.isAssignableFrom(type)) + return ofJsonType((Class) type); + return ofJsonType(toJsonType(type)); } static Class toJsonType(Class type) { @@ -194,7 +198,7 @@ static Class toJsonType(Class type) { } @SuppressWarnings("unchecked") - static Set ofJsonType(Class type) { + private static Set ofJsonType(Class type) { Validation validation = type.getAnnotation(Validation.class); if (validation != null) { NodeType[] types = validation.type(); diff --git a/src/test/java/org/hisp/dhis/jsontree/JsonNodeTest.java b/src/test/java/org/hisp/dhis/jsontree/JsonNodeTest.java index 370921a..e7e2f35 100644 --- a/src/test/java/org/hisp/dhis/jsontree/JsonNodeTest.java +++ b/src/test/java/org/hisp/dhis/jsontree/JsonNodeTest.java @@ -27,7 +27,11 @@ */ package org.hisp.dhis.jsontree; +import static org.hisp.dhis.jsontree.JsonNode.Index.ADD; import static org.hisp.dhis.jsontree.JsonNode.Index.AUTO; +import static org.hisp.dhis.jsontree.JsonNode.Index.AUTO_SKIP; +import static org.hisp.dhis.jsontree.JsonNode.Index.CHECK; +import static org.hisp.dhis.jsontree.JsonNode.Index.SKIP; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; @@ -35,6 +39,7 @@ import java.util.Deque; import java.util.LinkedList; +import java.util.List; import java.util.Set; import org.junit.jupiter.api.Test; @@ -266,6 +271,25 @@ void testGetListener_AbstractMethod_DoesExist() { assertEquals(".bar", rec.getLast().toString()); } + @Test + void testIndexResolve() { + // AUTO on tree keeps the operation level + assertEquals(SKIP, SKIP.resolve(AUTO)); + assertEquals(SKIP, AUTO_SKIP.resolve(AUTO)); + assertEquals(CHECK, CHECK.resolve(AUTO)); + assertEquals(ADD, ADD.resolve(AUTO)); + assertEquals(AUTO, AUTO.resolve(AUTO)); + + // but if something else is set on tree level AUTO(_SKIP) becomes that strategy + for (JsonNode.Index strategy : List.of(SKIP, CHECK, ADD, AUTO_SKIP)) { + assertEquals(SKIP, SKIP.resolve(strategy)); + assertEquals(strategy, AUTO_SKIP.resolve(strategy)); + assertEquals(CHECK, CHECK.resolve(strategy)); + assertEquals(ADD, ADD.resolve(strategy)); + assertEquals(strategy, AUTO.resolve(strategy)); + } + } + private static void assertGetThrowsJsonPathException(String json, String path, String expected) { JsonNode root = JsonNode.of(json); JsonPathException ex = assertThrowsExactly(JsonPathException.class, () -> root.get(path)); From 37fefaf0537415450af5b69a3a56ed59f26c3651 Mon Sep 17 00:00:00 2001 From: Jan Bernitt Date: Wed, 13 May 2026 14:59:02 +0200 Subject: [PATCH 2/3] fix: consider @Validation for JSON type of non-json Class --- .../java/org/hisp/dhis/jsontree/Validation.java | 16 ++++++++++++++++ .../org/hisp/dhis/jsontree/JsonObjectTest.java | 14 ++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/main/java/org/hisp/dhis/jsontree/Validation.java b/src/main/java/org/hisp/dhis/jsontree/Validation.java index b8dcfef..a7327b9 100644 --- a/src/main/java/org/hisp/dhis/jsontree/Validation.java +++ b/src/main/java/org/hisp/dhis/jsontree/Validation.java @@ -179,6 +179,22 @@ public static Set of(@NotNull Class type) { } static Class toJsonType(Class type) { + if (type.isAnnotationPresent(Validation.class)) { + Validation validation = type.getAnnotation(Validation.class); + NodeType[] types = validation.type(); + if (types.length == 1) { + return switch (types[0]) { + case INTEGER -> JsonInteger.class; + case BOOLEAN -> JsonBoolean.class; + case ARRAY -> JsonArray.class; + case STRING -> JsonString.class; + case OBJECT -> JsonObject.class; + case NUMBER -> JsonNumber.class; + case NULL -> JsonValue.class; + }; + } + if (types.length > 1) return JsonMixed.class; + } if (type == String.class || type.isEnum()) return JsonString.class; if (type == Character.class || type == char.class) return JsonString.class; if (type == Class.class) return JsonString.class; diff --git a/src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java b/src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java index e3c369a..f0a3934 100644 --- a/src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java +++ b/src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java @@ -7,6 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; +import java.util.Set; import org.hisp.dhis.jsontree.JsonNode.Index; import org.junit.jupiter.api.Test; @@ -150,4 +151,17 @@ void testProject() { assertTrue(obj.has("a", "b")); assertFalse(obj.has("a", "b", "c")); } + + @Validation(type = Validation.NodeType.INTEGER) + record Id(String value) {} + record Container(Id id) {} + + @Test + void testNodeType() { + List properties = JsonObject.properties(Container.class); + JsonObject.Property id = properties.get(0); + assertEquals(Set.of(Validation.NodeType.INTEGER), id.types()); + assertEquals(JsonInteger.class, id.jsonType()); + assertEquals(new Container(new Id("12")), JsonMixed.of("{\"id\": 12}").to(Container.class)); + } } From 729e9e2246738a64cf30539a094759e6c7aa7922 Mon Sep 17 00:00:00 2001 From: Jan Bernitt Date: Wed, 13 May 2026 15:03:07 +0200 Subject: [PATCH 3/3] chore: naming --- src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java b/src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java index f0a3934..292409c 100644 --- a/src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java +++ b/src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java @@ -157,7 +157,7 @@ record Id(String value) {} record Container(Id id) {} @Test - void testNodeType() { + void testProperties_NodeTypeOverride() { List properties = JsonObject.properties(Container.class); JsonObject.Property id = properties.get(0); assertEquals(Set.of(Validation.NodeType.INTEGER), id.types());