Skip to content

Commit 87bd29c

Browse files
fix(normalizer): restore behavior of clearing a oneOf if the schema content cannot currently be used by the generator
1 parent 4e084cd commit 87bd29c

10 files changed

Lines changed: 318 additions & 15 deletions

File tree

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

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import static org.openapitools.codegen.CodegenConstants.*;
4444
import static org.openapitools.codegen.utils.EnumUtils.ANY_OF;
4545
import static org.openapitools.codegen.utils.EnumUtils.ONE_OF;
46+
import static org.openapitools.codegen.utils.ModelUtils.isOneOfOfConsts;
4647
import static org.openapitools.codegen.utils.ModelUtils.simplifyOneOfAnyOfWithOnlyOneNonNullSubSchema;
4748
import static org.openapitools.codegen.utils.StringUtils.getUniqueString;
4849

@@ -1705,18 +1706,24 @@ protected Schema processSimplifyOneOf(Schema schema) {
17051706
}
17061707

17071708
schema = simplifyOneOfAnyOfWithOnlyOneNonNullSubSchema(openAPI, schema, oneOfSchemas);
1708-
if (ModelUtils.isIntegerSchema(schema) || ModelUtils.isNumberSchema(schema) || ModelUtils.isStringSchema(schema)) {
1709-
if (schema.getSpecVersion().equals(SpecVersion.V30)) {
1710-
schema.setOneOf(null);
1711-
} //else {
1712-
// TODO convert oneOf const/deprecated to enum
1713-
// }
1714-
}
1709+
clearOneOf(schema);
17151710
}
17161711

17171712
return schema;
17181713
}
17191714

1715+
/**
1716+
* Removes the {@code oneOf} from the schema if it is considered to not contain information that the generator can
1717+
* currently act upon. The schema is left untouched if all the {@code oneOf} branches contain an OAS 3.1 {@code const}.
1718+
* This since that structure can potentially be used for enum interpretation.
1719+
*/
1720+
private void clearOneOf(Schema schema) {
1721+
if (ModelUtils.isIntegerSchema(schema) || ModelUtils.isNumberSchema(schema) || ModelUtils.isStringSchema(schema)) {
1722+
if (!isOneOfOfConsts(schema)) {
1723+
schema.setOneOf(null);
1724+
}
1725+
}
1726+
}
17201727

