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..a7327b9 100644 --- a/src/main/java/org/hisp/dhis/jsontree/Validation.java +++ b/src/main/java/org/hisp/dhis/jsontree/Validation.java @@ -168,13 +168,33 @@ 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) { + 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; @@ -194,7 +214,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)); diff --git a/src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java b/src/test/java/org/hisp/dhis/jsontree/JsonObjectTest.java index e3c369a..292409c 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 testProperties_NodeTypeOverride() { + 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)); + } }