Skip to content

Commit 102f729

Browse files
committed
fix issues with incorrectly escaped values and implement CR feedback
1 parent f9446c2 commit 102f729

120 files changed

Lines changed: 697 additions & 309 deletions

File tree

Some content is hidden

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

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class CodegenOperation {
3333
hasErrorResponseObject; // if 4xx, 5xx responses have at least one error object defined
3434
public CodegenProperty returnProperty;
3535
public String path, operationId, returnType, returnFormat, httpMethod, returnBaseType,
36-
returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse;
36+
returnContainer, summary, unescapedSummary, unescapedNotes, notes, baseName, defaultResponse;
3737
public CodegenDiscriminator discriminator;
3838
public List<Map<String, String>> consumes, produces, prioritizedContentTypes;
3939
public List<CodegenServer> servers = new ArrayList<CodegenServer>();
@@ -429,6 +429,7 @@ public String toString() {
429429
sb.append(", returnBaseType='").append(returnBaseType).append('\'');
430430
sb.append(", returnContainer='").append(returnContainer).append('\'');
431431
sb.append(", summary='").append(summary).append('\'');
432+
sb.append(", unescapedSummary='").append(unescapedSummary).append('\'');
432433
sb.append(", unescapedNotes='").append(unescapedNotes).append('\'');
433434
sb.append(", notes='").append(notes).append('\'');
434435
sb.append(", baseName='").append(baseName).append('\'');
@@ -502,6 +503,7 @@ public boolean equals(Object o) {
502503
Objects.equals(returnBaseType, that.returnBaseType) &&
503504
Objects.equals(returnContainer, that.returnContainer) &&
504505
Objects.equals(summary, that.summary) &&
506+
Objects.equals(unescapedSummary, that.unescapedSummary) &&
505507
Objects.equals(unescapedNotes, that.unescapedNotes) &&
506508
Objects.equals(notes, that.notes) &&
507509
Objects.equals(baseName, that.baseName) &&
@@ -547,7 +549,7 @@ public int hashCode() {
547549
returnTypeIsPrimitive, returnSimpleType, subresourceOperation, isMap,
548550
isArray, isMultipart, isVoid, isResponseBinary, isResponseFile, isResponseOptional, hasReference,
549551
isDeprecated, isCallbackRequest, uniqueItems, path, operationId, returnType, httpMethod,
550-
returnBaseType, returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse,
552+
returnBaseType, returnContainer, summary, unescapedSummary, unescapedNotes, notes, baseName, defaultResponse,
551553
discriminator, consumes, produces, prioritizedContentTypes, servers, bodyParam, allParams, bodyParams,
552554
pathParams, queryParams, headerParams, formParams, cookieParams, requiredParams, returnProperty, optionalParams,
553555
authMethods, tags, responses, callbacks, imports, examples, requestBodyExamples, externalDocs,

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
3434
isCollectionFormatMulti, isPrimitiveType, isModel, isExplode, isDeepObject, isMatrix, isAllowEmptyValue,
3535
isFormStyle, isSpaceDelimited, isPipeDelimited;
3636
public String baseName, paramName, dataType, datatypeWithEnum, dataFormat, contentType,
37-
collectionFormat, description, unescapedDescription, baseType, defaultValue, enumDefaultValue, enumName, style;
37+
collectionFormat, description, unescapedDescription, baseType, defaultValue, unescapedDefaultValue, enumDefaultValue, enumName, style;
3838

3939
public String nameInLowerCase; // property name in lower case
4040
public String nameInCamelCase; // property name in camel case (e.g. modifiedDate)
@@ -182,6 +182,7 @@ public CodegenParameter copy() {
182182
output.multipleOf = this.multipleOf;
183183
output.jsonSchema = this.jsonSchema;
184184
output.defaultValue = this.defaultValue;
185+
output.unescapedDefaultValue = this.unescapedDefaultValue;
185186
output.enumDefaultValue = this.enumDefaultValue;
186187
output.example = this.example;
187188
output.examples = this.examples;
@@ -289,7 +290,7 @@ public int hashCode() {
289290
return Objects.hash(isFormParam, isQueryParam, isPathParam, isHeaderParam, isCookieParam,
290291
isBodyParam, isContainer, isCollectionFormatMulti, isPrimitiveType, isModel, isExplode, baseName,
291292
paramName, dataType, datatypeWithEnum, dataFormat, collectionFormat, description,
292-
unescapedDescription, baseType, containerType, containerTypeMapped, defaultValue,
293+
unescapedDescription, baseType, containerType, containerTypeMapped, defaultValue, unescapedDefaultValue,
293294
enumDefaultValue, enumName, style, isDeepObject, isMatrix, isAllowEmptyValue, example, examples,
294295
isFormStyle, isSpaceDelimited, isPipeDelimited,
295296
jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal,
@@ -382,6 +383,7 @@ public boolean equals(Object o) {
382383
Objects.equals(containerType, that.containerType) &&
383384
Objects.equals(containerTypeMapped, that.containerTypeMapped) &&
384385
Objects.equals(defaultValue, that.defaultValue) &&
386+
Objects.equals(unescapedDefaultValue, that.unescapedDefaultValue) &&
385387
Objects.equals(enumDefaultValue, that.enumDefaultValue) &&
386388
Objects.equals(enumName, that.enumName) &&
387389
Objects.equals(style, that.style) &&
@@ -450,6 +452,7 @@ public String toString() {
450452
sb.append(", containerType='").append(containerType).append('\'');
451453
sb.append(", containerTypeMapped='").append(containerTypeMapped).append('\'');
452454
sb.append(", defaultValue='").append(defaultValue).append('\'');
455+
sb.append(", unescapedDefaultValue='").append(unescapedDefaultValue).append('\'');
453456
sb.append(", enumDefaultValue='").append(enumDefaultValue).append('\'');
454457
sb.append(", enumName='").append(enumName).append('\'');
455458
sb.append(", style='").append(style).append('\'');

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti
8181
@Getter @Setter
8282
public String unescapedDescription;
8383

84+
/**
85+
* The default value string without escape characters; use this in string literal contexts
86+
* (e.g. inside "..." or """...""") together with an appropriate escaping lambda.
87+
* Unlike {@code defaultValue}, this is never passed through escapeText() or escapeUnsafeCharacters().
88+
*/
89+
@Getter @Setter
90+
public String unescapedDefaultValue;
91+
8492
/**
8593
* maxLength validation for strings, see http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.1
8694
*/
@@ -992,6 +1000,7 @@ public String toString() {
9921000
sb.append(", containerTypeMapped='").append(containerTypeMapped).append('\'');
9931001
sb.append(", title='").append(title).append('\'');
9941002
sb.append(", unescapedDescription='").append(unescapedDescription).append('\'');
1003+
sb.append(", unescapedDefaultValue='").append(unescapedDefaultValue).append('\'');
9951004
sb.append(", maxLength=").append(maxLength);
9961005
sb.append(", minLength=").append(minLength);
9971006
sb.append(", pattern='").append(pattern).append('\'');
@@ -1179,6 +1188,7 @@ public boolean equals(Object o) {
11791188
Objects.equals(containerTypeMapped, that.containerTypeMapped) &&
11801189
Objects.equals(title, that.title) &&
11811190
Objects.equals(unescapedDescription, that.unescapedDescription) &&
1191+
Objects.equals(unescapedDefaultValue, that.unescapedDefaultValue) &&
11821192
Objects.equals(maxLength, that.maxLength) &&
11831193
Objects.equals(minLength, that.minLength) &&
11841194
Objects.equals(pattern, that.pattern) &&
@@ -1212,7 +1222,7 @@ public int hashCode() {
12121222

12131223
return Objects.hash(openApiType, baseName, complexType, getter, setter, description,
12141224
dataType, datatypeWithEnum, dataFormat, name, min, max, defaultValue,
1215-
defaultValueWithParam, baseType, containerType, containerTypeMapped, title, unescapedDescription,
1225+
defaultValueWithParam, baseType, containerType, containerTypeMapped, title, unescapedDescription, unescapedDefaultValue,
12161226
maxLength, minLength, pattern, example, jsonSchema, minimum, maximum,
12171227
exclusiveMinimum, exclusiveMaximum, required, deprecated,
12181228
isPrimitiveType, isModel, isContainer, isString, isNumeric,

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class CodegenResponse implements IJsonSchemaValidationProperties {
3333
public boolean is4xx;
3434
public boolean is5xx;
3535
public String message;
36+
public String unescapedMessage;
3637
public List<Map<String, Object>> examples;
3738
public String dataType;
3839
public String baseType;
@@ -109,7 +110,7 @@ public class CodegenResponse implements IJsonSchemaValidationProperties {
109110

110111
@Override
111112
public int hashCode() {
112-
return Objects.hash(headers, code, message, examples, dataType, baseType, containerType, containerTypeMapped, hasHeaders,
113+
return Objects.hash(headers, code, message, unescapedMessage, examples, dataType, baseType, containerType, containerTypeMapped, hasHeaders,
113114
isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal, isByteArray, isBoolean, isDate,
114115
isDateTime, isUuid, isEmail, isPassword, isModel, isFreeFormObject, isAnyType, isDefault, simpleType, primitiveType,
115116
isMap, isOptional, isArray, isBinary, isFile, schema, jsonSchema, vendorExtensions, items, additionalProperties,
@@ -182,6 +183,7 @@ public boolean equals(Object o) {
182183
Objects.equals(headers, that.headers) &&
183184
Objects.equals(code, that.code) &&
184185
Objects.equals(message, that.message) &&
186+
Objects.equals(unescapedMessage, that.unescapedMessage) &&
185187
Objects.equals(examples, that.examples) &&
186188
Objects.equals(dataType, that.dataType) &&
187189
Objects.equals(baseType, that.baseType) &&
@@ -582,6 +584,7 @@ public String toString() {
582584
sb.append(", is4xx='").append(is4xx).append('\'');
583585
sb.append(", is5xx='").append(is5xx).append('\'');
584586
sb.append(", message='").append(message).append('\'');
587+
sb.append(", unescapedMessage='").append(unescapedMessage).append('\'');
585588
sb.append(", examples=").append(examples);
586589
sb.append(", dataType='").append(dataType).append('\'');
587590
sb.append(", baseType='").append(baseType).append('\'');

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,24 @@ protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
476476
.put("trimLineBreaks", new TrimLineBreaksLambda())
477477
.put("trimWhitespace", new TrimWhitespaceLambda())
478478
.put("trimTrailingWithNewLine", new TrimTrailingWhiteSpaceLambda(true))
479-
.put("trimTrailing", new TrimTrailingWhiteSpaceLambda(false));
479+
.put("trimTrailing", new TrimTrailingWhiteSpaceLambda(false))
480+
// Escapes text for use inside a Markdown table cell or inline text.
481+
// Order matters: \\ and & must be first to avoid double-escaping.
482+
// $ is escaped to prevent LaTeX math mode ($...$) in renderers that support it.
483+
.put("escapeMarkdown", (fragment, writer) -> writer.write(fragment.execute()
484+
.replace("\\", "\\\\")
485+
.replace("&", "&amp;")
486+
.replace("<", "&lt;")
487+
.replace(">", "&gt;")
488+
.replace("$", "\\$")
489+
.replace("|", "\\|")
490+
.replace("\r\n", " ")
491+
.replace("\n", " ")
492+
.replace("\r", " ")))
493+
.put("collapseNewlines", (fragment, writer) -> writer.write(fragment.execute()
494+
.replace("\r\n", " ")
495+
.replace("\n", " ")
496+
.replace("\r", " ")));
480497
}
481498

482499
private void registerMustacheLambdas() {
@@ -4315,6 +4332,7 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo
43154332

43164333
// set the default value
43174334
property.defaultValue = toDefaultValue(property, p);
4335+
property.unescapedDefaultValue = p.getDefault() != null ? String.valueOf(p.getDefault()) : null;
43184336
property.defaultValueWithParam = toDefaultValueWithParam(name, p);
43194337

43204338
LOGGER.debug("debugging from property return: {}", property);
@@ -4738,6 +4756,7 @@ public CodegenOperation fromOperation(String path,
47384756
}
47394757

47404758
op.summary = escapeText(operation.getSummary());
4759+
op.unescapedSummary = operation.getSummary();
47414760
op.unescapedNotes = operation.getDescription();
47424761
op.notes = escapeText(operation.getDescription());
47434762
op.hasConsumes = false;
@@ -5092,6 +5111,7 @@ public CodegenResponse fromResponse(String responseCode, ApiResponse response) {
50925111
}
50935112
r.schema = responseSchema;
50945113
r.message = escapeText(response.getDescription());
5114+
r.unescapedMessage = response.getDescription();
50955115

50965116
// adding examples to API responses
50975117
Map<String, Example> examples = ExamplesUtils.getExamplesFromResponse(openAPI, response);
@@ -5641,6 +5661,7 @@ public CodegenParameter fromParameter(Parameter parameter, Set<String> imports)
56415661

56425662
// set default value
56435663
codegenParameter.defaultValue = toDefaultParameterValue(codegenProperty, parameterSchema);
5664+
codegenParameter.unescapedDefaultValue = parameterSchema.getDefault() != null ? String.valueOf(parameterSchema.getDefault()) : null;
56445665

56455666
finishUpdatingParameter(codegenParameter, parameter);
56465667
return codegenParameter;
@@ -7543,6 +7564,7 @@ public CodegenParameter fromFormProperty(String name, Schema propertySchema, Set
75437564

75447565
// set default value
75457566
codegenParameter.defaultValue = toDefaultParameterValue(codegenProperty, propertySchema);
7567+
codegenParameter.unescapedDefaultValue = propertySchema.getDefault() != null ? String.valueOf(propertySchema.getDefault()) : null;
75467568

75477569
if (ModelUtils.isFileSchema(ps) && !ModelUtils.isStringSchema(ps)) {
75487570
// swagger v2 only, type file
@@ -8089,6 +8111,7 @@ public CodegenParameter fromRequestBody(RequestBody body, Set<String> imports, S
80898111
codegenParameter.baseName = "UNKNOWN_BASE_NAME";
80908112
codegenParameter.paramName = "UNKNOWN_PARAM_NAME";
80918113
codegenParameter.description = escapeText(body.getDescription());
8114+
codegenParameter.unescapedDescription = body.getDescription();
80928115
codegenParameter.required = body.getRequired() != null ? body.getRequired() : Boolean.FALSE;
80938116
codegenParameter.isBodyParam = Boolean.TRUE;
80948117
if (body.getExtensions() != null) {

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1274,7 +1274,20 @@ protected void updateModelForObject(CodegenModel m, Schema schema) {
12741274
@Override
12751275
protected ImmutableMap.Builder<String, Mustache.Lambda> addMustacheLambdas() {
12761276
return super.addMustacheLambdas()
1277-
.put("escapeDollar", new EscapeChar("(?<!\\\\)\\$", "\\\\\\$"));
1277+
.put("escapeDollar", new EscapeChar("(?<!\\\\)\\$", "\\\\\\$"))
1278+
// Replaces each $ with ${'$'} for use inside """...""" triple-quoted Kotlin strings,
1279+
// where backslash escapes are not available.
1280+
.put("escapeDollarInMultiline", new EscapeChar("\\$", "\\${'\\$'}"))
1281+
// Full escaping for raw values going into "..." double-quoted Kotlin strings.
1282+
// Handles \, $, " and also literal newline/tab/carriage-return chars.
1283+
// \\ replacement must be first to avoid double-escaping subsequent insertions.
1284+
.put("escapeInNormalString", (fragment, writer) -> writer.write(fragment.execute()
1285+
.replace("\\", "\\\\")
1286+
.replace("$", "\\$")
1287+
.replace("\"", "\\\"")
1288+
.replace("\n", "\\n")
1289+
.replace("\r", "\\r")
1290+
.replace("\t", "\\t")));
12781291
}
12791292

12801293
protected interface DataTypeAssigner {

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -962,17 +962,13 @@ public void processOpts() {
962962
// spring uses the jackson lib, and we disallow configuration.
963963
additionalProperties.put("jackson", "true");
964964

965-
// add lambda for mustache templates
966-
additionalProperties.put("lambdaEscapeInNormalString",
967-
(Mustache.Lambda) (fragment, writer) -> writer.write(fragment.execute().replaceAll("([$\"\\\\])", "\\\\$1")));
968-
additionalProperties.put("lambdaRemoveLineBreak",
969-
(Mustache.Lambda) (fragment, writer) -> writer.write(fragment.execute().replaceAll("[\\r\\n]", "")));
970965
}
971966

972967
@Override
973968
protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
974969
return super.addMustacheLambdas()
975-
.put("escapeDoubleQuote", new EscapeLambda("\"", "\\\""));
970+
.put("escapeDoubleQuote", new EscapeLambda("\"", "\\\""))
971+
.put("removeLineBreak", (fragment, writer) -> writer.write(fragment.execute().replaceAll("[\\r\\n]", "")));
976972
}
977973

978974
@Override
@@ -1445,6 +1441,7 @@ private void markPropertyAsInherited(CodegenModel model, String baseName, String
14451441
p.defaultValue = dataType + "." + toEnumVarName(discriminatorValue, dataType);
14461442
} else {
14471443
p.defaultValue = "\"" + escapeText(discriminatorValue) + "\"";
1444+
p.unescapedDefaultValue = discriminatorValue;
14481445
}
14491446
}
14501447
});

0 commit comments

Comments
 (0)