Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
* If a query parameter should be serialized as json
*/
public boolean queryIsJsonMimeType;
/**
* True when a header parameter uses a JSON media type in Parameter.content.
*/
public boolean headerIsJsonMimeType;
/**
* datatype is the generic inner parameter of a std::optional for C++, or Optional (Java)
*/
Expand Down Expand Up @@ -270,6 +274,7 @@ public CodegenParameter copy() {
output.isArray = this.isArray;
output.isMap = this.isMap;
output.queryIsJsonMimeType = this.queryIsJsonMimeType;
output.headerIsJsonMimeType = this.headerIsJsonMimeType;
output.isOptional = this.isOptional;
output.isExplode = this.isExplode;
output.style = this.style;
Expand All @@ -294,15 +299,15 @@ public int hashCode() {
isFormStyle, isSpaceDelimited, isPipeDelimited,
jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal,
isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isPassword,
isFreeFormObject, isAnyType, isArray, isMap, queryIsJsonMimeType, isOptional, isFile, isEnum, isEnumRef, _enum, allowableValues,
items, mostInnerItems, additionalProperties, vars, requiredVars, vendorExtensions, hasValidation,
getMaxProperties(), getMinProperties(), isNullable, isDeprecated, required, getMaximum(),
getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(), getMaxLength(), getMinLength(),
getPattern(), getMaxItems(), getMinItems(), getUniqueItems(), contentType, multipleOf, isNull, isVoid,
additionalPropertiesIsAnyType, hasVars, hasRequired, isShort, isUnboundedInteger,
hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes, schema, content,
requiredVarsMap, ref, uniqueItemsBoolean, schemaIsFromAdditionalProperties,
nameInPascalCase, nameInCamelCase, nameInLowerCase, nameInSnakeCase);
isFreeFormObject, isAnyType, isArray, isMap, queryIsJsonMimeType, headerIsJsonMimeType, isOptional,
isFile, isEnum, isEnumRef, _enum, allowableValues, items, mostInnerItems, additionalProperties, vars,
requiredVars, vendorExtensions, hasValidation, getMaxProperties(), getMinProperties(), isNullable,
isDeprecated, required, getMaximum(), getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(),
getMaxLength(), getMinLength(), getPattern(), getMaxItems(), getMinItems(), getUniqueItems(),
contentType, multipleOf, isNull, isVoid, additionalPropertiesIsAnyType, hasVars, hasRequired, isShort,
isUnboundedInteger, hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes, schema,
content, requiredVarsMap, ref, uniqueItemsBoolean, schemaIsFromAdditionalProperties, nameInPascalCase,
nameInCamelCase, nameInLowerCase, nameInSnakeCase);
}

