Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/generators/java-camel.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|title|server title name or client service name| |OpenAPI Spring|
|unhandledException|Declare operation methods to throw a generic exception and allow unhandled exceptions (useful for Spring `@ControllerAdvice` directives).| |false|
|useBeanValidation|Use BeanValidation API annotations| |true|
|useDeductionForOneOfInterfaces|whether to use deduction for generated oneOf interfaces| |false|
|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|
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
|useFeignClientContextId|Whether to generate Feign client with contextId parameter.| |true|
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|
Expand Down
1 change: 1 addition & 0 deletions docs/generators/java-microprofile.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
|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|
|useBeanValidation|Use BeanValidation API annotations| |false|
|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|
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
|useGzipFeature|Send gzip-encoded requests| |false|
|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|
Expand Down
1 change: 1 addition & 0 deletions docs/generators/java.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
|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|
|useBeanValidation|Use BeanValidation API annotations| |false|
|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|
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
|useGzipFeature|Send gzip-encoded requests| |false|
|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|
Expand Down
2 changes: 1 addition & 1 deletion docs/generators/spring.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|title|server title name or client service name| |OpenAPI Spring|
|unhandledException|Declare operation methods to throw a generic exception and allow unhandled exceptions (useful for Spring `@ControllerAdvice` directives).| |false|
|useBeanValidation|Use BeanValidation API annotations| |true|
|useDeductionForOneOfInterfaces|whether to use deduction for generated oneOf interfaces| |false|
|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|
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
|useFeignClientContextId|Whether to generate Feign client with contextId parameter.| |true|
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,13 @@ public static enum ENUM_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case,
public static final String X_MODEL_IS_MUTABLE = "x-model-is-mutable";
public static final String X_IMPLEMENTS = "x-implements";
public static final String X_IS_ONE_OF_INTERFACE = "x-is-one-of-interface";
public static final String USE_DEDUCTION_FOR_ONE_OF_INTERFACES = "useDeductionForOneOfInterfaces";
public static final String USE_DEDUCTION_FOR_ONE_OF_INTERFACES_DESC =
"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.";
public static final String X_DISCRIMINATOR_VALUE = "x-discriminator-value";
public static final String X_ONE_OF_NAME = "x-one-of-name";
public static final String X_NULLABLE = "x-nullable";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static org.openapitools.codegen.CodegenConstants.USE_DEDUCTION_FOR_ONE_OF_INTERFACES;
import static org.openapitools.codegen.CodegenConstants.X_IMPLEMENTS;
import static org.openapitools.codegen.utils.CamelizeOption.*;
import static org.openapitools.codegen.utils.ModelUtils.getSchemaItems;
Expand Down Expand Up @@ -225,6 +226,8 @@ protected enum ENUM_PROPERTY_NAMING_TYPE {MACRO_CASE, legacy, original}
@Setter
protected boolean useJspecify;
protected JSpecifyNullableLambda jSpecifyNullableLambda;
@Getter @Setter
protected boolean useDeductionForOneOfInterfaces = false;

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

