Skip to content

Commit 81115a0

Browse files
authored
[JAVA] use JsonTypeInfo.Id.DEDUCTION for oneOf interface (#23642)
* Use deduction for interface on java generators * regenerate Doc for java-microprofile.md * merge #23677 [KOTLIN-SPRING] Feature - add support for 'useDeductionForOneOfInterfaces'
1 parent ceca9ff commit 81115a0

11 files changed

Lines changed: 47 additions & 9 deletions

File tree

docs/generators/java-camel.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
109109
|title|server title name or client service name| |OpenAPI Spring|
110110
|unhandledException|Declare operation methods to throw a generic exception and allow unhandled exceptions (useful for Spring `@ControllerAdvice` directives).| |false|
111111
|useBeanValidation|Use BeanValidation API annotations| |true|
112-
|useDeductionForOneOfInterfaces|whether to use deduction for generated oneOf interfaces| |false|
112+
|useDeductionForOneOfInterfaces|Annotate discriminator-free oneOf interfaces with Jackson's @JsonTypeInfo(use = Id.DEDUCTION) and @JsonSubTypes so the concrete subtype is resolved from the JSON field set rather than a type-tag property. Has no effect when a discriminator is present (name-based resolution is used instead). Requires subtypes to have structurally distinct sets of properties.| |false|
113113
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
114114
|useFeignClientContextId|Whether to generate Feign client with contextId parameter.| |true|
115115
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|

docs/generators/java-microprofile.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
9595
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
9696
|useAbstractionForFiles|Use alternative types instead of java.io.File to allow passing bytes without a file on disk. Available on resttemplate, webclient, restclient, libraries| |false|
9797
|useBeanValidation|Use BeanValidation API annotations| |false|
98+
|useDeductionForOneOfInterfaces|Annotate discriminator-free oneOf interfaces with Jackson's @JsonTypeInfo(use = Id.DEDUCTION) and @JsonSubTypes so the concrete subtype is resolved from the JSON field set rather than a type-tag property. Has no effect when a discriminator is present (name-based resolution is used instead). Requires subtypes to have structurally distinct sets of properties.| |false|
9899
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
99100
|useGzipFeature|Send gzip-encoded requests| |false|
100101
|useJackson3|Use Jackson 3 instead of Jackson 2. Supported for 'native' and 'apache-httpclient' libraries (requires Java 17+) and for Spring 'resttemplate', 'webclient', and 'restclient' libraries (require useSpringBoot4=true).| |false|

docs/generators/java.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
9595
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
9696
|useAbstractionForFiles|Use alternative types instead of java.io.File to allow passing bytes without a file on disk. Available on resttemplate, webclient, restclient, libraries| |false|
9797
|useBeanValidation|Use BeanValidation API annotations| |false|
98+
|useDeductionForOneOfInterfaces|Annotate discriminator-free oneOf interfaces with Jackson's @JsonTypeInfo(use = Id.DEDUCTION) and @JsonSubTypes so the concrete subtype is resolved from the JSON field set rather than a type-tag property. Has no effect when a discriminator is present (name-based resolution is used instead). Requires subtypes to have structurally distinct sets of properties.| |false|
9899
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
99100
|useGzipFeature|Send gzip-encoded requests| |false|
100101
|useJackson3|Use Jackson 3 instead of Jackson 2. Supported for 'native' and 'apache-httpclient' libraries (requires Java 17+) and for Spring 'resttemplate', 'webclient', and 'restclient' libraries (require useSpringBoot4=true).| |false|

docs/generators/spring.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
102102
|title|server title name or client service name| |OpenAPI Spring|
103103
|unhandledException|Declare operation methods to throw a generic exception and allow unhandled exceptions (useful for Spring `@ControllerAdvice` directives).| |false|
104104
|useBeanValidation|Use BeanValidation API annotations| |true|
105-
|useDeductionForOneOfInterfaces|whether to use deduction for generated oneOf interfaces| |false|
105+
|useDeductionForOneOfInterfaces|Annotate discriminator-free oneOf interfaces with Jackson's @JsonTypeInfo(use = Id.DEDUCTION) and @JsonSubTypes so the concrete subtype is resolved from the JSON field set rather than a type-tag property. Has no effect when a discriminator is present (name-based resolution is used instead). Requires subtypes to have structurally distinct sets of properties.| |false|
106106
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
107107
|useFeignClientContextId|Whether to generate Feign client with contextId parameter.| |true|
108108
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|

modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,13 @@ public static enum ENUM_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case,
489489
public static final String X_MODEL_IS_MUTABLE = "x-model-is-mutable";
490490
public static final String X_IMPLEMENTS = "x-implements";
491491
public static final String X_IS_ONE_OF_INTERFACE = "x-is-one-of-interface";
492+
public static final String USE_DEDUCTION_FOR_ONE_OF_INTERFACES = "useDeductionForOneOfInterfaces";
493+
public static final String USE_DEDUCTION_FOR_ONE_OF_INTERFACES_DESC =
494+
"Annotate discriminator-free oneOf interfaces with Jackson's " +
495+
"@JsonTypeInfo(use = Id.DEDUCTION) and @JsonSubTypes so the concrete subtype " +
496+
"is resolved from the JSON field set rather than a type-tag property. " +
497+
"Has no effect when a discriminator is present (name-based resolution is used instead). " +
498+
"Requires subtypes to have structurally distinct sets of properties.";
492499
public static final String X_DISCRIMINATOR_VALUE = "x-discriminator-value";
493500
public static final String X_ONE_OF_NAME = "x-one-of-name";
494501
public static final String X_NULLABLE = "x-nullable";

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
import java.util.stream.Stream;
7676
import java.util.stream.StreamSupport;
7777

78+
import static org.openapitools.codegen.CodegenConstants.USE_DEDUCTION_FOR_ONE_OF_INTERFACES;
7879
import static org.openapitools.codegen.CodegenConstants.X_IMPLEMENTS;
7980
import static org.openapitools.codegen.utils.CamelizeOption.*;
8081
import static org.openapitools.codegen.utils.ModelUtils.getSchemaItems;
@@ -225,6 +226,8 @@ protected enum ENUM_PROPERTY_NAMING_TYPE {MACRO_CASE, legacy, original}
225226
@Setter
226227
protected boolean useJspecify;
227228
protected JSpecifyNullableLambda jSpecifyNullableLambda;
229+
@Getter @Setter
230+
protected boolean useDeductionForOneOfInterfaces = false;
228231

229232
private Map<String, String> schemaKeyToModelNameCache = new HashMap<>();
230233

@@ -608,6 +611,7 @@ public void processOpts() {
608611
convertPropertyToBooleanAndWriteBack(USE_ONE_OF_INTERFACES, this::setUseOneOfInterfaces);
609612
convertPropertyToStringAndWriteBack(CodegenConstants.ENUM_PROPERTY_NAMING, this::setEnumPropertyNaming);
610613
convertPropertyToBooleanAndWriteBack(USE_JSPECIFY, this::setUseJspecify);
614+
convertPropertyToBooleanAndWriteBack(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, this::setUseDeductionForOneOfInterfaces);
611615

612616
if (!StringUtils.isEmpty(parentGroupId) && !StringUtils.isEmpty(parentArtifactId) && !StringUtils.isEmpty(parentVersion)) {
613617
additionalProperties.put("parentOverridden", true);

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
4949
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
5050
import static java.util.Collections.sort;
51-
import static org.openapitools.codegen.CodegenConstants.X_IMPLEMENTS;
51+
import static org.openapitools.codegen.CodegenConstants.*;
5252
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
5353
import static org.openapitools.codegen.utils.StringUtils.camelize;
5454

@@ -285,6 +285,7 @@ public JavaClientCodegen() {
285285
cliOptions.add(CliOption.newBoolean(USE_SEALED_ONE_OF_INTERFACES, "Generate the oneOf interfaces as sealed interfaces. Only supported for WebClient and RestClient.", this.useSealedOneOfInterfaces));
286286
cliOptions.add(CliOption.newBoolean(USE_UNARY_INTERCEPTOR, "If true it will generate ResponseInterceptors using a UnaryOperator. This can be usefull for manipulating the request before it gets passed, for example doing your own decryption", this.useUnaryInterceptor));
287287
cliOptions.add(CliOption.newBoolean(USE_JSPECIFY, "Use Jspecify for null checks. Only supported for " + JSPECIFY_SUPPORTED_LIBRARIES, useJspecify));
288+
cliOptions.add(CliOption.newBoolean(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, USE_DEDUCTION_FOR_ONE_OF_INTERFACES_DESC, useDeductionForOneOfInterfaces));
288289

289290
supportedLibraries.put(JERSEY2, "HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.17.1");
290291
supportedLibraries.put(JERSEY3, "HTTP client: Jersey client 3.1.1. JSON processing: Jackson 2.17.1");

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
import java.util.stream.Collectors;
5555

5656
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
57+
import static org.openapitools.codegen.CodegenConstants.USE_DEDUCTION_FOR_ONE_OF_INTERFACES;
58+
import static org.openapitools.codegen.CodegenConstants.USE_DEDUCTION_FOR_ONE_OF_INTERFACES_DESC;
5759
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
5860
import static org.openapitools.codegen.utils.StringUtils.camelize;
5961

@@ -110,7 +112,6 @@ public class SpringCodegen extends AbstractJavaCodegen
110112
public static final String USE_SEALED = "useSealed";
111113
public static final String OPTIONAL_ACCEPT_NULLABLE = "optionalAcceptNullable";
112114
public static final String USE_SPRING_BUILT_IN_VALIDATION = "useSpringBuiltInValidation";
113-
public static final String USE_DEDUCTION_FOR_ONE_OF_INTERFACES = "useDeductionForOneOfInterfaces";
114115
public static final String SPRING_API_VERSION = "springApiVersion";
115116
public static final String USE_JACKSON_3 = "useJackson3";
116117
public static final String JACKSON2_PACKAGE = "com.fasterxml.jackson";
@@ -187,8 +188,6 @@ public enum RequestMappingMode {
187188
@Getter @Setter
188189
protected boolean useSpringBuiltInValidation = false;
189190
@Getter @Setter
190-
protected boolean useDeductionForOneOfInterfaces = false;
191-
@Getter @Setter
192191
protected boolean useJackson3 = false;
193192
@Getter @Setter
194193
protected boolean additionalNotNullAnnotations = false;
@@ -338,7 +337,7 @@ public SpringCodegen() {
338337
"Use `ofNullable` instead of just `of` to accept null values when using Optional.",
339338
optionalAcceptNullable));
340339

341-
cliOptions.add(CliOption.newBoolean(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, "whether to use deduction for generated oneOf interfaces", useDeductionForOneOfInterfaces));
340+
cliOptions.add(CliOption.newBoolean(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, USE_DEDUCTION_FOR_ONE_OF_INTERFACES_DESC, useDeductionForOneOfInterfaces));
342341
cliOptions.add(CliOption.newString(SPRING_API_VERSION, "Value for 'version' attribute in @RequestMapping (for Spring 7 and above)."));
343342
cliOptions.add(CliOption.newString(USE_HTTP_SERVICE_PROXY_FACTORY_INTERFACES_CONFIGURATOR,
344343
"Generate HttpInterfacesAbstractConfigurator based on an HttpServiceProxyFactory instance (as opposed to a WebClient instance, when disabled) for generating Spring HTTP interfaces.")
@@ -557,7 +556,6 @@ public void processOpts() {
557556
}
558557
convertPropertyToBooleanAndWriteBack(OPTIONAL_ACCEPT_NULLABLE, this::setOptionalAcceptNullable);
559558
convertPropertyToBooleanAndWriteBack(USE_SPRING_BUILT_IN_VALIDATION, this::setUseSpringBuiltInValidation);
560-
convertPropertyToBooleanAndWriteBack(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, this::setUseDeductionForOneOfInterfaces);
561559

562560
additionalProperties.put("springHttpStatus", new SpringHttpStatusLambda());
563561

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{{^discriminator}}
2+
{{#jackson}}
3+
{{#useDeductionForOneOfInterfaces}}
4+
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
5+
@JsonSubTypes({
6+
{{#interfaceModels}}
7+
@JsonSubTypes.Type(value = {{classname}}.class){{^-last}}, {{/-last}}
8+
{{/interfaceModels}}
9+
})
10+
{{/useDeductionForOneOfInterfaces}}
11+
{{/jackson}}
12+
{{/discriminator}}

modules/openapi-generator/src/main/resources/Java/oneof_interface.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{{>additionalOneOfTypeAnnotations}}{{>generatedAnnotation}}{{>typeInfoAnnotation}}{{>xmlAnnotation}}
1+
{{>additionalOneOfTypeAnnotations}}{{>generatedAnnotation}}{{>typeInfoAnnotation}}{{>deductionAnnotation}}{{>xmlAnnotation}}
22
{{#vendorExtensions.x-class-extra-annotation}}
33
{{{vendorExtensions.x-class-extra-annotation}}}
44
{{/vendorExtensions.x-class-extra-annotation}}

0 commit comments

Comments
 (0)