From 145a44ecfefb8a177378d580165d913802120ee2 Mon Sep 17 00:00:00 2001 From: Zheng Feng Date: Wed, 30 Oct 2024 19:34:14 +0800 Subject: [PATCH 1/2] Fix #6716 to introduce ignore-unknown-properties property (#6719) --- .../ROOT/pages/reference/extensions/rest-openapi.adoc | 6 ++++++ .../deployment/CamelQuarkusSwaggerCodegenProvider.java | 5 +++++ .../component/rest/openapi/deployment/QuarkusCodegen.java | 4 ++++ .../handlebars/Quarkus/generatedAnnotation.mustache | 1 + .../rest/openapi/runtime/RestOpenApiBuildTimeConfig.java | 8 ++++++++ .../src/main/resources/application.properties | 1 + 6 files changed, 25 insertions(+) diff --git a/docs/modules/ROOT/pages/reference/extensions/rest-openapi.adoc b/docs/modules/ROOT/pages/reference/extensions/rest-openapi.adoc index 957f609ad807..05e8a63cf3b6 100644 --- a/docs/modules/ROOT/pages/reference/extensions/rest-openapi.adoc +++ b/docs/modules/ROOT/pages/reference/extensions/rest-openapi.adoc @@ -165,6 +165,12 @@ If `true`, use bean validation annotations in the generated model classes. If `true`, use NON_NULL Jackson annotation in the generated model classes. | `boolean` | `false` + +|icon:lock[title=Fixed at build time] [[quarkus.camel.openapi.codegen.ignore-unknown-properties]]`link:#quarkus.camel.openapi.codegen.ignore-unknown-properties[quarkus.camel.openapi.codegen.ignore-unknown-properties]` + +If `true`, use JsonIgnoreProperties(ignoreUnknown = true) annotation in the generated model classes. +| `boolean` +| `false` |=== [.configuration-legend] diff --git a/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/CamelQuarkusSwaggerCodegenProvider.java b/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/CamelQuarkusSwaggerCodegenProvider.java index 48df92c74038..23f86e0e4cf2 100644 --- a/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/CamelQuarkusSwaggerCodegenProvider.java +++ b/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/CamelQuarkusSwaggerCodegenProvider.java @@ -82,6 +82,8 @@ public boolean trigger(CodeGenContext context) throws CodeGenException { String models = config.getOptionalValue("quarkus.camel.openapi.codegen.models", String.class).orElse(""); boolean useBeanValidation = config.getValue("quarkus.camel.openapi.codegen.use-bean-validation", Boolean.class); boolean notNullJackson = config.getValue("quarkus.camel.openapi.codegen.not-null-jackson", Boolean.class); + boolean ignoreUnknownProperties = config.getValue("quarkus.camel.openapi.codegen.ignore-unknown-properties", + Boolean.class); for (String specFile : specFiles) { CodegenConfigurator configurator = new CodegenConfigurator(); configurator.setLang("quarkus"); @@ -100,6 +102,9 @@ public boolean trigger(CodeGenContext context) throws CodeGenException { if (notNullJackson) { configurator.getAdditionalProperties().put(NOT_NULL_JACKSON_ANNOTATION, "true"); } + if (ignoreUnknownProperties) { + configurator.getAdditionalProperties().put("ignoreUnknownProperties", "true"); + } final ClientOptInput input = configurator.toClientOptInput(); new DefaultGenerator().opts(input).generate(); diff --git a/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/QuarkusCodegen.java b/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/QuarkusCodegen.java index 0d7fae0facb8..42618f4517d1 100644 --- a/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/QuarkusCodegen.java +++ b/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/QuarkusCodegen.java @@ -38,6 +38,7 @@ public class QuarkusCodegen extends AbstractJavaCodegen implements BeanValidatio public QuarkusCodegen() { super(); importMapping.put("QuarkusRegisterForReflection", "io.quarkus.runtime.annotations.RegisterForReflection"); + importMapping.put("JsonIgnoreProperties", "com.fasterxml.jackson.annotation.JsonIgnoreProperties"); supportedLibraries.put("quarkus3", "Quarkus 3 framework"); } @@ -100,6 +101,9 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert } } model.imports.add("QuarkusRegisterForReflection"); + if (additionalProperties.containsKey("ignoreUnknownProperties")) { + model.imports.add("JsonIgnoreProperties"); + } } @Override diff --git a/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/generatedAnnotation.mustache b/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/generatedAnnotation.mustache index bd62dcc6646a..6aa9a052e9e6 100644 --- a/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/generatedAnnotation.mustache +++ b/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/generatedAnnotation.mustache @@ -16,3 +16,4 @@ }} {{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} @RegisterForReflection{{#serializableModel}}(serialization = true){{/serializableModel}} +{{#ignoreUnknownProperties}}@JsonIgnoreProperties(ignoreUnknown = true){{/ignoreUnknownProperties}} diff --git a/extensions/rest-openapi/runtime/src/main/java/org/apache/camel/quarkus/rest/openapi/runtime/RestOpenApiBuildTimeConfig.java b/extensions/rest-openapi/runtime/src/main/java/org/apache/camel/quarkus/rest/openapi/runtime/RestOpenApiBuildTimeConfig.java index 0e0dbfb3404c..1d087cf701d7 100644 --- a/extensions/rest-openapi/runtime/src/main/java/org/apache/camel/quarkus/rest/openapi/runtime/RestOpenApiBuildTimeConfig.java +++ b/extensions/rest-openapi/runtime/src/main/java/org/apache/camel/quarkus/rest/openapi/runtime/RestOpenApiBuildTimeConfig.java @@ -63,6 +63,14 @@ public static class CodeGenConfig { */ @ConfigItem(defaultValue = "false") public boolean notNullJackson; + + /** + * If `true`, use JsonIgnoreProperties(ignoreUnknown = true) annotation in the generated model classes. + * + * @asciidoclet + */ + @ConfigItem(defaultValue = "false") + public boolean ignoreUnknownProperties; } } diff --git a/integration-tests/rest-openapi/src/main/resources/application.properties b/integration-tests/rest-openapi/src/main/resources/application.properties index 59425bb75b09..a16f53a6ab17 100644 --- a/integration-tests/rest-openapi/src/main/resources/application.properties +++ b/integration-tests/rest-openapi/src/main/resources/application.properties @@ -17,5 +17,6 @@ quarkus.native.resources.includes=openapi.json,petstore.json,example.yaml quarkus.camel.openapi.codegen.model-package=org.apache.camel.quarkus.component.rest.openapi.it.model quarkus.camel.openapi.codegen.not-null-jackson=true +quarkus.camel.openapi.codegen.ignore-unknown-properties=true camel.rest.bindingMode=json camel.rest.bindingPackageScan=${quarkus.camel.openapi.codegen.model-package} From 1ca70f22637d4ba1876ffb301adcb48e543e1858 Mon Sep 17 00:00:00 2001 From: Zheng Feng Date: Thu, 31 Oct 2024 06:50:32 +0800 Subject: [PATCH 2/2] Introduce additionProperties in rest-openapi codegen and fix some known issues with mustache template files (#6726) --- .../reference/extensions/rest-openapi.adoc | 6 ++++++ .../CamelQuarkusSwaggerCodegenProvider.java | 21 ++++++++++++++++--- .../Quarkus/generatedAnnotation.mustache | 2 -- .../handlebars/Quarkus/modelEnum.mustache | 2 +- .../Quarkus/modelInnerEnum.mustache | 4 ++-- .../handlebars/Quarkus/pojo.mustache | 4 ++++ .../runtime/RestOpenApiBuildTimeConfig.java | 9 ++++++++ .../src/main/resources/application.properties | 1 + 8 files changed, 41 insertions(+), 8 deletions(-) diff --git a/docs/modules/ROOT/pages/reference/extensions/rest-openapi.adoc b/docs/modules/ROOT/pages/reference/extensions/rest-openapi.adoc index 05e8a63cf3b6..fee26616da02 100644 --- a/docs/modules/ROOT/pages/reference/extensions/rest-openapi.adoc +++ b/docs/modules/ROOT/pages/reference/extensions/rest-openapi.adoc @@ -171,6 +171,12 @@ If `true`, use NON_NULL Jackson annotation in the generated model classes. If `true`, use JsonIgnoreProperties(ignoreUnknown = true) annotation in the generated model classes. | `boolean` | `false` + +|icon:lock[title=Fixed at build time] [[quarkus.camel.openapi.codegen.additional-properties.-additional-properties]]`link:#quarkus.camel.openapi.codegen.additional-properties.-additional-properties[quarkus.camel.openapi.codegen.additional-properties."additional-properties"]` + +Additional properties to be used in the mustache templates. +| `Map` +| |=== [.configuration-legend] diff --git a/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/CamelQuarkusSwaggerCodegenProvider.java b/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/CamelQuarkusSwaggerCodegenProvider.java index 23f86e0e4cf2..546af5455ffa 100644 --- a/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/CamelQuarkusSwaggerCodegenProvider.java +++ b/extensions/rest-openapi/deployment/src/main/java/org/apache/camel/quarkus/component/rest/openapi/deployment/CamelQuarkusSwaggerCodegenProvider.java @@ -84,6 +84,7 @@ public boolean trigger(CodeGenContext context) throws CodeGenException { boolean notNullJackson = config.getValue("quarkus.camel.openapi.codegen.not-null-jackson", Boolean.class); boolean ignoreUnknownProperties = config.getValue("quarkus.camel.openapi.codegen.ignore-unknown-properties", Boolean.class); + for (String specFile : specFiles) { CodegenConfigurator configurator = new CodegenConfigurator(); configurator.setLang("quarkus"); @@ -97,14 +98,28 @@ public boolean trigger(CodeGenContext context) throws CodeGenException { configurator.getCodegenArguments() .add(new CodegenArgument().option(CodegenConstants.MODEL_DOCS_OPTION).type("boolean").value("false")); if (useBeanValidation) { - configurator.getAdditionalProperties().put(USE_BEANVALIDATION, "true"); + configurator.getAdditionalProperties().put(USE_BEANVALIDATION, true); } if (notNullJackson) { - configurator.getAdditionalProperties().put(NOT_NULL_JACKSON_ANNOTATION, "true"); + configurator.getAdditionalProperties().put(NOT_NULL_JACKSON_ANNOTATION, true); } if (ignoreUnknownProperties) { - configurator.getAdditionalProperties().put("ignoreUnknownProperties", "true"); + configurator.getAdditionalProperties().put("ignoreUnknownProperties", true); } + config.getPropertyNames().forEach(name -> { + if (name.startsWith("quarkus.camel.openapi.codegen.additional-properties")) { + String key = name.substring("quarkus.camel.openapi.codegen.additional-properties.".length()); + String value = config.getValue(name, String.class); + if (configurator.getAdditionalProperties().containsKey(key)) { + LOG.warn("Overriding existing property: " + key + " with value: " + value); + } + if (value.equals("true") || value.equals("false")) { + configurator.getAdditionalProperties().put(key, Boolean.parseBoolean(value)); + } else { + configurator.getAdditionalProperties().put(key, value); + } + } + }); final ClientOptInput input = configurator.toClientOptInput(); new DefaultGenerator().opts(input).generate(); diff --git a/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/generatedAnnotation.mustache b/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/generatedAnnotation.mustache index 6aa9a052e9e6..071df2fc88f0 100644 --- a/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/generatedAnnotation.mustache +++ b/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/generatedAnnotation.mustache @@ -15,5 +15,3 @@ limitations under the License. }} {{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} -@RegisterForReflection{{#serializableModel}}(serialization = true){{/serializableModel}} -{{#ignoreUnknownProperties}}@JsonIgnoreProperties(ignoreUnknown = true){{/ignoreUnknownProperties}} diff --git a/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/modelEnum.mustache b/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/modelEnum.mustache index a86cf7ff4c63..9f975db070de 100644 --- a/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/modelEnum.mustache +++ b/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/modelEnum.mustache @@ -71,7 +71,7 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum return b; } } - {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + input + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } {{#gson}} diff --git a/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/modelInnerEnum.mustache b/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/modelInnerEnum.mustache index 9b13af047ab9..469024247402 100644 --- a/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/modelInnerEnum.mustache +++ b/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/modelInnerEnum.mustache @@ -55,7 +55,7 @@ return b; } } - {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + input + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } {{#gson}} public static class Adapter extends TypeAdapter<{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}> { @@ -70,4 +70,4 @@ return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}.fromValue(({{{datatype}}})(value)); } }{{/gson}} - } \ No newline at end of file + } diff --git a/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/pojo.mustache b/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/pojo.mustache index fc8b7d72f2fc..f03c1e39806f 100644 --- a/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/pojo.mustache +++ b/extensions/rest-openapi/deployment/src/main/resources/handlebars/Quarkus/pojo.mustache @@ -22,6 +22,10 @@ {{#notNullJacksonAnnotation}} @JsonInclude(JsonInclude.Include.NON_NULL) {{/notNullJacksonAnnotation}} +@RegisterForReflection{{#serializableModel}}(serialization = true){{/serializableModel}} +{{#ignoreUnknownProperties}} +@JsonIgnoreProperties(ignoreUnknown = true) +{{/ignoreUnknownProperties}} public class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{{#parcelableModel}}implements Parcelable {{#serializableModel}}, Serializable {{/serializableModel}}{{#interfaceModels}}{{#@first}}, {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/parcelableModel}}{{^parcelableModel}}{{#serializableModel}}implements Serializable{{#interfaceModels}}{{#@first}}, {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{/parcelableModel}}{ {{#serializableModel}} diff --git a/extensions/rest-openapi/runtime/src/main/java/org/apache/camel/quarkus/rest/openapi/runtime/RestOpenApiBuildTimeConfig.java b/extensions/rest-openapi/runtime/src/main/java/org/apache/camel/quarkus/rest/openapi/runtime/RestOpenApiBuildTimeConfig.java index 1d087cf701d7..fcebc9e0a5d5 100644 --- a/extensions/rest-openapi/runtime/src/main/java/org/apache/camel/quarkus/rest/openapi/runtime/RestOpenApiBuildTimeConfig.java +++ b/extensions/rest-openapi/runtime/src/main/java/org/apache/camel/quarkus/rest/openapi/runtime/RestOpenApiBuildTimeConfig.java @@ -16,6 +16,7 @@ */ package org.apache.camel.quarkus.rest.openapi.runtime; +import java.util.Map; import java.util.Optional; import io.quarkus.runtime.annotations.ConfigGroup; @@ -71,6 +72,14 @@ public static class CodeGenConfig { */ @ConfigItem(defaultValue = "false") public boolean ignoreUnknownProperties; + + /** + * Additional properties to be used in the mustache templates. + * + * @asciidoclet + */ + @ConfigItem + public Map additionalProperties; } } diff --git a/integration-tests/rest-openapi/src/main/resources/application.properties b/integration-tests/rest-openapi/src/main/resources/application.properties index a16f53a6ab17..01f7a2133a3b 100644 --- a/integration-tests/rest-openapi/src/main/resources/application.properties +++ b/integration-tests/rest-openapi/src/main/resources/application.properties @@ -18,5 +18,6 @@ quarkus.native.resources.includes=openapi.json,petstore.json,example.yaml quarkus.camel.openapi.codegen.model-package=org.apache.camel.quarkus.component.rest.openapi.it.model quarkus.camel.openapi.codegen.not-null-jackson=true quarkus.camel.openapi.codegen.ignore-unknown-properties=true +quarkus.camel.openapi.codegen.additional-properties.errorOnUnknownEnum=true camel.rest.bindingMode=json camel.rest.bindingPackageScan=${quarkus.camel.openapi.codegen.model-package}