Skip to content

Commit 6bc8e0b

Browse files
authored
Fix duplicated operationId with new rule in normalizer (#19872)
* fix duplicated opeationId with new rule in normalizer * update workflow * update samples * update samples * update java samples
1 parent e8c9722 commit 6bc8e0b

Some content is hidden

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

54 files changed

+5806
-0
lines changed

.github/workflows/samples-java-client-jdk11.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ on:
1717
- samples/client/others/java/jersey2-oneOf-duplicates/**
1818
- samples/client/others/java/jersey2-oneOf-Mixed/**
1919
- samples/client/others/java/resttemplate-list-schema-validation/**
20+
- samples/client/petstore/java/okhttp-gson-3.1-duplicated-operationid/**
2021
pull_request:
2122
paths:
2223
- 'samples/client/petstore/java/**'
@@ -33,6 +34,7 @@ on:
3334
- samples/client/others/java/jersey2-oneOf-duplicates/**
3435
- samples/client/others/java/jersey2-oneOf-Mixed/**
3536
- samples/client/others/java/resttemplate-list-schema-validation/**
37+
- samples/client/petstore/java/okhttp-gson-3.1-duplicated-operationid/**
3638
jobs:
3739
build:
3840
name: Build Java Client JDK11
@@ -84,6 +86,7 @@ jobs:
8486
- samples/client/others/java/jersey2-oneOf-duplicates/
8587
- samples/client/others/java/jersey2-oneOf-Mixed/
8688
- samples/client/others/java/resttemplate-list-schema-validation/
89+
- samples/client/petstore/java/okhttp-gson-3.1-duplicated-operationid/
8790
steps:
8891
- uses: actions/checkout@v4
8992
- uses: actions/setup-java@v4
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
generatorName: java
2+
outputDir: samples/client/petstore/java/okhttp-gson-3.1-duplicated-operationid
3+
library: okhttp-gson
4+
inputSpec: modules/openapi-generator/src/test/resources/3_1/java/duplicated_operationid.yaml
5+
templateDir: modules/openapi-generator/src/main/resources/Java
6+
validateSpec: false
7+
additionalProperties:
8+
artifactId: petstore-okhttp-gson-31-do
9+
hideGenerationTimestamp: "true"
10+
disallowAdditionalPropertiesIfNotPresent: false
11+
openapiNormalizer:
12+
FIX_DUPLICATED_OPERATIONID: true

bin/configs/java-okhttp-gson-3.1.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ outputDir: samples/client/petstore/java/okhttp-gson-3.1
33
library: okhttp-gson
44
inputSpec: modules/openapi-generator/src/test/resources/3_1/java/petstore.yaml
55
templateDir: modules/openapi-generator/src/main/resources/Java
6+
validateSpec: false
67
nameMappings:
78
_type: underscoreType
89
type_: typeWithUnderscore
@@ -14,3 +15,5 @@ additionalProperties:
1415
hideGenerationTimestamp: "true"
1516
useOneOfDiscriminatorLookup: "true"
1617
disallowAdditionalPropertiesIfNotPresent: false
18+
openapiNormalizer:
19+
FIX_DUPLICATED_OPERATIONID: true

docs/customization.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,3 +614,10 @@ Example:
614614
```
615615
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -o /tmp/java-okhttp/ --openapi-normalizer SET_PRIMITIVE_TYPES_TO_NULLABLE="integer|number"
616616
```
617+
618+
- `FIX_DUPLICATED_OPERATIONID`: When set to true, an integer suffix will be added to duplicated operationId(s), e.g. getName => getName_0, getName_1, etc
619+
620+
Example:
621+
```
622+
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_1/java/petstore.yaml -o /tmp/java-okhttp/ --openapi-normalizer FIX_DUPLICATED_OPERATIONID=true
623+
```

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
import java.util.*;
3535
import java.util.stream.Collectors;
3636

37+
import static org.openapitools.codegen.utils.StringUtils.getUniqueString;
38+
import static org.openapitools.codegen.utils.StringUtils.underscore;
39+
3740
public class OpenAPINormalizer {
3841
private OpenAPI openAPI;
3942
private Map<String, String> inputRules = new HashMap<>();
@@ -88,6 +91,12 @@ public class OpenAPINormalizer {
8891
final String SET_TAGS_TO_OPERATIONID = "SET_TAGS_TO_OPERATIONID";
8992
String setTagsToOperationId;
9093

94+
// when set to true, tags in all operations will be set to operationId or "default" if operationId
95+
// is empty
96+
final String FIX_DUPLICATED_OPERATIONID = "FIX_DUPLICATED_OPERATIONID";
97+
String fixDuplicatedOperationId;
98+
HashSet<String> operationIdSet = new HashSet<>();
99+
91100
// when set to true, auto fix integer with maximum value 4294967295 (2^32-1) or long with 18446744073709551615 (2^64-1)
92101
// by adding x-unsigned to the schema
93102
final String ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE = "ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE";
@@ -149,6 +158,7 @@ public OpenAPINormalizer(OpenAPI openAPI, Map<String, String> inputRules) {
149158
ruleNames.add(KEEP_ONLY_FIRST_TAG_IN_OPERATION);
150159
ruleNames.add(SET_TAGS_FOR_ALL_OPERATIONS);
151160
ruleNames.add(SET_TAGS_TO_OPERATIONID);
161+
ruleNames.add(FIX_DUPLICATED_OPERATIONID);
152162
ruleNames.add(ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE);
153163
ruleNames.add(REFACTOR_ALLOF_WITH_PROPERTIES_ONLY);
154164
ruleNames.add(NORMALIZE_31SPEC);
@@ -361,6 +371,8 @@ private void normalizeOperation(Operation operation) {
361371
processSetTagsForAllOperations(operation);
362372

363373
processSetTagsToOperationId(operation);
374+
375+
processFixDuplicatedOperationId(operation);
364376
}
365377

366378
/**
@@ -939,6 +951,26 @@ private void processSetTagsToOperationId(Operation operation) {
939951
}
940952
}
941953

954+
private void processFixDuplicatedOperationId(Operation operation) {
955+
if (!getRule(FIX_DUPLICATED_OPERATIONID)) {
956+
return;
957+
}
958+
959+
// skip null as default codegen will automatically generate one using path, http verb, etc
960+
if (operation.getOperationId() == null) {
961+
return;
962+
}
963+
964+
String uniqueName = getUniqueString(operationIdSet, operation.getOperationId());
965+
966+
if (!uniqueName.equals(operation.getOperationId())) {
967+
LOGGER.info("operationId {} renamed to {} to ensure uniqueness (enabled by openapi normalizer rule `FIX_DUPLICATED_OPERATIONID`)", operation.getOperationId(), uniqueName);
968+
operation.setOperationId(uniqueName);
969+
}
970+
}
971+
972+
973+
942974
/**
943975
* If the schema contains anyOf/oneOf and properties, remove oneOf/anyOf as these serve as rules to
944976
* ensure inter-dependency between properties. It's a workaround as such validation is not supported at the moment.

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,4 +283,32 @@ public static String escape(final String name, final Map<String, String> replace
283283
throw new RuntimeException("Word '" + name + "' could not be escaped.");
284284
});
285285
}
286+
287+
/**
288+
* Return a unique string based on a set of processed strings.
289+
*
290+
* @param processedStrings a set of strings that have been processed
291+
* @param input input to be checked for uniqueness
292+
* @return a unique string
293+
*/
294+
public static String getUniqueString(Set<String> processedStrings, String input) {
295+
if (input == null) {
296+
return null;
297+
}
298+
299+
String uniqueName = input;
300+
// check for input uniqueness
301+
int counter = 0;
302+
303+
if (processedStrings.contains(uniqueName)) {
304+
// look for next unique next, e.g. getName_7
305+
while (processedStrings.contains(uniqueName)) {
306+
uniqueName = uniqueName + "_" + counter;
307+
counter++;
308+
}
309+
}
310+
311+
processedStrings.add(uniqueName);
312+
return uniqueName;
313+
}
286314
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
openapi: 3.1.0
2+
servers:
3+
- url: 'http://petstore.swagger.io/v2'
4+
info:
5+
description: >-
6+
This is a sample server Petstore server. For this sample, you can use the api key
7+
`special-key` to test the authorization filters.
8+
version: 1.0.0
9+
title: OpenAPI Petstore
10+
license:
11+
name: Apache-2.0
12+
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
13+
tags:
14+
- name: pet
15+
description: Everything about your Pets
16+
- name: store
17+
description: Access to Petstore orders
18+
- name: user
19+
description: Operations about user
20+
paths:
21+
'/pet/{petId}':
22+
get:
23+
tags:
24+
- pet
25+
summary: Find pet by ID
26+
description: Returns a single pet
27+
operationId: getPetById
28+
parameters:
29+
- name: petId
30+
in: path
31+
description: ID of pet to return
32+
required: true
33+
schema:
34+
type: integer
35+
format: int64
36+
responses:
37+
'200':
38+
description: successful operation
39+
content:
40+
application/xml:
41+
schema:
42+
$ref: '#/components/schemas/myObject'
43+
application/json:
44+
schema:
45+
$ref: '#/components/schemas/myObject'
46+
'400':
47+
description: Invalid ID supplied
48+
'404':
49+
description: Pet not found
50+
security:
51+
- api_key: []
52+
"/fake/duplicated/operationId":
53+
get:
54+
tags:
55+
- fake
56+
operationId: getPetById
57+
responses:
58+
'200':
59+
description: ''
60+
content:
61+
application/json:
62+
schema:
63+
anyOf:
64+
- type: 'null'
65+
- "$ref": "#/components/schemas/myObject"
66+
externalDocs:
67+
description: Find out more about Swagger
68+
url: 'http://swagger.io'
69+
components:
70+
securitySchemes:
71+
petstore_auth:
72+
type: oauth2
73+
flows:
74+
implicit:
75+
authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog'
76+
scopes:
77+
'write:pets': modify pets in your account
78+
'read:pets': read your pets
79+
api_key:
80+
type: apiKey
81+
name: api_key
82+
in: header
83+
schemas:
84+
myObject:
85+
type: object
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3+
#
4+
# This file is auto-generated by OpenAPI Generator (https://openapi-generator.tech)
5+
6+
name: Java CI with Maven
7+
8+
on:
9+
push:
10+
branches: [ main, master ]
11+
pull_request:
12+
branches: [ main, master ]
13+
14+
jobs:
15+
build:
16+
name: Build OpenAPI Petstore
17+
runs-on: ubuntu-latest
18+
strategy:
19+
matrix:
20+
java: [ 17, 21 ]
21+
steps:
22+
- uses: actions/checkout@v4
23+
- name: Set up JDK
24+
uses: actions/setup-java@v4
25+
with:
26+
java-version: ${{ matrix.java }}
27+
distribution: 'temurin'
28+
cache: maven
29+
- name: Build with Maven
30+
run: mvn -B package --no-transfer-progress --file pom.xml
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
*.class
2+
3+
# Mobile Tools for Java (J2ME)
4+
.mtj.tmp/
5+
6+
# Package Files #
7+
*.jar
8+
*.war
9+
*.ear
10+
11+
# exclude jar for gradle wrapper
12+
!gradle/wrapper/*.jar
13+
14+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
15+
hs_err_pid*
16+
17+
# build files
18+
**/target
19+
target
20+
.gradle
21+
build
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# OpenAPI Generator Ignore
2+
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
3+
4+
# Use this file to prevent files from being overwritten by the generator.
5+
# The patterns follow closely to .gitignore or .dockerignore.
6+
7+
# As an example, the C# client generator defines ApiClient.cs.
8+
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
9+
#ApiClient.cs
10+
11+
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
12+
#foo/*/qux
13+
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
14+
15+
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
16+
#foo/**/qux
17+
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
18+
19+
# You can also negate patterns with an exclamation (!).
20+
# For example, you can ignore all files in a docs folder with the file extension .md:
21+
#docs/*.md
22+
# Then explicitly reverse the ignore rule for a single file:
23+
#!docs/README.md

0 commit comments

Comments
 (0)