Skip to content

Commit 7e9b961

Browse files
jpfinneJean-Paul Finnemartin-mfg
authored
[Java] [Spring] Use deduction configOptions for oneOfInterfaces (#20919)
* fix(java): x-discriminator-value should not produce @JsonTypeName * fix(java): Remove unused getDiscriminatorValue() * build at Fednot * build at Fednot * build at Fednot: skip sonar * scm for release at fednot * build fednot not 7.5.0-FEDNOT-SNAPSHOT * build fednot not 7.5.0-FEDNOT-SNAPSHOT * test all vars * rollback custom pom.xml * commit master * commit test * Samples for deduction * add files for deduction * small improvements * Merge changes from martin-mfg Merge master * Merge changes from martin-mfg Merge master * Merge changes from martin-mfg Add comment to force rebuild * Merge master * regenerate doc * regenerate client * regenerate client --------- Co-authored-by: Jean-Paul Finne <jean-paul.finne@fednot.be> Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
1 parent 731668b commit 7e9b961

File tree

90 files changed

+4966
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+4966
-0
lines changed

.github/workflows/samples-spring-jdk17.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ on:
1111
- samples/server/petstore/springboot-file-delegate-optional
1212
- samples/server/petstore/springboot-petstore-with-api-response-examples
1313
- samples/server/petstore/spring-boot-oneof-sealed
14+
- samples/openapi3/server/petstore/spring-boot-oneof-interface
1415
pull_request:
1516
paths:
1617
- samples/openapi3/client/petstore/spring-cloud-3-with-optional
@@ -21,6 +22,7 @@ on:
2122
- samples/server/petstore/springboot-file-delegate-optional
2223
- samples/server/petstore/springboot-petstore-with-api-response-examples
2324
- samples/server/petstore/spring-boot-oneof-sealed
25+
- samples/openapi3/server/petstore/spring-boot-oneof-interface
2426
jobs:
2527
build:
2628
name: Build Java Spring (JDK17)
@@ -39,6 +41,7 @@ jobs:
3941
- samples/server/petstore/springboot-file-delegate-optional
4042
- samples/server/petstore/springboot-petstore-with-api-response-examples
4143
- samples/server/petstore/spring-boot-oneof-sealed
44+
- samples/openapi3/server/petstore/spring-boot-oneof-interface
4245
steps:
4346
- uses: actions/checkout@v5
4447
- uses: actions/setup-java@v5

.github/workflows/samples-spring.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ jobs:
6060
- samples/server/petstore/springboot-spring-provide-args
6161
- samples/server/petstore/springboot-useoptional
6262
- samples/server/petstore/springboot-virtualan
63+
- samples/openapi3/server/petstore/spring-boot-oneof-interface
6364
steps:
6465
- uses: actions/checkout@v5
6566
- uses: actions/setup-java@v5
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
generatorName: spring
2+
outputDir: samples/openapi3/server/petstore/spring-boot-oneof-interface
3+
inputSpec: modules/openapi-generator/src/test/resources/3_0/oneof_polymorphism_and_inheritance.yaml
4+
templateDir: modules/openapi-generator/src/main/resources/JavaSpring
5+
additionalProperties:
6+
groupId: org.openapitools.openapi3
7+
documentationProvider: springdoc
8+
artifactId: springboot-oneof
9+
snapshotVersion: "true"
10+
hideGenerationTimestamp: "true"
11+
useOneOfInterfaces: "true"
12+
useDeductionForOneOfInterfaces: "true"

docs/generators/java-camel.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
9999
|title|server title name or client service name| |OpenAPI Spring|
100100
|unhandledException|Declare operation methods to throw a generic exception and allow unhandled exceptions (useful for Spring `@ControllerAdvice` directives).| |false|
101101
|useBeanValidation|Use BeanValidation API annotations| |true|
102+
|useDeductionForOneOfInterfaces|whether to use deduction for generated oneOf interfaces| |false|
102103
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
103104
|useFeignClientContextId|Whether to generate Feign client with contextId parameter.| |true|
104105
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|

docs/generators/spring.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
9292
|title|server title name or client service name| |OpenAPI Spring|
9393
|unhandledException|Declare operation methods to throw a generic exception and allow unhandled exceptions (useful for Spring `@ControllerAdvice` directives).| |false|
9494
|useBeanValidation|Use BeanValidation API annotations| |true|
95+
|useDeductionForOneOfInterfaces|whether to use deduction for generated oneOf interfaces| |false|
9596
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
9697
|useFeignClientContextId|Whether to generate Feign client with contextId parameter.| |true|
9798
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public class SpringCodegen extends AbstractJavaCodegen
9999
public static final String USE_SEALED = "useSealed";
100100
public static final String OPTIONAL_ACCEPT_NULLABLE = "optionalAcceptNullable";
101101
public static final String USE_SPRING_BUILT_IN_VALIDATION = "useSpringBuiltInValidation";
102+
public static final String USE_DEDUCTION_FOR_ONE_OF_INTERFACES = "useDeductionForOneOfInterfaces";
102103

103104
@Getter
104105
public enum RequestMappingMode {
@@ -159,6 +160,8 @@ public enum RequestMappingMode {
159160
protected boolean optionalAcceptNullable = true;
160161
@Getter @Setter
161162
protected boolean useSpringBuiltInValidation = false;
163+
@Getter @Setter
164+
protected boolean useDeductionForOneOfInterfaces = false;
162165

163166
public SpringCodegen() {
164167
super();
@@ -282,6 +285,7 @@ public SpringCodegen() {
282285
"Use `ofNullable` instead of just `of` to accept null values when using Optional.",
283286
optionalAcceptNullable));
284287

288+
cliOptions.add(CliOption.newBoolean(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, "whether to use deduction for generated oneOf interfaces", useDeductionForOneOfInterfaces));
285289
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
286290
supportedLibraries.put(SPRING_CLOUD_LIBRARY,
287291
"Spring-Cloud-Feign client with Spring-Boot auto-configured settings.");
@@ -449,6 +453,7 @@ public void processOpts() {
449453
}
450454
convertPropertyToBooleanAndWriteBack(OPTIONAL_ACCEPT_NULLABLE, this::setOptionalAcceptNullable);
451455
convertPropertyToBooleanAndWriteBack(USE_SPRING_BUILT_IN_VALIDATION, this::setUseSpringBuiltInValidation);
456+
convertPropertyToBooleanAndWriteBack(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, this::setUseDeductionForOneOfInterfaces);
452457

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

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66
{{#discriminator}}
77
{{>typeInfoAnnotation}}
88

9+
{{/discriminator}}{{^discriminator}}{{#useDeductionForOneOfInterfaces}}
10+
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
11+
@JsonSubTypes({
12+
{{#interfaceModels}}
13+
@JsonSubTypes.Type(value = {{classname}}.class){{^-last}}, {{/-last}}
14+
{{/interfaceModels}}
15+
})
16+
{{/useDeductionForOneOfInterfaces}}
917
{{/discriminator}}
1018
{{>generatedAnnotation}}
1119

modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,10 +1764,13 @@ public void testOneOfAndAllOf() throws IOException {
17641764
generator.setGeneratorPropertyDefault(CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR, "false");
17651765

17661766
codegen.setUseOneOfInterfaces(true);
1767+
codegen.setUseDeductionForOneOfInterfaces(true);
17671768
codegen.setLegacyDiscriminatorBehavior(false);
17681769

17691770
generator.opts(input).generate();
17701771

1772+
// test deduction
1773+
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/Animal.java"), "@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)", "@JsonSubTypes.Type(value = Dog.class),", "@JsonSubTypes.Type(value = Cat.class)");
17711774
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/Foo.java"), "public class Foo extends Entity implements FooRefOrValue");
17721775
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/FooRef.java"), "public class FooRef extends EntityRef implements FooRefOrValue");
17731776
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/FooRefOrValue.java"), "public interface FooRefOrValue");

modules/openapi-generator/src/test/resources/3_0/oneof_polymorphism_and_inheritance.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,20 @@ components:
209209
properties:
210210
length:
211211
type: integer
212+
Animal:
213+
oneOf:
214+
- $ref: '#/components/schemas/Dog'
215+
- $ref: '#/components/schemas/Cat'
216+
Cat:
217+
type: object
218+
properties:
219+
declawed:
220+
type: boolean
221+
Dog:
222+
type: object
223+
properties:
224+
bark:
225+
type: boolean
212226

213227
requestBodies:
214228
Foo:
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# openapi-java-client
2+
3+
OpenAPI Petstore
4+
- API version: 1.0.0
5+
- Generator version: 7.6.0-SNAPSHOT
6+
7+
This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
8+
9+
10+
*Automatically generated by the [OpenAPI Generator](https://openapi-generator.tech)*
11+
12+
13+
## Requirements
14+
15+
Building the API client library requires:
16+
1. Java 1.8+
17+
2. Maven (3.8.3+)/Gradle (7.2+)
18+
19+
## Installation
20+
21+
To install the API client library to your local Maven repository, simply execute:
22+
23+
```shell
24+
mvn clean install
25+
```
26+
27+
To deploy it to a remote Maven repository instead, configure the settings of the repository and execute:
28+
29+
```shell
30+
mvn clean deploy
31+
```
32+
33+
Refer to the [OSSRH Guide](http://central.sonatype.org/pages/ossrh-guide.html) for more information.
34+
35+
### Maven users
36+
37+
Add this dependency to your project's POM:
38+
39+
```xml
40+
<dependency>
41+
<groupId>org.openapitools</groupId>
42+
<artifactId>openapi-java-client</artifactId>
43+
<version>1.0.0</version>
44+
<scope>compile</scope>
45+
</dependency>
46+
```
47+
48+
### Gradle users
49+
50+
Add this dependency to your project's build file:
51+
52+
```groovy
53+
repositories {
54+
mavenCentral() // Needed if the 'openapi-java-client' jar has been published to maven central.
55+
mavenLocal() // Needed if the 'openapi-java-client' jar has been published to the local maven repo.
56+
}
57+
58+
dependencies {
59+
implementation "org.openapitools:openapi-java-client:1.0.0"
60+
}
61+
```
62+
63+
### Others
64+
65+
At first generate the JAR by executing:
66+
67+
```shell
68+
mvn clean package
69+
```
70+
71+
Then manually install the following JARs:
72+
73+
* `target/openapi-java-client-1.0.0.jar`
74+
* `target/lib/*.jar`
75+
76+
## Getting Started
77+
78+
Please follow the [installation](#installation) instruction and execute the following Java code:
79+
80+
```java
81+
82+
// Import classes:
83+
import org.openapitools.client.ApiClient;
84+
import org.openapitools.client.ApiException;
85+
import org.openapitools.client.Configuration;
86+
import org.openapitools.client.auth.*;
87+
import org.openapitools.client.models.*;
88+
import org.openapitools.client.api.PetApi;
89+
90+
public class Example {
91+
public static void main(String[] args) {
92+
ApiClient defaultClient = Configuration.getDefaultApiClient();
93+
defaultClient.setBasePath("http://petstore.swagger.io/v2");
94+
95+
// Configure OAuth2 access token for authorization: petstore_auth
96+
OAuth petstore_auth = (OAuth) defaultClient.getAuthentication("petstore_auth");
97+
petstore_auth.setAccessToken("YOUR ACCESS TOKEN");
98+
99+
PetApi apiInstance = new PetApi(defaultClient);
100+
Pet pet = new Pet(); // Pet | Pet object that needs to be added to the store
101+
try {
102+
Pet result = apiInstance.addPet(pet);
103+
System.out.println(result);
104+
} catch (ApiException e) {
105+
System.err.println("Exception when calling PetApi#addPet");
106+
System.err.println("Status code: " + e.getCode());
107+
System.err.println("Reason: " + e.getResponseBody());
108+
System.err.println("Response headers: " + e.getResponseHeaders());
109+
e.printStackTrace();
110+
}
111+
}
112+
}
113+
114+
```
115+
116+
## Documentation for API Endpoints
117+
118+
All URIs are relative to *http://petstore.swagger.io/v2*
119+
120+
Class | Method | HTTP request | Description
121+
------------ | ------------- | ------------- | -------------
122+
*PetApi* | [**addPet**](docs/PetApi.md#addPet) | **POST** /pet | Add a new pet to the store
123+
*PetApi* | [**deletePet**](docs/PetApi.md#deletePet) | **DELETE** /pet/{petId} | Deletes a pet
124+
*PetApi* | [**findPetsByStatus**](docs/PetApi.md#findPetsByStatus) | **GET** /pet/findByStatus | Finds Pets by status
125+
*PetApi* | [**findPetsByTags**](docs/PetApi.md#findPetsByTags) | **GET** /pet/findByTags | Finds Pets by tags
126+
*PetApi* | [**getPetById**](docs/PetApi.md#getPetById) | **GET** /pet/{petId} | Find pet by ID
127+
*PetApi* | [**updatePet**](docs/PetApi.md#updatePet) | **PUT** /pet | Update an existing pet
128+
*PetApi* | [**updatePetWithForm**](docs/PetApi.md#updatePetWithForm) | **POST** /pet/{petId} | Updates a pet in the store with form data
129+
*PetApi* | [**uploadFile**](docs/PetApi.md#uploadFile) | **POST** /pet/{petId}/uploadImage | uploads an image
130+
*StoreApi* | [**deleteOrder**](docs/StoreApi.md#deleteOrder) | **DELETE** /store/order/{orderId} | Delete purchase order by ID
131+
*StoreApi* | [**getInventory**](docs/StoreApi.md#getInventory) | **GET** /store/inventory | Returns pet inventories by status
132+
*StoreApi* | [**getOrderById**](docs/StoreApi.md#getOrderById) | **GET** /store/order/{orderId} | Find purchase order by ID
133+
*StoreApi* | [**placeOrder**](docs/StoreApi.md#placeOrder) | **POST** /store/order | Place an order for a pet
134+
*UserApi* | [**createUser**](docs/UserApi.md#createUser) | **POST** /user | Create user
135+
*UserApi* | [**createUsersWithArrayInput**](docs/UserApi.md#createUsersWithArrayInput) | **POST** /user/createWithArray | Creates list of users with given input array
136+
*UserApi* | [**createUsersWithListInput**](docs/UserApi.md#createUsersWithListInput) | **POST** /user/createWithList | Creates list of users with given input array
137+
*UserApi* | [**deleteUser**](docs/UserApi.md#deleteUser) | **DELETE** /user/{username} | Delete user
138+
*UserApi* | [**getUserByName**](docs/UserApi.md#getUserByName) | **GET** /user/{username} | Get user by user name
139+
*UserApi* | [**loginUser**](docs/UserApi.md#loginUser) | **GET** /user/login | Logs user into the system
140+
*UserApi* | [**logoutUser**](docs/UserApi.md#logoutUser) | **GET** /user/logout | Logs out current logged in user session
141+
*UserApi* | [**updateUser**](docs/UserApi.md#updateUser) | **PUT** /user/{username} | Updated user
142+
143+
144+
## Documentation for Models
145+
146+
- [Category](docs/Category.md)
147+
- [ModelApiResponse](docs/ModelApiResponse.md)
148+
- [Order](docs/Order.md)
149+
- [Pet](docs/Pet.md)
150+
- [Tag](docs/Tag.md)
151+
- [User](docs/User.md)
152+
153+
154+
<a id="documentation-for-authorization"></a>
155+
## Documentation for Authorization
156+
157+
158+
Authentication schemes defined for the API:
159+
<a id="petstore_auth"></a>
160+
### petstore_auth
161+
162+
- **Type**: OAuth
163+
- **Flow**: implicit
164+
- **Authorization URL**: http://petstore.swagger.io/api/oauth/dialog
165+
- **Scopes**:
166+
- write:pets: modify pets in your account
167+
- read:pets: read your pets
168+
169+
<a id="api_key"></a>
170+
### api_key
171+
172+
- **Type**: API key
173+
- **API key parameter name**: api_key
174+
- **Location**: HTTP header
175+
176+
177+
## Recommendation
178+
179+
It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issues.
180+
181+
## Author
182+
183+
184+

0 commit comments

Comments
 (0)