Skip to content

Commit 1dc0dbb

Browse files
BethibandeRenato Mameli
authored and
Renato Mameli
committed
[BUG] [Java] Invalid code generation for oneof types. (OpenAPITools#18544)
* [BUG] [Java] Invalid code generation for oneof types. OpenAPITools#18517 * update samples * [BUG] [Java] Invalid code generation for oneof types. OpenAPITools#18517 * [BUG] [Java] Invalid code generation for oneof types. OpenAPITools#18517 * [BUG] [Java] Invalid code generation for oneof types. OpenAPITools#18544
1 parent d6d8187 commit 1dc0dbb

File tree

15 files changed

+1057
-3
lines changed

15 files changed

+1057
-3
lines changed

modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/oneof_model.mustache

+85-3
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,21 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
4848
{{#composedSchemas}}
4949
{{#oneOf}}
5050
{{^isArray}}
51+
{{^isMap}}
5152
{{^vendorExtensions.x-duplicated-data-type}}
5253
final TypeAdapter<{{{dataType}}}> adapter{{{dataType}}} = gson.getDelegateAdapter(this, TypeToken.get({{{dataType}}}.class));
5354
{{/vendorExtensions.x-duplicated-data-type}}
55+
{{/isMap}}
5456
{{/isArray}}
5557
{{#isArray}}
5658

5759
final Type typeInstance = new TypeToken<{{{dataType}}}>(){}.getType();
5860
final TypeAdapter<{{{dataType}}}> adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}} = (TypeAdapter<{{{dataType}}}>) gson.getDelegateAdapter(this, TypeToken.get(typeInstance));
5961
{{/isArray}}
62+
{{#isMap}}
63+
final Type typeInstance = new TypeToken<{{{dataType}}}>(){}.getType();
64+
final TypeAdapter<{{{dataType}}}> adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}} = (TypeAdapter<{{{dataType}}}>) gson.getDelegateAdapter(this, TypeToken.get(typeInstance));
65+
{{/isMap}}
6066
{{/oneOf}}
6167
{{/composedSchemas}}
6268

@@ -72,11 +78,18 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
7278
{{#oneOf}}
7379
{{^vendorExtensions.x-duplicated-data-type}}
7480
// check if the actual instance is of the type `{{{dataType}}}`
75-
if (value.getActualInstance() instanceof {{#isArray}}List<?>{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) {
81+
if (value.getActualInstance() instanceof {{#isArray}}List<?>{{/isArray}}{{#isMap}}Map<?, ?>{{/isMap}}{{^isMap}}{{^isArray}}{{{dataType}}}{{/isArray}}{{/isMap}}) {
7682
{{#isPrimitiveType}}
83+
{{^isMap}}
7784
JsonPrimitive primitive = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}.toJsonTree(({{{dataType}}})value.getActualInstance()).getAsJsonPrimitive();
7885
elementAdapter.write(out, primitive);
7986
return;
87+
{{/isMap}}
88+
{{#isMap}}
89+
JsonObject object = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}.toJsonTree(({{{dataType}}})value.getActualInstance()).getAsJsonObject();
90+
elementAdapter.write(out, object);
91+
return;
92+
{{/isMap}}
8093
{{/isPrimitiveType}}
8194
{{^isPrimitiveType}}
8295
{{#isArray}}
@@ -88,13 +101,15 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
88101
}
89102
{{/isArray}}
90103
{{/isPrimitiveType}}
104+
{{^isMap}}
91105
{{^isArray}}
92106
{{^isPrimitiveType}}
93107
JsonElement element = adapter{{{dataType}}}.toJsonTree(({{{dataType}}})value.getActualInstance());
94108
elementAdapter.write(out, element);
95109
return;
96110
{{/isPrimitiveType}}
97111
{{/isArray}}
112+
{{/isMap}}
98113
}
99114
{{/vendorExtensions.x-duplicated-data-type}}
100115
{{/oneOf}}
@@ -143,6 +158,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
143158
try {
144159
// validate the JSON object to see if any exception is thrown
145160
{{^isArray}}
161+
{{^isMap}}
146162
{{#isNumber}}
147163
if (!jsonElement.getAsJsonPrimitive().isNumber()) {
148164
throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString()));
@@ -163,6 +179,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
163179
actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}};
164180
{{/isPrimitiveType}}
165181
{{/isNumber}}
182+
{{/isMap}}
166183
{{/isArray}}
167184
{{#isArray}}
168185
if (!jsonElement.isJsonArray()) {
@@ -194,6 +211,38 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
194211
}
195212
actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}};
196213
{{/isArray}}
214+
{{#isMap}}
215+
if (!jsonElement.isJsonObject()) {
216+
throw new IllegalArgumentException(String.format("Expected json element to be a object type in the JSON string but got `%s`", jsonElement.toString()));
217+
}
218+
219+
{{^isFreeFormObject}}
220+
Map<String, JsonElement> map = jsonElement.getAsJsonObject().asMap();
221+
// validate map items
222+
for(JsonElement element : map.values()) {
223+
{{#items}}
224+
{{#isNumber}}
225+
if (!jsonElement.getAsJsonPrimitive().isNumber()) {
226+
throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString()));
227+
}
228+
{{/isNumber}}
229+
{{^isNumber}}
230+
{{#isPrimitiveType}}
231+
if (!element.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) {
232+
throw new IllegalArgumentException(String.format("Expected array items to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString()));
233+
}
234+
{{/isPrimitiveType}}
235+
{{/isNumber}}
236+
{{^isNumber}}
237+
{{^isPrimitiveType}}
238+
{{{dataType}}}.validateJsonElement(element);
239+
{{/isPrimitiveType}}
240+
{{/isNumber}}
241+
{{/items}}
242+
}
243+
{{/isFreeFormObject}}
244+
actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}};
245+
{{/isMap}}
197246
match++;
198247
log.log(Level.FINER, "Input data matches schema '{{{dataType}}}'");
199248
} catch (Exception e) {
@@ -280,7 +329,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
280329
{{#composedSchemas}}
281330
{{#oneOf}}
282331
{{^vendorExtensions.x-duplicated-data-type}}
283-
if (instance instanceof {{#isArray}}List<?>{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) {
332+
if (instance instanceof {{#isArray}}List<?>{{/isArray}}{{#isMap}}Map<?, ?>{{/isMap}}{{^isMap}}{{^isArray}}{{{dataType}}}{{/isArray}}{{/isMap}}) {
284333
{{#isArray}}
285334
List<?> list = (List<?>) instance;
286335
if (list.get(0) instanceof {{{items.dataType}}}) {
@@ -322,7 +371,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
322371
* @return The actual instance of `{{{dataType}}}`
323372
* @throws ClassCastException if the instance is not `{{{dataType}}}`
324373
*/
325-
public {{{dataType}}} get{{#isArray}}{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}() throws ClassCastException {
374+
public {{{dataType}}} get{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}() throws ClassCastException {
326375
return ({{{dataType}}})super.getActualInstance();
327376
}
328377
{{/vendorExtensions.x-duplicated-data-type}}
@@ -345,6 +394,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
345394
// validate the json string with {{{dataType}}}
346395
try {
347396
{{^hasVars}}
397+
{{^isMap}}
348398
{{^isArray}}
349399
{{#isNumber}}
350400
if (!jsonElement.getAsJsonPrimitive().isNumber()) {
@@ -364,6 +414,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
364414
{{/isPrimitiveType}}
365415
{{/isNumber}}
366416
{{/isArray}}
417+
{{/isMap}}
367418
{{#isArray}}
368419
if (!jsonElement.isJsonArray()) {
369420
throw new IllegalArgumentException(String.format("Expected json element to be a array type in the JSON string but got `%s`", jsonElement.toString()));
@@ -392,6 +443,37 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
392443
{{/items}}
393444
}
394445
{{/isArray}}
446+
{{#isMap}}
447+
if (!jsonElement.isJsonObject()) {
448+
throw new IllegalArgumentException(String.format("Expected json element to be a object type in the JSON string but got `%s`", jsonElement.toString()));
449+
}
450+
451+
{{^isFreeFormObject}}
452+
Map<String, JsonElement> map = jsonElement.getAsJsonObject().asMap();
453+
// validate map items
454+
for(JsonElement element : map.values()) {
455+
{{#items}}
456+
{{#isNumber}}
457+
if (!jsonElement.getAsJsonPrimitive().isNumber()) {
458+
throw new IllegalArgumentException(String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString()));
459+
}
460+
{{/isNumber}}
461+
{{^isNumber}}
462+
{{#isPrimitiveType}}
463+
if (!element.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) {
464+
throw new IllegalArgumentException(String.format("Expected array items to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString()));
465+
}
466+
{{/isPrimitiveType}}
467+
{{/isNumber}}
468+
{{^isNumber}}
469+
{{^isPrimitiveType}}
470+
{{{dataType}}}.validateJsonElement(element);
471+
{{/isPrimitiveType}}
472+
{{/isNumber}}
473+
{{/items}}
474+
}
475+
{{/isFreeFormObject}}
476+
{{/isMap}}
395477
{{/hasVars}}
396478
{{#hasVars}}
397479
{{{.}}}.validateJsonElement(jsonElement);

modules/openapi-generator/src/test/resources/3_0/java/petstore-with-fake-endpoints-models-for-testing-okhttp-gson.yaml

+22
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,18 @@ paths:
10481048
schema:
10491049
$ref: '#/components/schemas/FileSchemaTestClass'
10501050
required: true
1051+
/fake/get-free-form-object:
1052+
get:
1053+
tags:
1054+
- fake
1055+
description: Get a free form object or Json string
1056+
responses:
1057+
'200':
1058+
description: Success
1059+
content:
1060+
application/json:
1061+
schema:
1062+
$ref: '#/components/schemas/FreeFormObjectTestClass'
10511063
/fake/test-query-parameters:
10521064
put:
10531065
tags:
@@ -2035,6 +2047,16 @@ components:
20352047
type: array
20362048
items:
20372049
$ref: '#/components/schemas/File'
2050+
FreeFormObjectTestClass:
2051+
type: object
2052+
properties:
2053+
name:
2054+
type: string
2055+
properties:
2056+
oneOf:
2057+
- type: string
2058+
- type: object
2059+
additionalProperties: true
20382060
File:
20392061
type: object
20402062
description: Must be named `File` for test.

samples/client/petstore/java/okhttp-gson/.openapi-generator/FILES

+4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ docs/FileSchemaTestClass.md
4848
docs/Foo.md
4949
docs/FooGetDefaultResponse.md
5050
docs/FormatTest.md
51+
docs/FreeFormObjectTestClass.md
52+
docs/FreeFormObjectTestClassProperties.md
5153
docs/Fruit.md
5254
docs/FruitReq.md
5355
docs/GmFruit.md
@@ -187,6 +189,8 @@ src/main/java/org/openapitools/client/model/FileSchemaTestClass.java
187189
src/main/java/org/openapitools/client/model/Foo.java
188190
src/main/java/org/openapitools/client/model/FooGetDefaultResponse.java
189191
src/main/java/org/openapitools/client/model/FormatTest.java
192+
src/main/java/org/openapitools/client/model/FreeFormObjectTestClass.java
193+
src/main/java/org/openapitools/client/model/FreeFormObjectTestClassProperties.java
190194
src/main/java/org/openapitools/client/model/Fruit.java
191195
src/main/java/org/openapitools/client/model/FruitReq.java
192196
src/main/java/org/openapitools/client/model/GmFruit.java

samples/client/petstore/java/okhttp-gson/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ Class | Method | HTTP request | Description
119119
*AnotherFakeApi* | [**getParameterStringNumber**](docs/AnotherFakeApi.md#getParameterStringNumber) | **GET** /fake/parameter-string-number | parameter string number
120120
*AnotherFakeApi* | [**nullRequestBody**](docs/AnotherFakeApi.md#nullRequestBody) | **GET** /fake/null-request-body | null request body
121121
*DefaultApi* | [**fooGet**](docs/DefaultApi.md#fooGet) | **GET** /foo |
122+
*FakeApi* | [**fakeGetFreeFormObjectGet**](docs/FakeApi.md#fakeGetFreeFormObjectGet) | **GET** /fake/get-free-form-object |
122123
*FakeApi* | [**fakeOuterBooleanSerialize**](docs/FakeApi.md#fakeOuterBooleanSerialize) | **POST** /fake/outer/boolean |
123124
*FakeApi* | [**fakeOuterCompositeSerialize**](docs/FakeApi.md#fakeOuterCompositeSerialize) | **POST** /fake/outer/composite |
124125
*FakeApi* | [**fakeOuterNumberSerialize**](docs/FakeApi.md#fakeOuterNumberSerialize) | **POST** /fake/outer/number |
@@ -205,6 +206,8 @@ Class | Method | HTTP request | Description
205206
- [Foo](docs/Foo.md)
206207
- [FooGetDefaultResponse](docs/FooGetDefaultResponse.md)
207208
- [FormatTest](docs/FormatTest.md)
209+
- [FreeFormObjectTestClass](docs/FreeFormObjectTestClass.md)
210+
- [FreeFormObjectTestClassProperties](docs/FreeFormObjectTestClassProperties.md)
208211
- [Fruit](docs/Fruit.md)
209212
- [FruitReq](docs/FruitReq.md)
210213
- [GmFruit](docs/GmFruit.md)

samples/client/petstore/java/okhttp-gson/api/openapi.yaml

+29
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,20 @@ paths:
11171117
x-content-type: application/json
11181118
x-accepts:
11191119
- application/json
1120+
/fake/get-free-form-object:
1121+
get:
1122+
description: Get a free form object or Json string
1123+
responses:
1124+
"200":
1125+
content:
1126+
application/json:
1127+
schema:
1128+
$ref: '#/components/schemas/FreeFormObjectTestClass'
1129+
description: Success
1130+
tags:
1131+
- fake
1132+
x-accepts:
1133+
- application/json
11201134
/fake/test-query-parameters:
11211135
put:
11221136
description: To test the collection format in query parameters
@@ -2134,6 +2148,16 @@ components:
21342148
$ref: '#/components/schemas/File'
21352149
type: array
21362150
type: object
2151+
FreeFormObjectTestClass:
2152+
example:
2153+
name: name
2154+
properties: FreeFormObjectTestClass_properties
2155+
properties:
2156+
name:
2157+
type: string
2158+
properties:
2159+
$ref: '#/components/schemas/FreeFormObjectTestClass_properties'
2160+
type: object
21372161
File:
21382162
description: Must be named `File` for test.
21392163
example:
@@ -2881,6 +2905,11 @@ components:
28812905
required:
28822906
- requiredFile
28832907
type: object
2908+
FreeFormObjectTestClass_properties:
2909+
oneOf:
2910+
- type: string
2911+
- additionalProperties: true
2912+
type: object
28842913
ArrayOfInlineAllOf_array_allof_dog_property_inner:
28852914
allOf:
28862915
- properties:

samples/client/petstore/java/okhttp-gson/docs/FakeApi.md

+59
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ All URIs are relative to *http://petstore.swagger.io:80/v2*
44

55
| Method | HTTP request | Description |
66
|------------- | ------------- | -------------|
7+
| [**fakeGetFreeFormObjectGet**](FakeApi.md#fakeGetFreeFormObjectGet) | **GET** /fake/get-free-form-object | |
78
| [**fakeOuterBooleanSerialize**](FakeApi.md#fakeOuterBooleanSerialize) | **POST** /fake/outer/boolean | |
89
| [**fakeOuterCompositeSerialize**](FakeApi.md#fakeOuterCompositeSerialize) | **POST** /fake/outer/composite | |
910
| [**fakeOuterNumberSerialize**](FakeApi.md#fakeOuterNumberSerialize) | **POST** /fake/outer/number | |
@@ -26,6 +27,64 @@ All URIs are relative to *http://petstore.swagger.io:80/v2*
2627
| [**testStringMapReference**](FakeApi.md#testStringMapReference) | **POST** /fake/stringMap-reference | test referenced string map |
2728

2829

30+
<a id="fakeGetFreeFormObjectGet"></a>
31+
# **fakeGetFreeFormObjectGet**
32+
> FreeFormObjectTestClass fakeGetFreeFormObjectGet()
33+
34+
35+
36+
Get a free form object or Json string
37+
38+
### Example
39+
```java
40+
// Import classes:
41+
import org.openapitools.client.ApiClient;
42+
import org.openapitools.client.ApiException;
43+
import org.openapitools.client.Configuration;
44+
import org.openapitools.client.models.*;
45+
import org.openapitools.client.api.FakeApi;
46+
47+
public class Example {
48+
public static void main(String[] args) {
49+
ApiClient defaultClient = Configuration.getDefaultApiClient();
50+
defaultClient.setBasePath("http://petstore.swagger.io:80/v2");
51+
52+
FakeApi apiInstance = new FakeApi(defaultClient);
53+
try {
54+
FreeFormObjectTestClass result = apiInstance.fakeGetFreeFormObjectGet();
55+
System.out.println(result);
56+
} catch (ApiException e) {
57+
System.err.println("Exception when calling FakeApi#fakeGetFreeFormObjectGet");
58+
System.err.println("Status code: " + e.getCode());
59+
System.err.println("Reason: " + e.getResponseBody());
60+
System.err.println("Response headers: " + e.getResponseHeaders());
61+
e.printStackTrace();
62+
}
63+
}
64+
}
65+
```
66+
67+
### Parameters
68+
This endpoint does not need any parameter.
69+
70+
### Return type
71+
72+
[**FreeFormObjectTestClass**](FreeFormObjectTestClass.md)
73+
74+
### Authorization
75+
76+
No authorization required
77+
78+
### HTTP request headers
79+
80+
- **Content-Type**: Not defined
81+
- **Accept**: application/json
82+
83+
### HTTP response details
84+
| Status code | Description | Response headers |
85+
|-------------|-------------|------------------|
86+
| **200** | Success | - |
87+
2988
<a id="fakeOuterBooleanSerialize"></a>
3089
# **fakeOuterBooleanSerialize**
3190
> Boolean fakeOuterBooleanSerialize(body)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
3+
# FreeFormObjectTestClass
4+
5+
6+
## Properties
7+
8+
| Name | Type | Description | Notes |
9+
|------------ | ------------- | ------------- | -------------|
10+
|**name** | **String** | | [optional] |
11+
|**properties** | [**FreeFormObjectTestClassProperties**](FreeFormObjectTestClassProperties.md) | | [optional] |
12+
13+
14+

0 commit comments

Comments
 (0)