From 1abb151c7b34c670be3e396549d926dbe7c49fcd Mon Sep 17 00:00:00 2001 From: moranlefler Date: Thu, 8 Jun 2023 09:43:19 +0300 Subject: [PATCH 1/3] KotlinJacksonModule supports JsonProperty annotations on Kotlin data classes --- jsonschema-module-jackson/pom.xml | 27 +++++++- .../module/jackson/JacksonModule.java | 13 +++- .../module/jackson/KotlinJacksonModule.java | 63 +++++++++++++++++++ .../module/jackson/KotlinJacksonModuleTest.kt | 29 +++++++++ 4 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModule.java create mode 100644 jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModuleTest.kt diff --git a/jsonschema-module-jackson/pom.xml b/jsonschema-module-jackson/pom.xml index 59216688..d6a63858 100644 --- a/jsonschema-module-jackson/pom.xml +++ b/jsonschema-module-jackson/pom.xml @@ -16,6 +16,7 @@ com.github.victools.jsonschema.module.jackson + 1.9.0-Beta @@ -34,6 +35,17 @@ jackson-annotations provided + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + @@ -54,7 +66,20 @@ org.moditect moditect-maven-plugin + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + true + + 1.8 + + + + org.apache.maven.plugins + maven-compiler-plugin + - \ No newline at end of file + 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 a698d6dc..af011a38 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 @@ -196,13 +196,24 @@ protected String getPropertyNameOverrideBasedOnJsonPropertyAnnotation(MemberScop if (annotation != null) { String nameOverride = annotation.value(); // check for invalid overrides - if (nameOverride != null && !nameOverride.isEmpty() && !nameOverride.equals(member.getDeclaredName())) { + if (isValidNameOverride(member, nameOverride)) { return nameOverride; } } return null; } + /** + * Checks whether the potential name override is valid for the specified member + * + * @param member field/method to override + * @param nameOverride the name that will override the original name of the member + * @return true if the specified override is valid for the member, false otherwise + */ + protected static boolean isValidNameOverride(MemberScope member, String nameOverride) { + return nameOverride != null && !nameOverride.isEmpty() && !nameOverride.equals(member.getDeclaredName()); + } + /** * Alter the declaring name of the given field as per the declaring type's {@link JsonNaming} annotation. * diff --git a/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModule.java b/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModule.java new file mode 100644 index 00000000..971fc69e --- /dev/null +++ b/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModule.java @@ -0,0 +1,63 @@ +package com.github.victools.jsonschema.module.jackson; + +import com.fasterxml.classmate.members.RawField; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.victools.jsonschema.generator.MemberScope; +import kotlin.Metadata; + +import java.lang.reflect.Parameter; +import java.util.List; +import java.util.OptionalInt; + +public class KotlinJacksonModule extends JacksonModule { + /** + * Look up an alternative name for a member in the constructor parameter list. + * When the Kotlin compiler compiles a Kotlin data class, it creates a constructor with a parameter + * for each field in the data class. The parameters have generic name such as "arg0", "arg1", etc. + * In order to find the appropriate constructor parameter, the method first determines the index of + * specified member within its type member list and uses the parameter with the same index. + * In order to avoid erroneous overrides, this method verifies that the specified member is indeed of a + * Kotlin class. + * + * @param member field/method to look-up alternative property name for + * @return alternative property name or the base class implementation return value + */ + @Override + protected String getPropertyNameOverrideBasedOnJsonPropertyAnnotation(MemberScope member) { + if (isKotlinType(member)) { + OptionalInt memberIndex = getMemberIndex(member); + if (memberIndex.isPresent()) { + Parameter[] parameters = getConstructorParameters(member); + Parameter parameter = parameters[memberIndex.getAsInt()]; + JsonProperty jsonPropertyAnnotation = parameter.getAnnotation(JsonProperty.class); + if (jsonPropertyAnnotation != null) { + String nameOverride = jsonPropertyAnnotation.value(); + if (isValidNameOverride(member, nameOverride)) { + return nameOverride; + } + } + } + } + return super.getPropertyNameOverrideBasedOnJsonPropertyAnnotation(member); + + } + + private OptionalInt getMemberIndex(MemberScope member) { + List memberFields = member.getDeclaringType().getMemberFields(); + for (int i = 0; i < memberFields.size(); i++) { + if (memberFields.get(i).getName().equals(member.getName())) { + return OptionalInt.of(i); + } + } + return OptionalInt.empty(); + } + + private static Parameter[] getConstructorParameters(MemberScope member) { + return member.getDeclaringType().getConstructors().get(0).getRawMember().getParameters(); + } + + private static boolean isKotlinType(MemberScope member) { + return member.getDeclaringType().getErasedType().isAnnotationPresent(Metadata.class); + } + +} diff --git a/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModuleTest.kt b/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModuleTest.kt new file mode 100644 index 00000000..db412eaf --- /dev/null +++ b/jsonschema-module-jackson/src/test/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModuleTest.kt @@ -0,0 +1,29 @@ +package com.github.victools.jsonschema.module.jackson + +import com.fasterxml.jackson.annotation.JsonProperty +import com.github.victools.jsonschema.generator.* +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import java.util.* + +class KotlinJacksonModuleTest { + data class TestJsonProperty( + @JsonProperty("my_text") val text: String, + @JsonProperty("my_number") val number: Int) + + @Test + fun `naming override in kotlin data class with JsonProperty`() { + val config = SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON) + .with(KotlinJacksonModule()) + .build() + + val generator = SchemaGenerator(config) + val result = generator.generateSchema(TestJsonProperty::class.java) + val propertiesNode = result[config.getKeyword(SchemaKeyword.TAG_PROPERTIES)] + val propertyNames: MutableSet = TreeSet() + propertiesNode.fieldNames().forEachRemaining { e: String -> propertyNames.add(e) } + Assertions.assertTrue(propertyNames.contains("my_text")) + Assertions.assertTrue(propertyNames.contains("my_number")) + } + +} From 03b030a3434697ca3db203a4060ff5b2fa804368 Mon Sep 17 00:00:00 2001 From: moranlefler Date: Thu, 8 Jun 2023 14:26:46 +0300 Subject: [PATCH 2/3] checkstyle fixes --- .../victools/jsonschema/module/jackson/JacksonModule.java | 2 +- .../jsonschema/module/jackson/KotlinJacksonModule.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) 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 af011a38..c518db83 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 @@ -204,7 +204,7 @@ protected String getPropertyNameOverrideBasedOnJsonPropertyAnnotation(MemberScop } /** - * Checks whether the potential name override is valid for the specified member + * Checks whether the potential name override is valid for the specified member. * * @param member field/method to override * @param nameOverride the name that will override the original name of the member diff --git a/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModule.java b/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModule.java index 971fc69e..f16bf1bd 100644 --- a/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModule.java +++ b/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/KotlinJacksonModule.java @@ -3,11 +3,10 @@ import com.fasterxml.classmate.members.RawField; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.victools.jsonschema.generator.MemberScope; -import kotlin.Metadata; - import java.lang.reflect.Parameter; import java.util.List; import java.util.OptionalInt; +import kotlin.Metadata; public class KotlinJacksonModule extends JacksonModule { /** From 2ee1137e6087fa1e10febd79ade429c8dff91dbb Mon Sep 17 00:00:00 2001 From: moranlefler Date: Fri, 9 Jun 2023 15:21:51 +0300 Subject: [PATCH 3/3] removed redundant maven-compiler-plugin reference --- jsonschema-module-jackson/pom.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/jsonschema-module-jackson/pom.xml b/jsonschema-module-jackson/pom.xml index d6a63858..63539cf9 100644 --- a/jsonschema-module-jackson/pom.xml +++ b/jsonschema-module-jackson/pom.xml @@ -50,9 +50,6 @@ - - maven-compiler-plugin - maven-checkstyle-plugin