@Override
Expand Down Expand Up @@ -345,6 +350,7 @@ public boolean equals(Object o) {
isArray == that.isArray &&
isMap == that.isMap &&
queryIsJsonMimeType == that.queryIsJsonMimeType &&
headerIsJsonMimeType == that.headerIsJsonMimeType &&
isOptional == that.isOptional &&
isFile == that.isFile &&
isEnum == that.isEnum &&
Expand Down Expand Up @@ -486,6 +492,7 @@ public String toString() {
sb.append(", isArray=").append(isArray);
sb.append(", isMap=").append(isMap);
sb.append(", queryIsJsonMimeType=").append(queryIsJsonMimeType);
sb.append(", headerIsJsonMimeType=").append(headerIsJsonMimeType);
sb.append(", isOptional=").append(isOptional);
sb.append(", isFile=").append(isFile);
sb.append(", isEnum=").append(isEnum);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5722,6 +5722,7 @@ public CodegenParameter fromParameter(Parameter parameter, Set<String> imports)
codegenParameter.isPathParam = true;
} else if (parameter instanceof HeaderParameter || "header".equalsIgnoreCase(parameter.getIn())) {
codegenParameter.isHeaderParam = true;
codegenParameter.headerIsJsonMimeType = isJsonMimeType(codegenParameter.contentType);
} else if (parameter instanceof CookieParameter || "cookie".equalsIgnoreCase(parameter.getIn())) {
codegenParameter.isCookieParam = true;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,43 @@ public class ApiClient {
}
}

/**
* Format the given parameter object as an ASCII-safe JSON string.
*
* @param param Parameter
* @return JSON representation of the parameter
*/
public String parameterToJsonString(Object param) {
String json = JSON.serialize(param);
int firstUnsafe = -1;
for (int i = 0; i < json.length(); i++) {
if (json.charAt(i) >= 0x7f) {
firstUnsafe = i;
break;
}
}
if (firstUnsafe == -1) {
return json;
}

StringBuilder escaped = new StringBuilder(json.length());
escaped.append(json, 0, firstUnsafe);
for (int i = firstUnsafe; i < json.length(); i++) {
char c = json.charAt(i);
if (c >= 0x7f) {
escaped.append("\\u");
escaped.append(Character.forDigit((c >> 12) & 0xf, 16));
escaped.append(Character.forDigit((c >> 8) & 0xf, 16));
escaped.append(Character.forDigit((c >> 4) & 0xf, 16));
escaped.append(Character.forDigit(c & 0xf, 16));
} else {
escaped.append(c);
}
}

return escaped.toString();
}

/**
* Formats the specified query parameter to a list containing a single {@code Pair} object.
*
Expand Down Expand Up @@ -1954,7 +1991,11 @@ public class ApiClient {
}
break;
case "header":
headerParams.put(param.getName(), parameterToString(value));
if (param.getContent() != null && param.getContent().containsKey("application/json")) {
headerParams.put(param.getName(), parameterToJsonString(value));
} else {
headerParams.put(param.getName(), parameterToString(value));
}
break;
case "cookie":
cookieParams.put(param.getName(), parameterToString(value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,12 @@ public class {{classname}} {
{{#headerParams}}

if ({{paramName}} != null) {
{{#headerIsJsonMimeType}}
localVarHeaderParams.put("{{baseName}}", localVarApiClient.parameterToJsonString({{paramName}}));
{{/headerIsJsonMimeType}}
{{^headerIsJsonMimeType}}
localVarHeaderParams.put("{{baseName}}", localVarApiClient.parameterToString({{paramName}}));
{{/headerIsJsonMimeType}}
}

{{/headerParams}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5362,6 +5362,29 @@ public void testQueryIsJsonMimeType() {
assertTrue(codegenOperation.queryParams.stream().allMatch(p -> p.queryIsJsonMimeType));
}

@Test
public void testHeaderIsJsonMimeType() {
DefaultCodegen codegen = new DefaultCodegen();
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_1/java/json-header-content.yaml");
codegen.setOpenAPI(openAPI);
String path = "/test";
CodegenOperation codegenOperation = codegen.fromOperation(path, "POST", openAPI.getPaths().get(path).getPost(), null);

assertThat(codegenOperation.headerParams).hasSize(2);

CodegenParameter jsonHeader = codegenOperation.headerParams.stream()
.filter(param -> "X-Json-Arg".equals(param.baseName))
.findFirst()
.orElseThrow();
assertThat(jsonHeader.headerIsJsonMimeType).isTrue();

CodegenParameter plainHeader = codegenOperation.headerParams.stream()
.filter(param -> "X-Plain-Arg".equals(param.baseName))
.findFirst()
.orElseThrow();
assertThat(plainHeader.headerIsJsonMimeType).isFalse();
}

@Test
public void testDefaultOauthIsNotNull() {
final DefaultCodegen codegen = new DefaultCodegen();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,59 @@ public void testJersey3NullableNullDefaultRemainsUndefined() {
.doesNotContain("JsonNullable.<List<String>>of(null)");
}

@Test
public void testJsonContentHeaderUsesJsonSerialization() {
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
final Path output = newTempFolder();
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName(JAVA_GENERATOR)
.setLibrary(JavaClientCodegen.OKHTTP_GSON)
.setInputSpec("src/test/resources/3_1/java/json-header-content.yaml")
.setOutputDir(output.toString().replace("\\", "/"));

List<File> files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate();

validateJavaSourceFiles(files);

assertThat(output.resolve("src/main/java/org/openapitools/client/ApiClient.java"))
.content()
.contains("public String parameterToJsonString(Object param)");

assertThat(output.resolve("src/main/java/org/openapitools/client/api/DefaultApi.java"))
.content()
.contains(
"localVarHeaderParams.put(\"X-Json-Arg\", localVarApiClient.parameterToJsonString(xJsonArg));"
)
.doesNotContain(
"localVarHeaderParams.put(\"X-Json-Arg\", localVarApiClient.parameterToString(xJsonArg));"
);
}

@Test
public void testDynamicJsonContentHeaderUsesJsonSerialization() {
final Path output = newTempFolder();
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName(JAVA_GENERATOR)
.setLibrary(JavaClientCodegen.OKHTTP_GSON)
.setInputSpec("src/test/resources/3_1/java/json-header-content.yaml")
.addAdditionalProperty("dynamicOperations", true)
.setOutputDir(output.toString().replace("\\", "/"));

List<File> files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate();

validateJavaSourceFiles(files);

assertThat(output.resolve("src/main/java/org/openapitools/client/ApiClient.java"))
.content()
.contains("if (param.getContent() != null && param.getContent().containsKey(\"application/json\")) {")
.contains("headerParams.put(param.getName(), parameterToJsonString(value));")
.contains("headerParams.put(param.getName(), parameterToString(value));");

assertThat(output.resolve("src/main/java/org/openapitools/client/api/DefaultApi.java"))
.content()
.contains("paramMap.put(\"X-Json-Arg\", xJsonArg);")
.contains("paramMap.put(\"X-Plain-Arg\", xPlainArg);");
}

@Test
public void testGeneratePingSomeObj() {
final Path output = newTempFolder();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
openapi: 3.1.0

info:
title: JSON header repro
version: 1.0.0

paths:
/test:
post:
operationId: testJsonHeader
parameters:
- name: X-Json-Arg
in: header
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/HeaderArg'
- name: X-Plain-Arg
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
in: header
schema:
type: string
responses:
'204':
description: OK

components:
schemas:
HeaderArg:
type: object
required:
- path
properties:
path:
type: string

Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,43 @@ public String parameterToString(Object param) {
}
}

/**
* Format the given parameter object as an ASCII-safe JSON string.
*
* @param param Parameter
* @return JSON representation of the parameter
*/
public String parameterToJsonString(Object param) {
String json = JSON.serialize(param);
int firstUnsafe = -1;
for (int i = 0; i < json.length(); i++) {
if (json.charAt(i) >= 0x7f) {
firstUnsafe = i;
break;
}
}
if (firstUnsafe == -1) {
return json;
}

StringBuilder escaped = new StringBuilder(json.length());
escaped.append(json, 0, firstUnsafe);
for (int i = firstUnsafe; i < json.length(); i++) {
char c = json.charAt(i);
if (c >= 0x7f) {
escaped.append("\\u");
escaped.append(Character.forDigit((c >> 12) & 0xf, 16));
escaped.append(Character.forDigit((c >> 8) & 0xf, 16));
escaped.append(Character.forDigit((c >> 4) & 0xf, 16));
escaped.append(Character.forDigit(c & 0xf, 16));
} else {
escaped.append(c);
}
}

return escaped.toString();
}

/**
* Formats the specified query parameter to a list containing a single {@code Pair} object.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,43 @@ public String parameterToString(Object param) {
}
}

/**
* Format the given parameter object as an ASCII-safe JSON string.
*
* @param param Parameter
* @return JSON representation of the parameter
*/
public String parameterToJsonString(Object param) {
String json = JSON.serialize(param);
int firstUnsafe = -1;
for (int i = 0; i < json.length(); i++) {
if (json.charAt(i) >= 0x7f) {
firstUnsafe = i;
break;
}
}
if (firstUnsafe == -1) {
return json;
}

StringBuilder escaped = new StringBuilder(json.length());
escaped.append(json, 0, firstUnsafe);
for (int i = firstUnsafe; i < json.length(); i++) {
char c = json.charAt(i);
if (c >= 0x7f) {
escaped.append("\\u");
escaped.append(Character.forDigit((c >> 12) & 0xf, 16));
escaped.append(Character.forDigit((c >> 8) & 0xf, 16));
escaped.append(Character.forDigit((c >> 4) & 0xf, 16));
escaped.append(Character.forDigit(c & 0xf, 16));
} else {
escaped.append(c);
}
}

return escaped.toString();
}

/**
* Formats the specified query parameter to a list containing a single {@code Pair} object.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,43 @@ public String parameterToString(Object param) {
}
}

/**
* Format the given parameter object as an ASCII-safe JSON string.
*
* @param param Parameter
* @return JSON representation of the parameter
*/
public String parameterToJsonString(Object param) {
String json = JSON.serialize(param);
int firstUnsafe = -1;
for (int i = 0; i < json.length(); i++) {
if (json.charAt(i) >= 0x7f) {
firstUnsafe = i;
break;
}
}
if (firstUnsafe == -1) {
return json;
}

StringBuilder escaped = new StringBuilder(json.length());
escaped.append(json, 0, firstUnsafe);
for (int i = firstUnsafe; i < json.length(); i++) {
char c = json.charAt(i);
if (c >= 0x7f) {
escaped.append("\\u");
escaped.append(Character.forDigit((c >> 12) & 0xf, 16));
escaped.append(Character.forDigit((c >> 8) & 0xf, 16));
escaped.append(Character.forDigit((c >> 4) & 0xf, 16));
escaped.append(Character.forDigit(c & 0xf, 16));
} else {
escaped.append(c);
}
}

return escaped.toString();
}

/**
* Formats the specified query parameter to a list containing a single {@code Pair} object.
*
Expand Down
Loading
Loading