Skip to content

Commit

Permalink
Fix duplicated operationId with new rule in normalizer (#19872)
Browse files Browse the repository at this point in the history
* fix duplicated opeationId with new rule in normalizer

* update workflow

* update samples

* update samples

* update java samples
  • Loading branch information
wing328 authored Nov 11, 2024
1 parent e8c9722 commit 6bc8e0b
Show file tree
Hide file tree
Showing 54 changed files with 5,806 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/samples-java-client-jdk11.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ on:
- samples/client/others/java/jersey2-oneOf-duplicates/**
- samples/client/others/java/jersey2-oneOf-Mixed/**
- samples/client/others/java/resttemplate-list-schema-validation/**
- samples/client/petstore/java/okhttp-gson-3.1-duplicated-operationid/**
pull_request:
paths:
- 'samples/client/petstore/java/**'
Expand All @@ -33,6 +34,7 @@ on:
- samples/client/others/java/jersey2-oneOf-duplicates/**
- samples/client/others/java/jersey2-oneOf-Mixed/**
- samples/client/others/java/resttemplate-list-schema-validation/**
- samples/client/petstore/java/okhttp-gson-3.1-duplicated-operationid/**
jobs:
build:
name: Build Java Client JDK11
Expand Down Expand Up @@ -84,6 +86,7 @@ jobs:
- samples/client/others/java/jersey2-oneOf-duplicates/
- samples/client/others/java/jersey2-oneOf-Mixed/
- samples/client/others/java/resttemplate-list-schema-validation/
- samples/client/petstore/java/okhttp-gson-3.1-duplicated-operationid/
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
Expand Down
12 changes: 12 additions & 0 deletions bin/configs/java-okhttp-gson-3.1-duplicated-operationid.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
generatorName: java
outputDir: samples/client/petstore/java/okhttp-gson-3.1-duplicated-operationid
library: okhttp-gson
inputSpec: modules/openapi-generator/src/test/resources/3_1/java/duplicated_operationid.yaml
templateDir: modules/openapi-generator/src/main/resources/Java
validateSpec: false
additionalProperties:
artifactId: petstore-okhttp-gson-31-do
hideGenerationTimestamp: "true"
disallowAdditionalPropertiesIfNotPresent: false
openapiNormalizer:
FIX_DUPLICATED_OPERATIONID: true
3 changes: 3 additions & 0 deletions bin/configs/java-okhttp-gson-3.1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ outputDir: samples/client/petstore/java/okhttp-gson-3.1
library: okhttp-gson
inputSpec: modules/openapi-generator/src/test/resources/3_1/java/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/Java
validateSpec: false
nameMappings:
_type: underscoreType
type_: typeWithUnderscore
Expand All @@ -14,3 +15,5 @@ additionalProperties:
hideGenerationTimestamp: "true"
useOneOfDiscriminatorLookup: "true"
disallowAdditionalPropertiesIfNotPresent: false
openapiNormalizer:
FIX_DUPLICATED_OPERATIONID: true
7 changes: 7 additions & 0 deletions docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -614,3 +614,10 @@ Example:
```
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"
```
- `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
Example:
```
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
```
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
import java.util.*;
import java.util.stream.Collectors;

import static org.openapitools.codegen.utils.StringUtils.getUniqueString;
import static org.openapitools.codegen.utils.StringUtils.underscore;

public class OpenAPINormalizer {
private OpenAPI openAPI;
private Map<String, String> inputRules = new HashMap<>();
Expand Down Expand Up @@ -88,6 +91,12 @@ public class OpenAPINormalizer {
final String SET_TAGS_TO_OPERATIONID = "SET_TAGS_TO_OPERATIONID";
String setTagsToOperationId;

// when set to true, tags in all operations will be set to operationId or "default" if operationId
// is empty
final String FIX_DUPLICATED_OPERATIONID = "FIX_DUPLICATED_OPERATIONID";
String fixDuplicatedOperationId;
HashSet<String> operationIdSet = new HashSet<>();

// when set to true, auto fix integer with maximum value 4294967295 (2^32-1) or long with 18446744073709551615 (2^64-1)
// by adding x-unsigned to the schema
final String ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE = "ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE";
Expand Down Expand Up @@ -149,6 +158,7 @@ public OpenAPINormalizer(OpenAPI openAPI, Map<String, String> inputRules) {
ruleNames.add(KEEP_ONLY_FIRST_TAG_IN_OPERATION);
ruleNames.add(SET_TAGS_FOR_ALL_OPERATIONS);
ruleNames.add(SET_TAGS_TO_OPERATIONID);
ruleNames.add(FIX_DUPLICATED_OPERATIONID);
ruleNames.add(ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE);
ruleNames.add(REFACTOR_ALLOF_WITH_PROPERTIES_ONLY);
ruleNames.add(NORMALIZE_31SPEC);
Expand Down Expand Up @@ -361,6 +371,8 @@ private void normalizeOperation(Operation operation) {
processSetTagsForAllOperations(operation);

processSetTagsToOperationId(operation);

processFixDuplicatedOperationId(operation);
}

/**
Expand Down Expand Up @@ -939,6 +951,26 @@ private void processSetTagsToOperationId(Operation operation) {
}
}

private void processFixDuplicatedOperationId(Operation operation) {
if (!getRule(FIX_DUPLICATED_OPERATIONID)) {
return;
}

// skip null as default codegen will automatically generate one using path, http verb, etc
if (operation.getOperationId() == null) {
return;
}

String uniqueName = getUniqueString(operationIdSet, operation.getOperationId());

if (!uniqueName.equals(operation.getOperationId())) {
LOGGER.info("operationId {} renamed to {} to ensure uniqueness (enabled by openapi normalizer rule `FIX_DUPLICATED_OPERATIONID`)", operation.getOperationId(), uniqueName);
operation.setOperationId(uniqueName);
}
}



/**
* If the schema contains anyOf/oneOf and properties, remove oneOf/anyOf as these serve as rules to
* ensure inter-dependency between properties. It's a workaround as such validation is not supported at the moment.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,32 @@ public static String escape(final String name, final Map<String, String> replace
throw new RuntimeException("Word '" + name + "' could not be escaped.");
});
}

/**
* Return a unique string based on a set of processed strings.
*
* @param processedStrings a set of strings that have been processed
* @param input input to be checked for uniqueness
* @return a unique string
*/
public static String getUniqueString(Set<String> processedStrings, String input) {
if (input == null) {
return null;
}

String uniqueName = input;
// check for input uniqueness
int counter = 0;

if (processedStrings.contains(uniqueName)) {
// look for next unique next, e.g. getName_7
while (processedStrings.contains(uniqueName)) {
uniqueName = uniqueName + "_" + counter;
counter++;
}
}

processedStrings.add(uniqueName);
return uniqueName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
openapi: 3.1.0
servers:
- url: 'http://petstore.swagger.io/v2'
info:
description: >-
This is a sample server Petstore server. For this sample, you can use the api key
`special-key` to test the authorization filters.
version: 1.0.0
title: OpenAPI Petstore
license:
name: Apache-2.0
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
tags:
- name: pet
description: Everything about your Pets
- name: store
description: Access to Petstore orders
- name: user
description: Operations about user
paths:
'/pet/{petId}':
get:
tags:
- pet
summary: Find pet by ID
description: Returns a single pet
operationId: getPetById
parameters:
- name: petId
in: path
description: ID of pet to return
required: true
schema:
type: integer
format: int64
responses:
'200':
description: successful operation
content:
application/xml:
schema:
$ref: '#/components/schemas/myObject'
application/json:
schema:
$ref: '#/components/schemas/myObject'
'400':
description: Invalid ID supplied
'404':
description: Pet not found
security:
- api_key: []
"/fake/duplicated/operationId":
get:
tags:
- fake
operationId: getPetById
responses:
'200':
description: ''
content:
application/json:
schema:
anyOf:
- type: 'null'
- "$ref": "#/components/schemas/myObject"
externalDocs:
description: Find out more about Swagger
url: 'http://swagger.io'
components:
securitySchemes:
petstore_auth:
type: oauth2
flows:
implicit:
authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog'
scopes:
'write:pets': modify pets in your account
'read:pets': read your pets
api_key:
type: apiKey
name: api_key
in: header
schemas:
myObject:
type: object
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
#
# This file is auto-generated by OpenAPI Generator (https://openapi-generator.tech)

name: Java CI with Maven

on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]

jobs:
build:
name: Build OpenAPI Petstore
runs-on: ubuntu-latest
strategy:
matrix:
java: [ 17, 21 ]
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn -B package --no-transfer-progress --file pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# exclude jar for gradle wrapper
!gradle/wrapper/*.jar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

# build files
**/target
target
.gradle
build
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.github/workflows/maven.yml
.gitignore
.travis.yml
README.md
api/openapi.yaml
build.gradle
build.sbt
docs/FakeApi.md
docs/PetApi.md
git_push.sh
gradle.properties
gradle/wrapper/gradle-wrapper.jar
gradle/wrapper/gradle-wrapper.properties
gradlew
gradlew.bat
pom.xml
settings.gradle
src/main/AndroidManifest.xml
src/main/java/org/openapitools/client/ApiCallback.java
src/main/java/org/openapitools/client/ApiClient.java
src/main/java/org/openapitools/client/ApiException.java
src/main/java/org/openapitools/client/ApiResponse.java
src/main/java/org/openapitools/client/Configuration.java
src/main/java/org/openapitools/client/GzipRequestInterceptor.java
src/main/java/org/openapitools/client/JSON.java
src/main/java/org/openapitools/client/Pair.java
src/main/java/org/openapitools/client/ProgressRequestBody.java
src/main/java/org/openapitools/client/ProgressResponseBody.java
src/main/java/org/openapitools/client/ServerConfiguration.java
src/main/java/org/openapitools/client/ServerVariable.java
src/main/java/org/openapitools/client/StringUtil.java
src/main/java/org/openapitools/client/api/FakeApi.java
src/main/java/org/openapitools/client/api/PetApi.java
src/main/java/org/openapitools/client/auth/ApiKeyAuth.java
src/main/java/org/openapitools/client/auth/Authentication.java
src/main/java/org/openapitools/client/auth/HttpBasicAuth.java
src/main/java/org/openapitools/client/auth/HttpBearerAuth.java
src/main/java/org/openapitools/client/auth/OAuth.java
src/main/java/org/openapitools/client/auth/OAuthFlow.java
src/main/java/org/openapitools/client/auth/OAuthOkHttpClient.java
src/main/java/org/openapitools/client/auth/RetryingOAuth.java
src/main/java/org/openapitools/client/model/AbstractOpenApiSchema.java
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7.10.0-SNAPSHOT
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# Generated by OpenAPI Generator: https://openapi-generator.tech
#
# Ref: https://docs.travis-ci.com/user/languages/java/
#
language: java
jdk:
- openjdk12
- openjdk11
- openjdk10
- openjdk9
- openjdk8
before_install:
# ensure gradlew has proper permission
- chmod a+x ./gradlew
script:
# test using maven
#- mvn test
# test using gradle
- gradle test
# test using sbt
# - sbt test
Loading

0 comments on commit 6bc8e0b

Please sign in to comment.