Skip to content

Commit 3ae5d3e

Browse files
fix(java): serialize JSON header parameter content
1 parent 59339a9 commit 3ae5d3e

7 files changed

Lines changed: 114 additions & 9 deletions

File tree

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
5050
* If a query parameter should be serialized as json
5151
*/
5252
public boolean queryIsJsonMimeType;
53+
/**
54+
* True when a header parameter uses a JSON media type in Parameter.content.
55+
*/
56+
public boolean headerIsJsonMimeType;
5357
/**
5458
* datatype is the generic inner parameter of a std::optional for C++, or Optional (Java)
5559
*/
@@ -270,6 +274,7 @@ public CodegenParameter copy() {
270274
output.isArray = this.isArray;
271275
output.isMap = this.isMap;
272276
output.queryIsJsonMimeType = this.queryIsJsonMimeType;
277+
output.headerIsJsonMimeType = this.headerIsJsonMimeType;
273278
output.isOptional = this.isOptional;
274279
output.isExplode = this.isExplode;
275280
output.style = this.style;
@@ -294,15 +299,15 @@ public int hashCode() {
294299
isFormStyle, isSpaceDelimited, isPipeDelimited,
295300
jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal,
296301
isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isPassword,
297-
isFreeFormObject, isAnyType, isArray, isMap, queryIsJsonMimeType, isOptional, isFile, isEnum, isEnumRef, _enum, allowableValues,
298-
items, mostInnerItems, additionalProperties, vars, requiredVars, vendorExtensions, hasValidation,
299-
getMaxProperties(), getMinProperties(), isNullable, isDeprecated, required, getMaximum(),
300-
getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(), getMaxLength(), getMinLength(),
301-
getPattern(), getMaxItems(), getMinItems(), getUniqueItems(), contentType, multipleOf, isNull, isVoid,
302-
additionalPropertiesIsAnyType, hasVars, hasRequired, isShort, isUnboundedInteger,
303-
hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes, schema, content,
304-
requiredVarsMap, ref, uniqueItemsBoolean, schemaIsFromAdditionalProperties,
305-
nameInPascalCase, nameInCamelCase, nameInLowerCase, nameInSnakeCase);
302+
isFreeFormObject, isAnyType, isArray, isMap, queryIsJsonMimeType, headerIsJsonMimeType, isOptional,
303+
isFile, isEnum, isEnumRef, _enum, allowableValues, items, mostInnerItems, additionalProperties, vars,
304+
requiredVars, vendorExtensions, hasValidation, getMaxProperties(), getMinProperties(), isNullable,
305+
isDeprecated, required, getMaximum(), getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(),
306+
getMaxLength(), getMinLength(), getPattern(), getMaxItems(), getMinItems(), getUniqueItems(),
307+
contentType, multipleOf, isNull, isVoid, additionalPropertiesIsAnyType, hasVars, hasRequired, isShort,
308+
isUnboundedInteger, hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes, schema,
309+
content, requiredVarsMap, ref, uniqueItemsBoolean, schemaIsFromAdditionalProperties, nameInPascalCase,
310+
nameInCamelCase, nameInLowerCase, nameInSnakeCase);
306311
}
307312