Expand Down Expand Up @@ -608,6 +611,7 @@ public void processOpts() {
convertPropertyToBooleanAndWriteBack(USE_ONE_OF_INTERFACES, this::setUseOneOfInterfaces);
convertPropertyToStringAndWriteBack(CodegenConstants.ENUM_PROPERTY_NAMING, this::setEnumPropertyNaming);
convertPropertyToBooleanAndWriteBack(USE_JSPECIFY, this::setUseJspecify);
convertPropertyToBooleanAndWriteBack(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, this::setUseDeductionForOneOfInterfaces);

if (!StringUtils.isEmpty(parentGroupId) && !StringUtils.isEmpty(parentArtifactId) && !StringUtils.isEmpty(parentVersion)) {
additionalProperties.put("parentOverridden", true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
import static java.util.Collections.sort;
import static org.openapitools.codegen.CodegenConstants.X_IMPLEMENTS;
import static org.openapitools.codegen.CodegenConstants.*;
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
import static org.openapitools.codegen.utils.StringUtils.camelize;

Expand Down Expand Up @@ -285,6 +285,7 @@ public JavaClientCodegen() {
cliOptions.add(CliOption.newBoolean(USE_SEALED_ONE_OF_INTERFACES, "Generate the oneOf interfaces as sealed interfaces. Only supported for WebClient and RestClient.", this.useSealedOneOfInterfaces));
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));
cliOptions.add(CliOption.newBoolean(USE_JSPECIFY, "Use Jspecify for null checks. Only supported for " + JSPECIFY_SUPPORTED_LIBRARIES, useJspecify));
cliOptions.add(CliOption.newBoolean(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, USE_DEDUCTION_FOR_ONE_OF_INTERFACES_DESC, useDeductionForOneOfInterfaces));

supportedLibraries.put(JERSEY2, "HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.17.1");
supportedLibraries.put(JERSEY3, "HTTP client: Jersey client 3.1.1. JSON processing: Jackson 2.17.1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
import java.util.stream.Collectors;

import static org.apache.commons.lang3.StringUtils.isNotEmpty;
import static org.openapitools.codegen.CodegenConstants.USE_DEDUCTION_FOR_ONE_OF_INTERFACES;
import static org.openapitools.codegen.CodegenConstants.USE_DEDUCTION_FOR_ONE_OF_INTERFACES_DESC;
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
import static org.openapitools.codegen.utils.StringUtils.camelize;

Expand Down Expand Up @@ -110,7 +112,6 @@ public class SpringCodegen extends AbstractJavaCodegen
public static final String USE_SEALED = "useSealed";
public static final String OPTIONAL_ACCEPT_NULLABLE = "optionalAcceptNullable";
public static final String USE_SPRING_BUILT_IN_VALIDATION = "useSpringBuiltInValidation";
public static final String USE_DEDUCTION_FOR_ONE_OF_INTERFACES = "useDeductionForOneOfInterfaces";
public static final String SPRING_API_VERSION = "springApiVersion";
public static final String USE_JACKSON_3 = "useJackson3";
public static final String JACKSON2_PACKAGE = "com.fasterxml.jackson";
Expand Down Expand Up @@ -187,8 +188,6 @@ public enum RequestMappingMode {
@Getter @Setter
protected boolean useSpringBuiltInValidation = false;
@Getter @Setter
protected boolean useDeductionForOneOfInterfaces = false;
@Getter @Setter
protected boolean useJackson3 = false;
@Getter @Setter
protected boolean additionalNotNullAnnotations = false;
Expand Down Expand Up @@ -338,7 +337,7 @@ public SpringCodegen() {
"Use `ofNullable` instead of just `of` to accept null values when using Optional.",
optionalAcceptNullable));

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

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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{{^discriminator}}
{{#jackson}}
{{#useDeductionForOneOfInterfaces}}
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
@JsonSubTypes({
{{#interfaceModels}}
@JsonSubTypes.Type(value = {{classname}}.class){{^-last}}, {{/-last}}
{{/interfaceModels}}
})
{{/useDeductionForOneOfInterfaces}}
{{/jackson}}
{{/discriminator}}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{>additionalOneOfTypeAnnotations}}{{>generatedAnnotation}}{{>typeInfoAnnotation}}{{>xmlAnnotation}}
{{>additionalOneOfTypeAnnotations}}{{>generatedAnnotation}}{{>typeInfoAnnotation}}{{>deductionAnnotation}}{{>xmlAnnotation}}
{{#vendorExtensions.x-class-extra-annotation}}
{{{vendorExtensions.x-class-extra-annotation}}}
{{/vendorExtensions.x-class-extra-annotation}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4452,4 +4452,18 @@ void oneOf_issue_912() {
.recursivelyContainsWithNameAndAttributes("JsonSubTypes.Type", Map.of("value", "Source.class", "name", "\"source\""));
}

@Test
public void testUseDeductionForOneInterfaces() {
final Map<String, File> files = generateFromContract("src/test/resources/3_1/oneof_polymorphism_and_inheritance.yaml", RESTCLIENT,
Map.of(USE_ONE_OF_INTERFACES, "true", USE_DEDUCTION_FOR_ONE_OF_INTERFACES, "true"));
JavaFileAssert.assertThat(files.get("Animal.java")).fileContains("@JsonSubTypes")
.isInterface()
.assertTypeAnnotations().containsWithName("JsonSubTypes")
.recursivelyContainsWithNameAndAttributes("JsonSubTypes.Type", Map.of("value", "Dog.class"))
.recursivelyContainsWithNameAndAttributes("JsonSubTypes.Type", Map.of("value", "Cat.class"))
.containsWithNameAndAttributes("JsonTypeInfo", Map.of("use", "JsonTypeInfo.Id.DEDUCTION"));

}


}
Loading