17211728
/**
17221729
* Ensure inheritance is correctly defined for OneOf and Discriminators.

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,6 +2802,19 @@ public static boolean containsEnums(OpenAPI openAPI) {
28022802
return schemaMap.values().stream().anyMatch(ModelUtils::isEnumSchema);
28032803
}
28042804

2805+
/**
2806+
* Whether all branches in the oneOf contains a {@code const}. Returns false for OAS 3.0 that does not support
2807+
* {@code const}.
2808+
* @param schema The Schema
2809+
* @return true if the schema is OAS 3.1 and all {@code oneOf} branches contains a {@code const}.
2810+
*/
2811+
public static boolean isOneOfOfConsts(Schema<?> schema) {
2812+
if (hasOneOf(schema) && schema.getSpecVersion().equals(SpecVersion.V31)) {
2813+
return schema.getOneOf().stream().allMatch(oneOf -> oneOf.getConst() != null);
2814+
}
2815+
return false;
2816+
}
2817+
28052818
@FunctionalInterface
28062819
private interface OpenAPISchemaVisitor {
28072820

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

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
public class OpenAPINormalizerTest {
3636

37+
private static final String SIMPLIFY_ONE_OF_ANY_OF = "SIMPLIFY_ONEOF_ANYOF";
38+
private static final String SIMPLIFY_ONEOF_ANYOF_ENUM = "SIMPLIFY_ONEOF_ANYOF_ENUM";
3739
private static final String REF_AS_PARENT_IN_ALLOF = "REF_AS_PARENT_IN_ALLOF";
3840
private static final String X_PARENT = "x-parent";
3941
private static final String X_INTERNAL = "x-internal";
@@ -201,7 +203,7 @@ public void testSimplifyOneOfAnyOfEnum() throws Exception {
201203

202204
// Test with rule enabled (default)
203205
Map<String, String> options = new HashMap<>();
204-
options.put("SIMPLIFY_ONEOF_ANYOF_ENUM", "true");
206+
options.put(SIMPLIFY_ONEOF_ANYOF_ENUM, "true");
205207
OpenAPINormalizer normalizer = new OpenAPINormalizer(openAPI, options);
206208
normalizer.normalize();
207209

@@ -239,7 +241,7 @@ public void testSimplifyOneOfAnyOfEnum() throws Exception {
239241
// Test with rule disabled
240242
OpenAPI openAPI2 = TestUtils.parseSpec("src/test/resources/3_0/simplifyOneOfWithEnums_test.yaml");
241243
Map<String, String> options2 = new HashMap<>();
242-
options2.put("SIMPLIFY_ONEOF_ANYOF_ENUM", "false");
244+
options2.put(SIMPLIFY_ONEOF_ANYOF_ENUM, "false");
243245
OpenAPINormalizer normalizer2 = new OpenAPINormalizer(openAPI2, options2);
244246
normalizer2.normalize();
245247

@@ -303,7 +305,7 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf() {
303305
assertEquals(schema19.getAnyOf().size(), 1);
304306

305307
Map<String, String> options = new HashMap<>();
306-
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
308+
options.put(SIMPLIFY_ONE_OF_ANY_OF, "true");
307309
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
308310
openAPINormalizer.normalize();
309311

@@ -361,7 +363,7 @@ public void testOpenAPINormalizerSimplifyOneOfWithSingleRef() {
361363
assertEquals(((Schema) oneOfWithSingleRef.getProperties().get("number")).getOneOf().size(), 1);
362364

363365
Map<String, String> options = new HashMap<>();
364-
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
366+
options.put(SIMPLIFY_ONE_OF_ANY_OF, "true");
365367
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
366368
openAPINormalizer.normalize();
367369

@@ -502,7 +504,7 @@ public void testOpenAPINormalizerConvertEnumNullToNullable() {
502504
assertNull(schema.getNullable());
503505

504506
Map<String, String> options = new HashMap<>();
505-
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
507+
options.put(SIMPLIFY_ONE_OF_ANY_OF, "true");
506508
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
507509
openAPINormalizer.normalize();
508510

@@ -1530,7 +1532,7 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf31Spec() {
15301532

15311533
// start the normalization
15321534
Map<String, String> options = new HashMap<>();
1533-
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
1535+
options.put(SIMPLIFY_ONE_OF_ANY_OF, "true");
15341536
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
15351537
openAPINormalizer.normalize();
15361538

@@ -1604,6 +1606,40 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf31Spec() {
16041606
assertEquals(((Schema) schema24.getProperties().get("anyof_nullable_number")).getTypes().size(), 1);
16051607
}
16061608

1609+
@Test
1610+
public void testOneOfWithStringsWithDifferentPatternsAreCollapsedWithSimplifyOneOfAnyOf() {
1611+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/simplifyOneOfAnyOf_test.yaml");
1612+
1613+
Schema stringPatternsWithOneOf = openAPI.getComponents().getSchemas().get("StringPatternsWithOneOf");
1614+
assertEquals(stringPatternsWithOneOf.getOneOf().size(), 2);
1615+
1616+
// start the normalization
1617+
Map<String, String> options = new HashMap<>();
1618+
options.put(SIMPLIFY_ONE_OF_ANY_OF, "true");
1619+
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
1620+
openAPINormalizer.normalize();
1621+
1622+
Schema normalizedStringPatternsWithOneOf = openAPI.getComponents().getSchemas().get("StringPatternsWithOneOf");
1623+
assertNull(normalizedStringPatternsWithOneOf.getOneOf());
1624+
}
1625+
1626+
@Test
1627+
public void testOneOfWithConstsIsUntouchedBySimplifyOneOfAnyOf() {
1628+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/simplifyOneOfAnyOf_test.yaml");
1629+
1630+
Schema integerWithOneOfConsts = openAPI.getComponents().getSchemas().get("TypeIntegerWithOneOf");
1631+
assertEquals(integerWithOneOfConsts.getOneOf().size(), 3);
1632+
1633+
// start the normalization
1634+
Map<String, String> options = new HashMap<>();
1635+
options.put(SIMPLIFY_ONEOF_ANYOF_ENUM, "false");
1636+
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
1637+
openAPINormalizer.normalize();
1638+
1639+
Schema normalizedIntegerWithOneOfConsts = openAPI.getComponents().getSchemas().get("TypeIntegerWithOneOf");
1640+
assertEquals(normalizedIntegerWithOneOfConsts.getOneOf().size(), 3);
1641+
}
1642+
16071643
@Test
16081644
public void testOpenAPINormalizerSimplifyOneOfWithSingleRef31Spec() {
16091645
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/simplifyOneOfAnyOf_test.yaml");
@@ -1612,7 +1648,7 @@ public void testOpenAPINormalizerSimplifyOneOfWithSingleRef31Spec() {
16121648
assertEquals(((Schema) oneOfWithSingleRef.getProperties().get("number")).getOneOf().size(), 1);
16131649

16141650
Map<String, String> options = new HashMap<>();
1615-
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
1651+
options.put(SIMPLIFY_ONE_OF_ANY_OF, "true");
16161652
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
16171653
openAPINormalizer.normalize();
16181654

modules/openapi-generator/src/test/resources/3_1/simplifyOneOfAnyOf_test.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,13 @@ components:
150150
OneOfNullAndRef3:
151151
oneOf:
152152
- $ref: '#/components/schemas/Parent'
153-
- type: "null"
153+
- type: "null"
154+
StringPatternsWithOneOf:
155+
type: string
156+
oneOf:
157+
- type: string
158+
description: Numeric identifier
159+
pattern: '^\d{1,35}$'
160+
- type: string
161+
description: UUID identifier
162+
pattern: '^[0-9a-f-]{36}$'

samples/client/petstore/csharp/generichost/latest/AnnotatedEnum/.openapi-generator/FILES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ docs/models/ParentWithPluralOneOfProperty.md
1717
docs/models/ParentWithPluralOneOfPropertyNumber.md
1818
docs/models/PropertiesWithAnyOf.md
1919
docs/models/SingleAnyOfTest.md
20+
docs/models/StringPatternsWithOneOf.md
2021
docs/models/TypeIntegerWithOneOf.md
2122
docs/scripts/git_push.ps1
2223
docs/scripts/git_push.sh
@@ -61,6 +62,7 @@ src/Org.OpenAPITools/Model/ParentWithPluralOneOfProperty.cs
6162
src/Org.OpenAPITools/Model/ParentWithPluralOneOfPropertyNumber.cs
6263
src/Org.OpenAPITools/Model/PropertiesWithAnyOf.cs
6364
src/Org.OpenAPITools/Model/SingleAnyOfTest.cs
65+
src/Org.OpenAPITools/Model/StringPatternsWithOneOf.cs
6466
src/Org.OpenAPITools/Model/TypeIntegerWithOneOf.cs
6567
src/Org.OpenAPITools/Org.OpenAPITools.csproj
6668
src/Org.OpenAPITools/README.md

samples/client/petstore/csharp/generichost/latest/AnnotatedEnum/api/openapi.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ components:
131131
allOf:
132132
- $ref: "#/components/schemas/Parent"
133133
nullable: true
134+
StringPatternsWithOneOf:
135+
oneOf:
136+
- description: Numeric identifier
137+
pattern: "^\\d{1,35}$"
138+
type: string
139+
- description: UUID identifier
140+
pattern: "^[0-9a-f-]{36}$"
141+
type: string
134142
ParentWithPluralOneOfProperty_number:
135143
oneOf:
136144
- $ref: "#/components/schemas/Number"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Org.OpenAPITools.Model.StringPatternsWithOneOf
2+
3+
## Properties
4+
5+
Name | Type | Description | Notes
6+
------------ | ------------- | ------------- | -------------
7+
8+
[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md)
9+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Example
3+
*
4+
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
5+
*
6+
* The version of the OpenAPI document: 1.0.0
7+
* Generated by: https://github.com/openapitools/openapi-generator.git
8+
*/
9+
10+
11+
using Xunit;
12+
13+
using System;
14+
using System.Linq;
15+
using System.IO;
16+
using System.Collections.Generic;
17+
using Org.OpenAPITools.Model;
18+
using Org.OpenAPITools.Client;
19+
using System.Reflection;
20+
21+
namespace Org.OpenAPITools.Test.Model
22+
{
23+
/// <summary>
24+
/// Class for testing StringPatternsWithOneOf
25+
/// </summary>
26+
/// <remarks>
27+
/// This file is automatically generated by OpenAPI Generator (https://openapi-generator.tech).
28+
/// Please update the test case below to test the model.
29+
/// </remarks>
30+
public class StringPatternsWithOneOfTests : IDisposable
31+
{
32+
// TODO uncomment below to declare an instance variable for StringPatternsWithOneOf
33+
//private StringPatternsWithOneOf instance;
34+
35+
public StringPatternsWithOneOfTests()
36+
{
37+
// TODO uncomment below to create an instance of StringPatternsWithOneOf
38+
//instance = new StringPatternsWithOneOf();
39+
}
40+
41+
public void Dispose()
42+
{
43+
// Cleanup when everything is done.
44+
}
45+
46+
/// <summary>
47+
/// Test an instance of StringPatternsWithOneOf
48+
/// </summary>
49+
[Fact]
50+
public void StringPatternsWithOneOfInstanceTest()
51+
{
52+
// TODO uncomment below to test "IsType" StringPatternsWithOneOf
53+
//Assert.IsType<StringPatternsWithOneOf>(instance);
54+
}
55+
}
56+
}

samples/client/petstore/csharp/generichost/latest/AnnotatedEnum/src/Org.OpenAPITools/Client/HostConfiguration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public HostConfiguration(IServiceCollection services)
5959
_jsonOptions.Converters.Add(new PropertiesWithAnyOfJsonConverter());
6060
_jsonOptions.Converters.Add(new SingleAnyOfTestJsonConverter());
6161
_jsonOptions.Converters.Add(new SingleAnyOfTestNullableJsonConverter());
62+
_jsonOptions.Converters.Add(new StringPatternsWithOneOfJsonConverter());
6263
_jsonOptions.Converters.Add(new TypeIntegerWithOneOfJsonConverter());
6364
_jsonOptions.Converters.Add(new TypeIntegerWithOneOfNullableJsonConverter());
6465
JsonSerializerOptionsProvider jsonSerializerOptionsProvider = new(_jsonOptions);

0 commit comments

Comments
 (0)