From 425aa7db4454b447b1fd521341140e4ea6e37a02 Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 16 Sep 2024 11:59:17 +0200 Subject: [PATCH] [Kotlin] Add a new additional property to configure Jackson's `failOnUnknownProperties` (#19506) * [Kotlin] Add a new additional property to configure Jackson's `failOnUnknownProperties` Default to false * [Kotlin] Unconditionally import `com.fasterxml.jackson.databind.DeserializationFeature` * [Kotlin] Refactor and add test --- docs/generators/kotlin.md | 1 + .../languages/KotlinClientCodegen.java | 10 +++++++ .../infrastructure/Serializer.kt.mustache | 3 +-- .../kotlin/KotlinClientCodegenModelTest.java | 27 +++++++++++++++++++ .../client/infrastructure/Serializer.kt | 1 + .../client/infrastructure/Serializer.kt | 1 + .../client/infrastructure/Serializer.kt | 1 + .../client/infrastructure/Serializer.kt | 1 + .../client/infrastructure/Serializer.kt | 1 + .../client/infrastructure/Serializer.kt | 1 + .../client/infrastructure/Serializer.kt | 1 + .../client/infrastructure/Serializer.kt | 2 ++ .../client/infrastructure/Serializer.kt | 2 ++ .../client/infrastructure/Serializer.kt | 2 ++ 14 files changed, 52 insertions(+), 2 deletions(-) diff --git a/docs/generators/kotlin.md b/docs/generators/kotlin.md index 060b0d2c626..05f6c4cbab0 100644 --- a/docs/generators/kotlin.md +++ b/docs/generators/kotlin.md @@ -25,6 +25,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |collectionType|Option. Collection type to use|
**array**
kotlin.Array
**list**
kotlin.collections.List
|list| |dateLibrary|Option. Date library to use|
**threetenbp-localdatetime**
Threetenbp - Backport of JSR310 (jvm only, for legacy app only)
**kotlinx-datetime**
kotlinx-datetime (preferred for multiplatform)
**string**
String
**java8-localdatetime**
Java 8 native JSR310 (jvm only, for legacy app only)
**java8**
Java 8 native JSR310 (jvm only, preferred for jdk 1.8+)
**threetenbp**
Threetenbp - Backport of JSR310 (jvm only, preferred for jdk < 1.8)
|java8| |enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |original| +|failOnUnknownProperties|Fail Jackson de-serialization on unknown properties| |false| |generateOneOfAnyOfWrappers|Generate oneOf, anyOf schemas as wrappers.| |false| |generateRoomModels|Generate Android Room database models in addition to API models (JVM Volley library only)| |false| |groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java index 6984956674a..3690e034826 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinClientCodegen.java @@ -85,6 +85,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen { public static final String DATE_LIBRARY = "dateLibrary"; public static final String REQUEST_DATE_CONVERTER = "requestDateConverter"; public static final String COLLECTION_TYPE = "collectionType"; + public static final String FAIL_ON_UNKNOWN_PROPERTIES = "failOnUnknownProperties"; public static final String MOSHI_CODE_GEN = "moshiCodeGen"; @@ -108,6 +109,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen { @Setter protected String roomModelPackage = ""; @Setter protected boolean omitGradleWrapper = false; @Setter protected boolean generateOneOfAnyOfWrappers = true; + @Getter @Setter protected boolean failOnUnknownProperties = false; protected String authFolder; @@ -259,6 +261,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen { cliOptions.add(CliOption.newBoolean(IDEA, "Add IntellJ Idea plugin and mark Kotlin main and test folders as source folders.")); cliOptions.add(CliOption.newBoolean(MOSHI_CODE_GEN, "Whether to enable codegen with the Moshi library. Refer to the [official Moshi doc](https://github.com/square/moshi#codegen) for more info.")); + cliOptions.add(CliOption.newBoolean(FAIL_ON_UNKNOWN_PROPERTIES, "Fail Jackson de-serialization on unknown properties", false)); cliOptions.add(CliOption.newBoolean(NULLABLE_RETURN_TYPE, "Nullable return type")); @@ -438,6 +441,13 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen { setGenerateOneOfAnyOfWrappers(Boolean.parseBoolean(additionalProperties.get(GENERATE_ONEOF_ANYOF_WRAPPERS).toString())); } + if (additionalProperties.containsKey(FAIL_ON_UNKNOWN_PROPERTIES)) { + setFailOnUnknownProperties(Boolean.parseBoolean(additionalProperties.get(FAIL_ON_UNKNOWN_PROPERTIES).toString())); + } else { + additionalProperties.put(FAIL_ON_UNKNOWN_PROPERTIES, false); + setFailOnUnknownProperties(false); + } + commonSupportingFiles(); switch (getLibrary()) { diff --git a/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache index 57fe58a103f..a281836a734 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-client/jvm-common/infrastructure/Serializer.kt.mustache @@ -28,9 +28,7 @@ import kotlinx.datetime.Instant import java.util.UUID {{/gson}} {{#jackson}} -{{#enumUnknownDefaultCase}} import com.fasterxml.jackson.databind.DeserializationFeature -{{/enumUnknownDefaultCase}} import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.annotation.JsonInclude @@ -111,6 +109,7 @@ import java.util.concurrent.atomic.AtomicLong .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true) {{/enumUnknownDefaultCase}} .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, {{failOnUnknownProperties}}) {{/jackson}} {{#kotlinx_serialization}} @Deprecated("Use Serializer.kotlinxSerializationAdapters instead", replaceWith = ReplaceWith("Serializer.kotlinxSerializationAdapters")) diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java index 0b4832d7942..9bdbfcb4b54 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinClientCodegenModelTest.java @@ -34,6 +34,7 @@ import org.openapitools.codegen.DefaultGenerator; import org.openapitools.codegen.TestUtils; import org.openapitools.codegen.config.CodegenConfigurator; import org.openapitools.codegen.languages.KotlinClientCodegen; +import org.openapitools.codegen.testutils.ConfigAssert; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -406,6 +407,32 @@ public class KotlinClientCodegenModelTest { TestUtils.assertFileNotExists(Paths.get(path, "gradle", "wrapper", "gradle-wrapper.jar")); } + @Test + public void testFailOnUnknownPropertiesAdditionalProperty() { + final KotlinClientCodegen codegen = new KotlinClientCodegen(); + + // Default case, nothing provided + codegen.processOpts(); + + ConfigAssert configAssert = new ConfigAssert(codegen.additionalProperties()); + // Default to false + configAssert.assertValue(KotlinClientCodegen.FAIL_ON_UNKNOWN_PROPERTIES, codegen::isFailOnUnknownProperties, Boolean.FALSE); + + // Provide true + codegen.additionalProperties().put(KotlinClientCodegen.FAIL_ON_UNKNOWN_PROPERTIES, true); + codegen.processOpts(); + + // Should be true + configAssert.assertValue(KotlinClientCodegen.FAIL_ON_UNKNOWN_PROPERTIES, codegen::isFailOnUnknownProperties, Boolean.TRUE); + + // Provide false + codegen.additionalProperties().put(KotlinClientCodegen.FAIL_ON_UNKNOWN_PROPERTIES, false); + codegen.processOpts(); + + // Should be false + configAssert.assertValue(KotlinClientCodegen.FAIL_ON_UNKNOWN_PROPERTIES, codegen::isFailOnUnknownProperties, Boolean.FALSE); + } + private static class ModelNameTest { private final String expectedName; private final String expectedClassName; diff --git a/samples/client/echo_api/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/echo_api/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index 6a09fd57f30..80783430664 100644 --- a/samples/client/echo_api/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/echo_api/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -13,4 +13,5 @@ object Serializer { .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } diff --git a/samples/client/echo_api/kotlin-jvm-spring-3-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/echo_api/kotlin-jvm-spring-3-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index 6a09fd57f30..80783430664 100644 --- a/samples/client/echo_api/kotlin-jvm-spring-3-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/echo_api/kotlin-jvm-spring-3-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -13,4 +13,5 @@ object Serializer { .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } diff --git a/samples/client/petstore/kotlin-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index 6a09fd57f30..80783430664 100644 --- a/samples/client/petstore/kotlin-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/petstore/kotlin-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -13,4 +13,5 @@ object Serializer { .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } diff --git a/samples/client/petstore/kotlin-jvm-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-jvm-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index 6a09fd57f30..80783430664 100644 --- a/samples/client/petstore/kotlin-jvm-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/petstore/kotlin-jvm-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -13,4 +13,5 @@ object Serializer { .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } diff --git a/samples/client/petstore/kotlin-jvm-spring-2-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-jvm-spring-2-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index 6a09fd57f30..80783430664 100644 --- a/samples/client/petstore/kotlin-jvm-spring-2-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/petstore/kotlin-jvm-spring-2-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -13,4 +13,5 @@ object Serializer { .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } diff --git a/samples/client/petstore/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index 6a09fd57f30..80783430664 100644 --- a/samples/client/petstore/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/petstore/kotlin-jvm-spring-3-restclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -13,4 +13,5 @@ object Serializer { .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } diff --git a/samples/client/petstore/kotlin-jvm-spring-3-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-jvm-spring-3-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index 6a09fd57f30..80783430664 100644 --- a/samples/client/petstore/kotlin-jvm-spring-3-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/petstore/kotlin-jvm-spring-3-webclient/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -13,4 +13,5 @@ object Serializer { .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } diff --git a/samples/client/petstore/kotlin-jvm-vertx-jackson-coroutines/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-jvm-vertx-jackson-coroutines/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index ece5c413e12..3fc7935a7bf 100644 --- a/samples/client/petstore/kotlin-jvm-vertx-jackson-coroutines/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/petstore/kotlin-jvm-vertx-jackson-coroutines/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -1,5 +1,6 @@ package org.openapitools.client.infrastructure +import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.annotation.JsonInclude @@ -11,4 +12,5 @@ object Serializer { .findAndRegisterModules() .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } diff --git a/samples/client/petstore/kotlin-jvm-vertx-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-jvm-vertx-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index ece5c413e12..3fc7935a7bf 100644 --- a/samples/client/petstore/kotlin-jvm-vertx-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/petstore/kotlin-jvm-vertx-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -1,5 +1,6 @@ package org.openapitools.client.infrastructure +import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.annotation.JsonInclude @@ -11,4 +12,5 @@ object Serializer { .findAndRegisterModules() .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } diff --git a/samples/client/petstore/kotlin-retrofit2-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-retrofit2-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt index ece5c413e12..3fc7935a7bf 100644 --- a/samples/client/petstore/kotlin-retrofit2-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ b/samples/client/petstore/kotlin-retrofit2-jackson/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -1,5 +1,6 @@ package org.openapitools.client.infrastructure +import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.annotation.JsonInclude @@ -11,4 +12,5 @@ object Serializer { .findAndRegisterModules() .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) }