Skip to content

Commit 652d4ed

Browse files
authored
Remove duplicate oneOf schemas during pre-processing (#21174)
* fix: Remove duplicate oneOf schemas during pre-processing * chore: Updated samples * fix: Fixed regression with oneOf+discriminator * fix: Fixed possible null pointer during schema preprocessing * refactor: Moved oneOf deduplication to OpenAPINormalizer
1 parent 104ceb9 commit 652d4ed

File tree

93 files changed

+1503
-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.

93 files changed

+1503
-0
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,9 @@ protected Schema normalizeAllOfWithProperties(Schema schema, Set<Schema> visited
922922
}
923923

924924
protected Schema normalizeOneOf(Schema schema, Set<Schema> visitedSchemas) {
925+
// Remove duplicate oneOf entries
926+
ModelUtils.deduplicateOneOfSchema(schema);
927+
925928
// simplify first as the schema may no longer be a oneOf after processing the rule below
926929
schema = processSimplifyOneOf(schema);
927930

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2243,6 +2243,23 @@ public static Schema simplyOneOfAnyOfWithOnlyOneNonNullSubSchema(OpenAPI openAPI
22432243
return schema;
22442244
}
22452245

2246+
/**
2247+
* Removes duplicate `oneOf` from a given schema if it does not also have a discriminator.
2248+
*
2249+
* @param schema Schema
2250+
*/
2251+
public static void deduplicateOneOfSchema(Schema<?> schema) {
2252+
if (schema.getOneOf() == null) {
2253+
return;
2254+
}
2255+
if (schema.getDiscriminator() != null) {
2256+
return; // Duplicate oneOf are allowed if there is a discriminator that can be used to separate them.
2257+
}
2258+
2259+
Set<Schema> deduplicated = new LinkedHashSet<>(schema.getOneOf());
2260+
schema.setOneOf(new ArrayList<>(deduplicated));
2261+
}
2262+
22462263
/**
22472264
* Check if the schema is of type 'null' or schema itself is pointing to null
22482265
* <p>

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,3 +1107,16 @@ components:
11071107
allOf:
11081108
- $ref: '#/components/schemas/existing_tags_array'
11091109
- description: This is a test for allOf with metadata only fields
1110+
DuplicateOneOf:
1111+
type: object
1112+
oneOf:
1113+
- $ref: '#/components/schemas/Order'
1114+
- $ref: '#/components/schemas/Order'
1115+
WithInnerOneOf:
1116+
type: object
1117+
properties:
1118+
foo:
1119+
type: object
1120+
oneOf:
1121+
- $ref: '#/components/schemas/Order'
1122+
- $ref: '#/components/schemas/Order'

samples/client/petstore/rust/hyper/petstore/.openapi-generator/FILES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ docs/UniqueItemArrayTesting.md
3232
docs/User.md
3333
docs/UserApi.md
3434
docs/Vehicle.md
35+
docs/WithInnerOneOf.md
3536
git_push.sh
3637
src/apis/client.rs
3738
src/apis/configuration.rs
@@ -69,3 +70,4 @@ src/models/type_testing.rs
6970
src/models/unique_item_array_testing.rs
7071
src/models/user.rs
7172
src/models/vehicle.rs
73+
src/models/with_inner_one_of.rs

samples/client/petstore/rust/hyper/petstore/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Class | Method | HTTP request | Description
8080
- [UniqueItemArrayTesting](docs/UniqueItemArrayTesting.md)
8181
- [User](docs/User.md)
8282
- [Vehicle](docs/Vehicle.md)
83+
- [WithInnerOneOf](docs/WithInnerOneOf.md)
8384

8485

8586
To get access to the crate's generated documentation, use:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# DuplicateOneOf
2+
3+
## Enum Variants
4+
5+
| Name | Description |
6+
|---- | -----|
7+
| Order | |
8+
9+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
10+
11+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# WithInnerOneOf
2+
3+
## Properties
4+
5+
Name | Type | Description | Notes
6+
------------ | ------------- | ------------- | -------------
7+
**foo** | Option<[**models::Order**](Order.md)> | | [optional]
8+
9+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
10+
11+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# WithInnerOneOfFoo
2+
3+
## Enum Variants
4+
5+
| Name | Description |
6+
|---- | -----|
7+
| Order | |
8+
9+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
10+
11+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* OpenAPI Petstore
3+
*
4+
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
5+
*
6+
* The version of the OpenAPI document: 1.0.0
7+
*
8+
* Generated by: https://openapi-generator.tech
9+
*/
10+
11+
use crate::models;
12+
use serde::{Deserialize, Serialize};
13+
14+
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
15+
#[serde(untagged)]
16+
pub enum DuplicateOneOf {
17+
Order(Box<models::Order>),
18+
}
19+
20+
impl Default for DuplicateOneOf {
21+
fn default() -> Self {
22+
Self::Order(Default::default())
23+
}
24+
}
25+
/// Order Status
26+
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
27+
pub enum Status {
28+
#[serde(rename = "placed")]
29+
Placed,
30+
#[serde(rename = "approved")]
31+
Approved,
32+
#[serde(rename = "delivered")]
33+
Delivered,
34+
}
35+
36+
impl Default for Status {
37+
fn default() -> Status {
38+
Self::Placed
39+
}
40+
}
41+

samples/client/petstore/rust/hyper/petstore/src/models/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ pub mod user;
4848
pub use self::user::User;
4949
pub mod vehicle;
5050
pub use self::vehicle::Vehicle;
51+
pub mod with_inner_one_of;
52+
pub use self::with_inner_one_of::WithInnerOneOf;
5153
use serde::{Deserialize, Deserializer, Serializer};
5254
use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs};
5355
use std::marker::PhantomData;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* OpenAPI Petstore
3+
*
4+
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
5+
*
6+
* The version of the OpenAPI document: 1.0.0
7+
*
8+
* Generated by: https://openapi-generator.tech
9+
*/
10+
11+
use crate::models;
12+
use serde::{Deserialize, Serialize};
13+
14+
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
15+
pub struct WithInnerOneOf {
16+
#[serde(rename = "foo", skip_serializing_if = "Option::is_none")]
17+
pub foo: Option<Box<models::Order>>,
18+
}
19+
20+
impl WithInnerOneOf {
21+
pub fn new() -> WithInnerOneOf {
22+
WithInnerOneOf {
23+
foo: None,
24+
}
25+
}
26+
}
27+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* OpenAPI Petstore
3+
*
4+
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
5+
*
6+
* The version of the OpenAPI document: 1.0.0
7+
*
8+
* Generated by: https://openapi-generator.tech
9+
*/
10+
11+
use crate::models;
12+
use serde::{Deserialize, Serialize};
13+
14+
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
15+
#[serde(untagged)]
16+
pub enum WithInnerOneOfFoo {
17+
Order(Box<models::Order>),
18+
}
19+
20+
impl Default for WithInnerOneOfFoo {
21+
fn default() -> Self {
22+
Self::Order(Default::default())
23+
}
24+
}
25+
/// Order Status
26+
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
27+
pub enum Status {
28+
#[serde(rename = "placed")]
29+
Placed,
30+
#[serde(rename = "approved")]
31+
Approved,
32+
#[serde(rename = "delivered")]
33+
Delivered,
34+
}
35+
36+
impl Default for Status {
37+
fn default() -> Status {
38+
Self::Placed
39+
}
40+
}
41+

samples/client/petstore/rust/hyper0x/petstore/.openapi-generator/FILES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ docs/UniqueItemArrayTesting.md
3232
docs/User.md
3333
docs/UserApi.md
3434
docs/Vehicle.md
35+
docs/WithInnerOneOf.md
3536
git_push.sh
3637
src/apis/configuration.rs
3738
src/apis/fake_api.rs
@@ -67,3 +68,4 @@ src/models/type_testing.rs
6768
src/models/unique_item_array_testing.rs
6869
src/models/user.rs
6970
src/models/vehicle.rs
71+
src/models/with_inner_one_of.rs

samples/client/petstore/rust/hyper0x/petstore/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Class | Method | HTTP request | Description
8080
- [UniqueItemArrayTesting](docs/UniqueItemArrayTesting.md)
8181
- [User](docs/User.md)
8282
- [Vehicle](docs/Vehicle.md)
83+
- [WithInnerOneOf](docs/WithInnerOneOf.md)
8384

8485

8586
To get access to the crate's generated documentation, use:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# DuplicateOneOf
2+
3+
## Enum Variants
4+
5+
| Name | Description |
6+
|---- | -----|
7+
| Order | |
8+
9+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
10+
11+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# WithInnerOneOf
2+
3+
## Properties
4+
5+
Name | Type | Description | Notes
6+
------------ | ------------- | ------------- | -------------
7+
**foo** | Option<[**models::Order**](Order.md)> | | [optional]
8+
9+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
10+
11+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# WithInnerOneOfFoo
2+
3+
## Enum Variants
4+
5+
| Name | Description |
6+
|---- | -----|
7+
| Order | |
8+
9+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
10+
11+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* OpenAPI Petstore
3+
*
4+
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
5+
*
6+
* The version of the OpenAPI document: 1.0.0
7+
*
8+
* Generated by: https://openapi-generator.tech
9+
*/
10+
11+
use crate::models;
12+
use serde::{Deserialize, Serialize};
13+
14+
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
15+
#[serde(untagged)]
16+
pub enum DuplicateOneOf {
17+
Order(Box<models::Order>),
18+
}
19+
20+
impl Default for DuplicateOneOf {
21+
fn default() -> Self {
22+
Self::Order(Default::default())
23+
}
24+
}
25+
/// Order Status
26+
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
27+
pub enum Status {
28+
#[serde(rename = "placed")]
29+
Placed,
30+
#[serde(rename = "approved")]
31+
Approved,
32+
#[serde(rename = "delivered")]
33+
Delivered,
34+
}
35+
36+
impl Default for Status {
37+
fn default() -> Status {
38+
Self::Placed
39+
}
40+
}
41+

samples/client/petstore/rust/hyper0x/petstore/src/models/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ pub mod user;
4848
pub use self::user::User;
4949
pub mod vehicle;
5050
pub use self::vehicle::Vehicle;
51+
pub mod with_inner_one_of;
52+
pub use self::with_inner_one_of::WithInnerOneOf;
5153
use serde::{Deserialize, Deserializer, Serializer};
5254
use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs};
5355
use std::marker::PhantomData;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* OpenAPI Petstore
3+
*
4+
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
5+
*
6+
* The version of the OpenAPI document: 1.0.0
7+
*
8+
* Generated by: https://openapi-generator.tech
9+
*/
10+
11+
use crate::models;
12+
use serde::{Deserialize, Serialize};
13+
14+
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
15+
pub struct WithInnerOneOf {
16+
#[serde(rename = "foo", skip_serializing_if = "Option::is_none")]
17+
pub foo: Option<Box<models::Order>>,
18+
}
19+
20+
impl WithInnerOneOf {
21+
pub fn new() -> WithInnerOneOf {
22+
WithInnerOneOf {
23+
foo: None,
24+
}
25+
}
26+
}
27+

0 commit comments

Comments
 (0)