Skip to content

Commit b89a2f1

Browse files
committed
add dollar escaping for multiline strings
1 parent 5485eab commit b89a2f1

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,8 @@ protected void updateModelForObject(CodegenModel m, Schema schema) {
11311131
@Override
11321132
protected ImmutableMap.Builder<String, Mustache.Lambda> addMustacheLambdas() {
11331133
return super.addMustacheLambdas()
1134-
.put("escapeDollar", new EscapeChar("(?<!\\\\)\\$", "\\\\\\$"));
1134+
.put("escapeDollar", new EscapeChar("(?<!\\\\)\\$", "\\\\\\$"))
1135+
.put("escapeDollarInMultiline", new EscapeChar("(?<!\\\\)\\$", "\\${'\\$'}"));
11351136
}
11361137

11371138
protected interface DataTypeAssigner {

modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) v
7575
}} @Operation(
7676
summary = "{{#lambda.escapeDollar}}{{{summary}}}{{/lambda.escapeDollar}}",
7777
operationId = "{{{operationId}}}",
78-
description = """{{{unescapedNotes}}}""",
78+
description = """{{#lambda.escapeDollarInMultiline}}{{{unescapedNotes}}}{{/lambda.escapeDollarInMultiline}}""",
7979
responses = [{{#responses}}
8080
ApiResponse(responseCode = "{{{code}}}", description = "{{#lambda.escapeDollar}}{{{message}}}{{/lambda.escapeDollar}}"{{#baseType}}, content = [Content({{#isArray}}array = ArraySchema({{/isArray}}schema = Schema(implementation = {{{baseType}}}::class)){{#isArray}}){{/isArray}}]{{/baseType}}){{^-last}},{{/-last}}{{/responses}} ]{{#hasAuthMethods}},
8181
security = [ {{#authMethods}}SecurityRequirement(name = "{{name}}"{{#isOAuth}}, scopes = [ {{#scopes}}"{{scope}}"{{^-last}}, {{/-last}}{{/scopes}} ]{{/isOAuth}}){{^-last}},{{/-last}}{{/authMethods}} ]{{/hasAuthMethods}}

modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ interface {{classname}} {
8787
tags = [{{#tags}}"{{{name}}}",{{/tags}}],
8888
summary = "{{#lambda.escapeDollar}}{{{summary}}}{{/lambda.escapeDollar}}",
8989
operationId = "{{{operationId}}}",
90-
description = """{{{unescapedNotes}}}""",
90+
description = """{{#lambda.escapeDollarInMultiline}}{{{unescapedNotes}}}{{/lambda.escapeDollarInMultiline}}""",
9191
responses = [{{#responses}}
9292
ApiResponse(responseCode = "{{{code}}}", description = "{{#lambda.escapeDollar}}{{{message}}}{{/lambda.escapeDollar}}"{{#baseType}}, content = [Content({{#isArray}}array = ArraySchema({{/isArray}}schema = Schema(implementation = {{{baseType}}}::class)){{#isArray}}){{/isArray}}]{{/baseType}}){{^-last}},{{/-last}}{{/responses}}
9393
]{{#hasAuthMethods}},

modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2676,6 +2676,95 @@ public void testDollarsAndQuotesSwagger1() {
26762676
));
26772677
}
26782678

2679+
@Test
2680+
public void testDollarsAndQuotesSwagger2() {
2681+
Path apiSources = generateApiSources(
2682+
"src/test/resources/3_0/kotlin/petstore-with-tags.yaml",
2683+
Map.of(
2684+
KotlinSpringServerCodegen.DOCUMENTATION_PROVIDER, "springdoc",
2685+
KotlinSpringServerCodegen.ANNOTATION_LIBRARY, "swagger2",
2686+
KotlinSpringServerCodegen.DELEGATE_PATTERN, true
2687+
),
2688+
Map.of(
2689+
CodegenConstants.MODELS, "true",
2690+
CodegenConstants.MODEL_TESTS, "false",
2691+
CodegenConstants.MODEL_DOCS, "false",
2692+
CodegenConstants.APIS, "true",
2693+
CodegenConstants.SUPPORTING_FILES, "false"
2694+
)
2695+
);
2696+
assertGeneratedFilesContain(Map.of(
2697+
apiSources.resolve("src/main/kotlin/org/openapitools/api/itemsApi.kt"),
2698+
List.of(
2699+
"summary = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\"",
2700+
"description = \"\"\"SQ = \"; SBS = \\; DBS = \\\\; SD = ${'$'}some\"\"\"",
2701+
"@Parameter(description = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\", required = true) @PathVariable(\"item\\$Id\") itemDollarId: kotlin.String",
2702+
"@Parameter(description = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\", required = true) @PathVariable(\"item\\$SubId\") itemDollarSubId: kotlin.String",
2703+
"@Parameter(description = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\", schema = Schema(defaultValue = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\")) @Valid @RequestParam(value = \"filter\\$Type\", required = false, defaultValue = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\") filterDollarType: kotlin.String",
2704+
"@Parameter(description = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\", schema = Schema(defaultValue = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\")) @Valid @RequestParam(value = \"filter\\$SubType\", required = false, defaultValue = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\") filterDollarSubType: kotlin.String",
2705+
"@Parameter(description = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\", `in` = ParameterIn.HEADER) @RequestHeader(value = \"X-Custom_Header\", required = false) xCustomHeader: kotlin.String?",
2706+
"@Parameter(description = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\", `in` = ParameterIn.HEADER) @RequestHeader(value = \"X-Custom_Header_two\", required = false) xCustomHeaderTwo: kotlin.String?",
2707+
"@CookieValue(name = \"session\\$Token\", required = false) sessionDollarToken: kotlin.String?",
2708+
"@CookieValue(name = \"session\\$TokenTwo\", required = false) sessionDollarTokenTwo: kotlin.String?"
2709+
),
2710+
apiSources.resolve("src/main/kotlin/org/openapitools/model/ItemsItemIdSomethingItemSubIdGet200Response.kt"),
2711+
List.of(
2712+
"* @param itemDollarId SQ = \"; SBS = \\; DBS = \\\\; SD = $some",
2713+
"* @param nameDollarValue SQ = \"; SBS = \\; DBS = \\\\; SD = $some",
2714+
"@Schema(example = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\", description = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\")",
2715+
"@get:JsonProperty(\"item\\$Id\") val itemDollarId: kotlin.String? = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\",",
2716+
"@Schema(example = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\", description = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\")",
2717+
"@get:JsonProperty(\"name\\$Value\") val nameDollarValue: kotlin.String? = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\",",
2718+
"@get:JsonProperty(\"details\\$Info\")"
2719+
),
2720+
apiSources.resolve("src/main/kotlin/org/openapitools/model/ItemWithDollarAttributesAndExamples.kt"),
2721+
List.of(
2722+
"@Schema(example = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\", description = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\")",
2723+
"@get:JsonProperty(\"\\$id\") val dollarId: kotlin.String? = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\",",
2724+
"@Schema(example = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\", description = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\")",
2725+
"@get:JsonProperty(\"\\$name\") val dollarName: kotlin.String? = \"SQ = \\\"; SBS = \\\\; DBS = \\\\\\\\; SD = \\$some\""
2726+
)
2727+
));
2728+
// assertGeneratedFilesNotContain(Map.of(
2729+
// apiSources.resolve("src/main/kotlin/org/openapitools/api/itemsApi.kt"),
2730+
// List.of(
2731+
// "SQ = \\\\\";",
2732+
// "SBS = \\\\\\\\;",
2733+
// "DBS = \\\\\\\\\\\\\\\\;",
2734+
// "SD = \\\\$some",
2735+
// "@PathVariable(\"item$Id\")",
2736+
// "@PathVariable(\"item$SubId\")",
2737+
// "@RequestParam(value = \"filter$Type\"",
2738+
// "@RequestParam(value = \"filter$SubType\"",
2739+
// "@CookieValue(name = \"session$Token\"",
2740+
// "@CookieValue(name = \"session$TokenTwo\"",
2741+
// "@RequestParam(value = \"form$Name\"",
2742+
// "@RequestParam(value = \"form$Value\"",
2743+
// "PATH_ITEMS_ITEM_ID_SOMETHING_ITEM_SUB_ID_GET: String = \"/items/{item$Id}/something/{item$SubId}\"",
2744+
// "/* \"/items/{item\\$Id}/something/{item\\$SubId}\" */"
2745+
// ),
2746+
// apiSources.resolve("src/main/kotlin/org/openapitools/model/ItemsItemIdSomethingItemSubIdGet200Response.kt"),
2747+
// List.of(
2748+
// "SQ = \\\\\";",
2749+
// "SBS = \\\\\\\\;",
2750+
// "DBS = \\\\\\\\\\\\\\\\;",
2751+
// "SD = \\\\$some",
2752+
// "item$Id",
2753+
// "name$Value",
2754+
// "details$Info"
2755+
// ),
2756+
// apiSources.resolve("src/main/kotlin/org/openapitools/model/ItemWithDollarAttributesAndExamples.kt"),
2757+
// List.of(
2758+
// "SQ = \\\\\";",
2759+
// "SBS = \\\\\\\\;",
2760+
// "DBS = \\\\\\\\\\\\\\\\;",
2761+
// "SD = \\\\$some",
2762+
// "\"$id\"",
2763+
// "\"$name\""
2764+
// )
2765+
// ));
2766+
}
2767+
26792768
private Path generateApiSources(
26802769
String specFilePath,
26812770
Map<String, Object> additionalProperties,

0 commit comments

Comments
 (0)