308313
@Override
@@ -345,6 +350,7 @@ public boolean equals(Object o) {
345350
isArray == that.isArray &&
346351
isMap == that.isMap &&
347352
queryIsJsonMimeType == that.queryIsJsonMimeType &&
353+
headerIsJsonMimeType == that.headerIsJsonMimeType &&
348354
isOptional == that.isOptional &&
349355
isFile == that.isFile &&
350356
isEnum == that.isEnum &&
@@ -486,6 +492,7 @@ public String toString() {
486492
sb.append(", isArray=").append(isArray);
487493
sb.append(", isMap=").append(isMap);
488494
sb.append(", queryIsJsonMimeType=").append(queryIsJsonMimeType);
495+
sb.append(", headerIsJsonMimeType=").append(headerIsJsonMimeType);
489496
sb.append(", isOptional=").append(isOptional);
490497
sb.append(", isFile=").append(isFile);
491498
sb.append(", isEnum=").append(isEnum);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5714,6 +5714,7 @@ public CodegenParameter fromParameter(Parameter parameter, Set<String> imports)
57145714
codegenParameter.isPathParam = true;
57155715
} else if (parameter instanceof HeaderParameter || "header".equalsIgnoreCase(parameter.getIn())) {
57165716
codegenParameter.isHeaderParam = true;
5717+
codegenParameter.headerIsJsonMimeType = isJsonMimeType(codegenParameter.contentType);
57175718
} else if (parameter instanceof CookieParameter || "cookie".equalsIgnoreCase(parameter.getIn())) {
57185719
codegenParameter.isCookieParam = true;
57195720
} else {

‎modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,28 @@ public class ApiClient {
912912
}
913913
}
914914
915+
/**
916+
* Format the given parameter object as an ASCII-safe JSON string.
917+
*
918+
* @param param Parameter
919+
* @return JSON representation of the parameter
920+
*/
921+
public String parameterToJsonString(Object param) {
922+
String json = JSON.serialize(param);
923+
StringBuilder escaped = new StringBuilder(json.length());
924+
925+
for (int i = 0; i < json.length(); i++) {
926+
char c = json.charAt(i);
927+
if (c > 0x7f) {
928+
escaped.append(String.format("\\u%04x", (int) c));
929+
} else {
930+
escaped.append(c);
931+
}
932+
}
933+
934+
return escaped.toString();
935+
}
936+
915937
/**
916938
* Formats the specified query parameter to a list containing a single {@code Pair} object.
917939
*

‎modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/api.mustache‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,12 @@ public class {{classname}} {
229229
{{#headerParams}}
230230

231231
if ({{paramName}} != null) {
232+
{{#headerIsJsonMimeType}}
233+
localVarHeaderParams.put("{{baseName}}", localVarApiClient.parameterToJsonString({{paramName}}));
234+
{{/headerIsJsonMimeType}}
235+
{{^headerIsJsonMimeType}}
232236
localVarHeaderParams.put("{{baseName}}", localVarApiClient.parameterToString({{paramName}}));
237+
{{/headerIsJsonMimeType}}
233238
}
234239

235240
{{/headerParams}}

‎modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5362,6 +5362,18 @@ public void testQueryIsJsonMimeType() {
53625362
assertTrue(codegenOperation.queryParams.stream().allMatch(p -> p.queryIsJsonMimeType));
53635363
}
53645364

5365+
@Test
5366+
public void testHeaderIsJsonMimeType() {
5367+
DefaultCodegen codegen = new DefaultCodegen();
5368+
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_1/java/json-header-content.yaml");
5369+
codegen.setOpenAPI(openAPI);
5370+
String path = "/test";
5371+
CodegenOperation codegenOperation = codegen.fromOperation(path, "POST", openAPI.getPaths().get(path).getPost(), null);
5372+
5373+
assertThat(codegenOperation.headerParams).hasSize(1);
5374+
assertTrue(codegenOperation.headerParams.get(0).headerIsJsonMimeType);
5375+
}
5376+
53655377
@Test
53665378
public void testDefaultOauthIsNotNull() {
53675379
final DefaultCodegen codegen = new DefaultCodegen();

‎modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,32 @@ public void testGeneratePing() {
511511
.contains("public class DefaultApi");
512512
}
513513

514+
@Test
515+
public void testJsonContentHeaderUsesJsonSerialization() {
516+
final Path output = newTempFolder();
517+
final CodegenConfigurator configurator = new CodegenConfigurator()
518+
.setGeneratorName(JAVA_GENERATOR)
519+
.setLibrary(JavaClientCodegen.OKHTTP_GSON)
520+
.setInputSpec("src/test/resources/3_1/java/json-header-content.yaml")
521+
.setOutputDir(output.toString().replace("\\", "/"));
522+
523+
List<File> files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate();
524+
525+
validateJavaSourceFiles(files);
526+
527+
assertThat(output.resolve("src/main/java/org/openapitools/client/ApiClient.java"))
528+
.content()
529+
.contains("public String parameterToJsonString(Object param)");
530+
assertThat(output.resolve("src/main/java/org/openapitools/client/api/DefaultApi.java"))
531+
.content()
532+
.contains(
533+
"localVarHeaderParams.put(\"X-Json-Arg\", localVarApiClient.parameterToJsonString(xJsonArg));"
534+
)
535+
.doesNotContain(
536+
"localVarHeaderParams.put(\"X-Json-Arg\", localVarApiClient.parameterToString(xJsonArg));"
537+
);
538+
}
539+
514540
@Test
515541
public void testGeneratePingSomeObj() {
516542
final Path output = newTempFolder();
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
openapi: 3.1.0
2+
3+
info:
4+
title: JSON header repro
5+
version: 1.0.0
6+
7+
paths:
8+
/test:
9+
post:
10+
operationId: testJsonHeader
11+
parameters:
12+
- name: X-Json-Arg
13+
in: header
14+
required: true
15+
content:
16+
application/json:
17+
schema:
18+
$ref: '#/components/schemas/HeaderArg'
19+
responses:
20+
'204':
21+
description: OK
22+
23+
components:
24+
schemas:
25+
HeaderArg:
26+
type: object
27+
required:
28+
- path
29+
properties:
30+
path:
31+
type: string
32+

0 commit comments

Comments
 (0)