Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new openapi-normalizer rule: ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE #14891

Merged
merged 1 commit into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,3 +505,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/enableKeepOnlyFirstTagInOperation_test.yaml -o /tmp/java-okhttp/ --openapi-normalizer SET_TAGS_FOR_ALL_OPERATIONS=true
```

- `ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE`: 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

Example:
```
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/addUnsignedToIntegerWithInvalidMaxValue_test.yaml -o /tmp/java-okhttp/ --openapi-normalizer ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE=true
```
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ public class OpenAPINormalizer {
final String SET_TAGS_FOR_ALL_OPERATIONS = "SET_TAGS_FOR_ALL_OPERATIONS";
String setTagsForAllOperations;

// 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";
boolean addUnsignedToIntegerWithInvalidMaxValue;

// ============= end of rules =============

/**
Expand Down Expand Up @@ -132,6 +137,9 @@ public void parseRules(Map<String, String> rules) {
setTagsForAllOperations = rules.get(SET_TAGS_FOR_ALL_OPERATIONS);
}

if (enableAll || "true".equalsIgnoreCase(rules.get(ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE))) {
addUnsignedToIntegerWithInvalidMaxValue = true;
}
}

/**
Expand Down Expand Up @@ -367,6 +375,8 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
normalizeProperties(schema.getProperties(), visitedSchemas);
} else if (schema instanceof BooleanSchema) {
normalizeBooleanSchema(schema, visitedSchemas);
} else if (schema instanceof IntegerSchema) {
normalizeIntegerSchema(schema, visitedSchemas);
} else if (schema instanceof Schema) {
normalizeSchemaWithOnlyProperties(schema, visitedSchemas);
} else {
Expand All @@ -380,6 +390,10 @@ private void normalizeBooleanSchema(Schema schema, Set<Schema> visitedSchemas) {
processSimplifyBooleanEnum(schema);
}

private void normalizeIntegerSchema(Schema schema, Set<Schema> visitedSchemas) {
processAddUnsignedToIntegerWithInvalidMaxValue(schema);
}

private void normalizeSchemaWithOnlyProperties(Schema schema, Set<Schema> visitedSchemas) {
// normalize non-composed schema (e.g. schema with only properties)
}
Expand Down Expand Up @@ -675,5 +689,36 @@ private void processSimplifyBooleanEnum(Schema schema) {
}
}

/**
* If the schema is integer and the max value is invalid (out of bound)
* then add x-unsigned to use unsigned integer/long instead.
*
* @param schema Schema
* @return Schema
*/
private void processAddUnsignedToIntegerWithInvalidMaxValue(Schema schema) {
if (!addUnsignedToIntegerWithInvalidMaxValue && !enableAll) {
return;
}

LOGGER.info("processAddUnsignedToIntegerWithInvalidMaxValue");
if (schema instanceof IntegerSchema) {
if (ModelUtils.isLongSchema(schema)) {
if ("18446744073709551615".equals(String.valueOf(schema.getMaximum())) &&
"0".equals(String.valueOf(schema.getMinimum()))) {
schema.addExtension("x-unsigned", true);
LOGGER.info("fix long");
}
} else {
if ("4294967295".equals(String.valueOf(schema.getMaximum())) &&
"0".equals(String.valueOf(schema.getMinimum()))) {
schema.addExtension("x-unsigned", true);
LOGGER.info("fix integer");

}
}
}
}

// ===================== end of rules =====================
}
Original file line number Diff line number Diff line change
Expand Up @@ -4471,4 +4471,30 @@ public void testOpenAPINormalizerSetTagsInAllOperations() {
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getTags().get(0), "core");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getTags().get(0), "core");
}

@Test
public void testAddUnsignedToIntegerWithInvalidMaxValue() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/addUnsignedToIntegerWithInvalidMaxValue_test.yaml");

Schema person = openAPI.getComponents().getSchemas().get("Person");
assertNull(((Schema)person.getProperties().get("integer")).getExtensions());
assertNull(((Schema)person.getProperties().get("int32")).getExtensions());
assertNull(((Schema)person.getProperties().get("int64")).getExtensions());
assertNull(((Schema)person.getProperties().get("integer_max")).getExtensions());
assertNull(((Schema)person.getProperties().get("int32_max")).getExtensions());
assertNull(((Schema)person.getProperties().get("int64_max")).getExtensions());

Map<String, String> options = new HashMap<>();
options.put("ADD_UNSIGNED_TO_INTEGER_WITH_INVALID_MAX_VALUE", "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();

Schema person2 = openAPI.getComponents().getSchemas().get("Person");
assertNull(((Schema)person2.getProperties().get("integer")).getExtensions());
assertNull(((Schema)person2.getProperties().get("int32")).getExtensions());
assertNull(((Schema)person2.getProperties().get("int64")).getExtensions());
assertTrue((Boolean)((Schema)person2.getProperties().get("integer_max")).getExtensions().get("x-unsigned"));
assertTrue((Boolean)((Schema)person2.getProperties().get("int32_max")).getExtensions().get("x-unsigned"));
assertTrue((Boolean)((Schema)person2.getProperties().get("int64_max")).getExtensions().get("x-unsigned"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
openapi: 3.0.1
info:
version: 1.0.0
title: Example
license:
name: MIT
servers:
- url: http://api.example.xyz/v1
paths:
/person/display/{personId}:
get:
tags:
- person
- basic
parameters:
- name: personId
in: path
required: true
description: The id of the person to retrieve
schema:
type: string
operationId: list
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/Person"
delete:
tags:
- person
parameters:
- name: personId
in: path
required: true
description: The id of the person to retrieve
schema:
type: string
operationId: delete
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/Person"
components:
schemas:
Person:
description: person
type: object
properties:
integer:
type: integer
int32:
type: integer
format: int32
int64:
type: integer
format: int64
integer_max:
type: integer
minimum: 0
maximum: 4294967295 #(2^32)-1
int32_max:
type: integer
format: int32
minimum: 0
maximum: 4294967295 #(2^32)-1
int64_max:
type: integer
format: int64
minimum: 0
maximum: 18446744073709551615 #(2^64)-1