From e5912bd31c0e0c211419ab2c62e51652f7d004cb Mon Sep 17 00:00:00 2001 From: SimY4 Date: Tue, 28 May 2024 15:45:48 +1000 Subject: [PATCH] [jackson module] Use JsonValue method type when present. --- .../module/jackson/JacksonModule.java | 1 + .../jackson/JsonValueDefinitionProvider.java | 65 +++++++++++++++++++ .../module/jackson/IntegrationTest.java | 11 ++++ .../module/jackson/JacksonModuleTest.java | 2 +- .../jackson/integration-test-result.json | 3 + 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/JsonValueDefinitionProvider.java diff --git a/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/JacksonModule.java b/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/JacksonModule.java index 1d887605..c527115a 100644 --- a/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/JacksonModule.java +++ b/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/JacksonModule.java @@ -115,6 +115,7 @@ public void applyToConfigBuilder(SchemaGeneratorConfigBuilder builder) { applySubtypeResolverToConfigBuilder(generalConfigPart, fieldConfigPart, methodConfigPart); generalConfigPart.withCustomDefinitionProvider(new JsonUnwrappedDefinitionProvider()); + generalConfigPart.withCustomDefinitionProvider(new JsonValueDefinitionProvider()); } private void applySubtypeResolverToConfigBuilder(SchemaGeneratorGeneralConfigPart generalConfigPart, diff --git a/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/JsonValueDefinitionProvider.java b/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/JsonValueDefinitionProvider.java new file mode 100644 index 00000000..1fe03359 --- /dev/null +++ b/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/JsonValueDefinitionProvider.java @@ -0,0 +1,65 @@ +/* + * Copyright 2020 VicTools. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.victools.jsonschema.module.jackson; + +import com.fasterxml.classmate.ResolvedType; +import com.fasterxml.classmate.members.ResolvedMethod; +import com.fasterxml.jackson.annotation.JsonValue; +import com.github.victools.jsonschema.generator.CustomDefinition; +import com.github.victools.jsonschema.generator.CustomDefinitionProviderV2; +import com.github.victools.jsonschema.generator.SchemaGenerationContext; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Implementation of the {@link CustomDefinitionProviderV2} interface for treating object types based on a {@link JsonValue} annotation + * being present with {@code value = true} on exactly one argument-free method. If no such annotations exist, no custom definition will be returned; + * thereby falling back on whatever is defined in a following custom definition (e.g. from one of the standard generator {@code Option}s). + */ +public class JsonValueDefinitionProvider implements CustomDefinitionProviderV2 { + + @Override + public CustomDefinition provideCustomSchemaDefinition(ResolvedType javaType, SchemaGenerationContext context) { + ResolvedMethod jsonValueAnnotatedMethod = getJsonValueAnnotatedMethod(javaType, context); + if (jsonValueAnnotatedMethod == null) { + return null; + } + return new CustomDefinition(context.createDefinition(jsonValueAnnotatedMethod.getType())); + } + + /** + * Look-up the single {@link JsonValue} annotated method with {@code value = true} and no expected arguments. + * + * @param javaType targeted type to look-up serialization method for + * @param context generation context providing access to type resolution context + * @return single method with {@link JsonValue} annotation + */ + protected ResolvedMethod getJsonValueAnnotatedMethod(ResolvedType javaType, SchemaGenerationContext context) { + ResolvedMethod[] memberMethods = context.getTypeContext().resolveWithMembers(javaType).getMemberMethods(); + Set jsonValueAnnotatedMethods = Stream.of(memberMethods) + .filter(method -> method.getArgumentCount() == 0) + .filter(method -> Optional.ofNullable(method.getAnnotations().get(JsonValue.class)).map(JsonValue::value).orElse(false)) + .collect(Collectors.toSet()); + if (jsonValueAnnotatedMethods.size() == 1) { + return jsonValueAnnotatedMethods.iterator().next(); + } + return null; + } + +} diff --git a/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/IntegrationTest.java b/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/IntegrationTest.java index 061a5312..12ba9428 100644 --- a/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/IntegrationTest.java +++ b/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/IntegrationTest.java @@ -95,6 +95,8 @@ static class TestClass { public TestEnumWithJsonPropertyAnnotations enumValueWithJsonPropertyAnnotations; + public TestTypeWithJsonValue typeWithJsonValue; + public BaseType interfaceWithDeclaredSubtypes; @JsonUnwrapped @@ -131,6 +133,15 @@ enum TestEnumWithJsonPropertyAnnotations { @JsonProperty Y } + static class TestTypeWithJsonValue { + String value; + + @JsonValue + String getJsonValue() { + return value; + } + } + @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") static class TestTypeWithObjectId { IdType id; diff --git a/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/JacksonModuleTest.java b/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/JacksonModuleTest.java index 8b147f2d..db2f2a94 100644 --- a/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/JacksonModuleTest.java +++ b/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/JacksonModuleTest.java @@ -185,7 +185,7 @@ private void verifyCommonConfigurations(boolean considerNamingStrategy, int addi Mockito.verify(this.methodConfigPart).withWriteOnlyCheck(Mockito.any()); Mockito.verify(this.typesInGeneralConfigPart).withDescriptionResolver(Mockito.any()); - Mockito.verify(this.typesInGeneralConfigPart, Mockito.times(1 + additionalCustomTypeDefinitions)) + Mockito.verify(this.typesInGeneralConfigPart, Mockito.times(2 + additionalCustomTypeDefinitions)) .withCustomDefinitionProvider(Mockito.any()); } diff --git a/jsonschema-module-jackson/src/test/resources/com/github/victools/jsonschema/module/jackson/integration-test-result.json b/jsonschema-module-jackson/src/test/resources/com/github/victools/jsonschema/module/jackson/integration-test-result.json index 8e48e311..5cceea21 100644 --- a/jsonschema-module-jackson/src/test/resources/com/github/victools/jsonschema/module/jackson/integration-test-result.json +++ b/jsonschema-module-jackson/src/test/resources/com/github/victools/jsonschema/module/jackson/integration-test-result.json @@ -54,6 +54,9 @@ "type": "string", "enum": ["entry1", "entry2", "entry3"] }, + "typeWithJsonValue":{ + "type":"string" + }, "fieldWithDescription": { "type": "string", "description": "field description"