diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/FieldScope.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/FieldScope.java index 673415d0..0d89bbc4 100644 --- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/FieldScope.java +++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/FieldScope.java @@ -25,6 +25,7 @@ import java.lang.reflect.AnnotatedParameterizedType; import java.lang.reflect.AnnotatedType; import java.lang.reflect.Field; +import java.util.function.Supplier; import java.util.stream.Stream; /** @@ -112,6 +113,14 @@ public MethodScope findGetter() { * @return public getter from within the field's declaring class */ private MethodScope doFindGetter() { + if (this.getMember().getType().isInstanceOf(Supplier.class)) { + ResolvedMethod[] methods = getContext().resolveWithMembers(this.getMember().getType()).getMemberMethods(); + return Stream.of(methods) + .filter(method -> method.getName().equals("get")) + .findFirst() + .map(method -> this.getContext().createMethodScope(method, this.getDeclaringTypeMembers())) + .orElse(null); + } String capitalisedFieldName = this.getDeclaredName().substring(0, 1).toUpperCase() + this.getDeclaredName().substring(1); String getterName1 = "get" + capitalisedFieldName; String getterName2 = "is" + capitalisedFieldName; diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/MemberScope.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/MemberScope.java index 72456e0d..52f9501d 100644 --- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/MemberScope.java +++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/MemberScope.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 VicTools. + * Copyright 2020 VicTools & Sascha Kohlmann * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Member; import java.util.Optional; +import java.util.function.Supplier; /** * Representation of a single introspected field or method. @@ -321,14 +322,21 @@ public A getContainerItemAnnotationConsideringFieldAndGet if (this.isFakeContainerItemScope()) { return this.getContainerItemAnnotationConsideringFieldAndGetter(annotationClass); } - if (this.getOverriddenType() != null - && this.getDeclaredType().getErasedType() == Optional.class - && this.getOverriddenType().getErasedType() == this.getDeclaredType().getTypeParameters().get(0).getErasedType()) { + if (this.getOverriddenType() != null && (isSupplier() || isOptional())) { return this.getContainerItemAnnotationConsideringFieldAndGetter(annotationClass); } return null; } + private boolean isSupplier() { + return this.member.getType().isInstanceOf(Supplier.class); + } + + private boolean isOptional() { + return this.getDeclaredType().getErasedType() == Optional.class + && this.getOverriddenType().getErasedType() == this.getDeclaredType().getTypeParameters().get(0).getErasedType(); + } + /** * Returns the name to be used to reference this member in its parent's "properties". * diff --git a/jsonschema-module-jakarta-validation/src/test/java/com/github/victools/jsonschema/module/jakarta/validation/IntegrationTest.java b/jsonschema-module-jakarta-validation/src/test/java/com/github/victools/jsonschema/module/jakarta/validation/IntegrationTest.java index 2d254a13..65ce617c 100644 --- a/jsonschema-module-jakarta-validation/src/test/java/com/github/victools/jsonschema/module/jakarta/validation/IntegrationTest.java +++ b/jsonschema-module-jakarta-validation/src/test/java/com/github/victools/jsonschema/module/jakarta/validation/IntegrationTest.java @@ -33,6 +33,7 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Null; import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.PositiveOrZero; import jakarta.validation.constraints.Size; import java.io.IOException; import java.io.InputStream; @@ -40,6 +41,7 @@ import java.util.List; import java.util.Optional; import java.util.Scanner; +import java.util.function.Supplier; import org.junit.jupiter.api.Test; import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; @@ -63,6 +65,7 @@ public void testIntegration() throws Exception { JakartaValidationOption.INCLUDE_PATTERN_EXPRESSIONS); SchemaGeneratorConfig config = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2019_09, OptionPreset.PLAIN_JSON) .with(Option.NULLABLE_ARRAY_ITEMS_ALLOWED) + .with(Option.FLATTENED_SUPPLIERS) .with(module) .build(); SchemaGenerator generator = new SchemaGenerator(config); @@ -77,7 +80,7 @@ private static String loadResource(String resourcePath) throws IOException { StringBuilder stringBuilder = new StringBuilder(); try (InputStream inputStream = IntegrationTest.class .getResourceAsStream(resourcePath); - Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name())) { + Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name())) { while (scanner.hasNext()) { stringBuilder.append(scanner.nextLine()).append('\n'); } @@ -128,5 +131,27 @@ static class TestClass { @DecimalMin(value = "0", inclusive = false) @DecimalMax(value = "1", inclusive = false) public double exclusiveRangeDouble; + + @PositiveOrZero + public IntegrationTest.TestSupplier supplierPositiveOrZero; + + public TestSupplierWithAnnotation supplierWithAnnotationPositiveOrZero; + } + + static class TestSupplier implements Supplier { + + @Override + public Integer get() { + return 0; + } + } + + static class TestSupplierWithAnnotation implements Supplier { + + @Override + @PositiveOrZero + public Integer get() { + return 0; + } } } diff --git a/jsonschema-module-jakarta-validation/src/test/resources/com/github/victools/jsonschema/module/jakarta/validation/integration-test-result.json b/jsonschema-module-jakarta-validation/src/test/resources/com/github/victools/jsonschema/module/jakarta/validation/integration-test-result.json index 17ba23d4..64aadf7f 100644 --- a/jsonschema-module-jakarta-validation/src/test/resources/com/github/victools/jsonschema/module/jakarta/validation/integration-test-result.json +++ b/jsonschema-module-jakarta-validation/src/test/resources/com/github/victools/jsonschema/module/jakarta/validation/integration-test-result.json @@ -82,6 +82,14 @@ "type": "string", "minLength": 5, "maxLength": 12 + }, + "supplierPositiveOrZero": { + "type": "integer", + "minimum": 0 + }, + "supplierWithAnnotationPositiveOrZero": { + "type": "integer", + "minimum": 0 } }, "required": ["notBlankText", "notEmptyList", "notEmptyPatternText", "notNullEmail", "notNullList"] diff --git a/jsonschema-module-javax-validation/src/test/java/com/github/victools/jsonschema/module/javax/validation/IntegrationTest.java b/jsonschema-module-javax-validation/src/test/java/com/github/victools/jsonschema/module/javax/validation/IntegrationTest.java index 8f08c4de..2746e9cc 100644 --- a/jsonschema-module-javax-validation/src/test/java/com/github/victools/jsonschema/module/javax/validation/IntegrationTest.java +++ b/jsonschema-module-javax-validation/src/test/java/com/github/victools/jsonschema/module/javax/validation/IntegrationTest.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Optional; import java.util.Scanner; +import java.util.function.Supplier; import javax.validation.constraints.DecimalMax; import javax.validation.constraints.DecimalMin; import javax.validation.constraints.Email; @@ -39,6 +40,7 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; import javax.validation.constraints.Pattern; +import javax.validation.constraints.PositiveOrZero; import javax.validation.constraints.Size; import org.junit.jupiter.api.Test; import org.skyscreamer.jsonassert.JSONAssert; @@ -128,5 +130,27 @@ static class TestClass { @DecimalMin(value = "0", inclusive = false) @DecimalMax(value = "1", inclusive = false) public double exclusiveRangeDouble; + + @PositiveOrZero + public IntegrationTest.TestSupplier supplierPositiveOrZero; + + public TestSupplierWithAnnotation supplierWithAnnotationPositiveOrZero; + } + + static class TestSupplier implements Supplier { + + @Override + public Integer get() { + return 0; + } + } + + static class TestSupplierWithAnnotation implements Supplier { + + @Override + @PositiveOrZero + public Integer get() { + return 0; + } } } diff --git a/jsonschema-module-javax-validation/src/test/resources/com/github/victools/jsonschema/module/javax/validation/integration-test-result.json b/jsonschema-module-javax-validation/src/test/resources/com/github/victools/jsonschema/module/javax/validation/integration-test-result.json index 17ba23d4..64aadf7f 100644 --- a/jsonschema-module-javax-validation/src/test/resources/com/github/victools/jsonschema/module/javax/validation/integration-test-result.json +++ b/jsonschema-module-javax-validation/src/test/resources/com/github/victools/jsonschema/module/javax/validation/integration-test-result.json @@ -82,6 +82,14 @@ "type": "string", "minLength": 5, "maxLength": 12 + }, + "supplierPositiveOrZero": { + "type": "integer", + "minimum": 0 + }, + "supplierWithAnnotationPositiveOrZero": { + "type": "integer", + "minimum": 0 } }, "required": ["notBlankText", "notEmptyList", "notEmptyPatternText", "notNullEmail", "notNullList"]