Skip to content

Commit 0aedd88

Browse files
committed
[kotlin-spring][server]fix generation of referenced examples on RequestBody
# Conflicts: # modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java
1 parent 578bdbe commit 0aedd88

File tree

8 files changed

+152
-0
lines changed

8 files changed

+152
-0
lines changed

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.openapitools.codegen.model.OperationMap;
3535
import org.openapitools.codegen.model.OperationsMap;
3636
import org.openapitools.codegen.templating.mustache.SpringHttpStatusLambda;
37+
import org.openapitools.codegen.utils.ExamplesUtils;
3738
import org.openapitools.codegen.utils.ModelUtils;
3839
import org.openapitools.codegen.utils.URLPathUtils;
3940
import org.slf4j.Logger;
@@ -999,6 +1000,20 @@ public void setReturnContainer(final String returnContainer) {
9991000
});
10001001
});
10011002
}
1003+
if (operation.bodyParam != null && operation.bodyParam.getContent() != null && !operation.bodyParam.getContent().isEmpty()) {
1004+
List<Map<String,Object>> contentList = new ArrayList<>();
1005+
operation.bodyParam.getContent().forEach((mediaType, mediaTypeObject) -> {
1006+
Map<String,Object> entry = new HashMap<>();
1007+
entry.put("mediaType", mediaType);
1008+
entry.put("schema", mediaTypeObject.getSchema());
1009+
if (mediaTypeObject.getExamples() != null && !mediaTypeObject.getExamples().isEmpty()) {
1010+
entry.put("examples", ExamplesUtils.unaliasExamples(openAPI, mediaTypeObject.getExamples()));
1011+
}
1012+
contentList.add(entry);
1013+
});
1014+
operation.bodyParam.vendorExtensions.put("content", contentList);
1015+
1016+
}
10021017

10031018
final List<CodegenParameter> allParams = operation.allParams;
10041019
if (allParams != null) {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) v
7676
summary = "{{{summary}}}",
7777
operationId = "{{{operationId}}}",
7878
description = """{{{unescapedNotes}}}""",
79+
requestBody = {{>requestBody}},
7980
responses = [{{#responses}}
8081
ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{#baseType}}, content = [Content({{#isArray}}array = ArraySchema({{/isArray}}schema = Schema(implementation = {{{baseType}}}::class)){{#isArray}}){{/isArray}}]{{/baseType}}){{^-last}},{{/-last}}{{/responses}} ]{{#hasAuthMethods}},
8182
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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ interface {{classname}} {
8888
summary = "{{{summary}}}",
8989
operationId = "{{{operationId}}}",
9090
description = """{{{unescapedNotes}}}""",
91+
requestBody = {{>requestBody}},
9192
responses = [{{#responses}}
9293
ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{#baseType}}, content = [Content({{#isArray}}array = ArraySchema({{/isArray}}schema = Schema(implementation = {{{baseType}}}::class)){{#isArray}}){{/isArray}}]{{/baseType}}){{^-last}},{{/-last}}{{/responses}}
9394
]{{#hasAuthMethods}},
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@SwaggerRequestBody(
2+
description = "{{{bodyParam.description}}}",
3+
content = [
4+
{{#bodyParam.vendorExtensions.content}}
5+
Content(
6+
mediaType = "{{mediaType}}",
7+
examples = [
8+
{{#examples}}
9+
Example(name = "{{{exampleName}}}", value = "{{{exampleValue}}}"){{^-last}},{{/-last}}
10+
{{/examples}}
11+
]
12+
){{^-last}},{{/-last}}
13+
{{/bodyParam.vendorExtensions.content}}
14+
]
15+
)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.openapitools.codegen.kotlin.assertions;
2+
3+
import org.assertj.core.util.CanIgnoreReturnValue;
4+
import org.jetbrains.kotlin.psi.KtAnnotationEntry;
5+
6+
@CanIgnoreReturnValue
7+
public class MethodAnnotationAssert extends AbstractAnnotationAssert<MethodAnnotationAssert> {
8+
private final MethodAssert methodAssert;
9+
10+
MethodAnnotationAssert(final MethodAssert methodAssert, final KtAnnotationEntry annotationEntry) {
11+
super(annotationEntry, MethodAnnotationAssert.class);
12+
this.methodAssert = methodAssert;
13+
}
14+
15+
public MethodAssert toMethod() {
16+
return methodAssert;
17+
}
18+
}

modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/assertions/MethodAssert.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.assertj.core.api.AbstractAssert;
44
import org.assertj.core.api.Assertions;
55
import org.assertj.core.util.CanIgnoreReturnValue;
6+
import org.jetbrains.kotlin.psi.KtAnnotationEntry;
67
import org.jetbrains.kotlin.psi.KtNamedFunction;
78
import org.jetbrains.kotlin.psi.KtParameter;
89

@@ -30,6 +31,19 @@ public ParameterAssert assertParameter(final String parameterName) {
3031
return new ParameterAssert(this, parameters.get(0));
3132
}
3233

34+
public MethodAnnotationAssert assertAnnotation(final String annotationName) {
35+
final List<KtAnnotationEntry> annotations = actual.getAnnotationEntries().stream()
36+
.filter(
37+
p -> Objects.equals(p.getTypeReference() != null ? p.getTypeReference().getText() : null, annotationName)
38+
)
39+
.collect(Collectors.toList());
40+
Assertions.assertThat(annotations)
41+
.withFailMessage("Expected class to have a single annotation %s, but found %s", annotationName, annotations.size())
42+
.hasSize(1);
43+
44+
return new MethodAnnotationAssert(this, annotations.get(0));
45+
}
46+
3347
public ClassAssert toClass() {
3448
return classAssert;
3549
}

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3561,4 +3561,37 @@ private Map<String, File> generateFromContract(
35613561
return generator.opts(input).generate().stream()
35623562
.collect(Collectors.toMap(File::getName, Function.identity()));
35633563
}
3564+
3565+
@Test
3566+
public void testRequestBodyExamplesAreGenerated() throws IOException {
3567+
Map<String, Object> additionalProperties = new HashMap<>();
3568+
additionalProperties.put(ANNOTATION_LIBRARY, AnnotationLibrary.SWAGGER2.toCliOptValue());
3569+
final Map<String, File> files = generateFromContract("src/test/resources/bugs/issue_20009.yaml", additionalProperties);
3570+
KotlinFileAssert.assertThat(files.get("PetsApiController.kt"))
3571+
.assertClass("PetsApiController")
3572+
.assertMethod("postPet")
3573+
.assertAnnotation("Operation")
3574+
.hasAttributes(ImmutableMap.of("requestBody", "@SwaggerRequestBody(\n" +
3575+
" description = \"Request body to create a pet\",\n" +
3576+
" content = [\n" +
3577+
" Content(\n" +
3578+
" mediaType = \"application/vnd.api.v2+json\",\n" +
3579+
" examples = [\n" +
3580+
" Example(name = \"V2ReferencedExample\", value = \"{\\\"v2_example_schema_property\\\":\\\"example schema property value from referenced example\\\",\\\"v2_another_example_schema_property\\\":\\\"another example schema property value from referenced example\\\"}\")\n" +
3581+
" ]\n" +
3582+
" ),\n" +
3583+
" Content(\n" +
3584+
" mediaType = \"application/vnd.api+json\",\n" +
3585+
" examples = [\n" +
3586+
" Example(name = \"\", value = \"\\\"example6 value\\\"\"),\n" +
3587+
" Example(name = \"ReferencedExample\", value = \"{\\\"example_schema_property\\\":\\\"example schema property value from referenced example\\\",\\\"another_example_schema_property\\\":\\\"another example schema property value from referenced example\\\"}\")\n" +
3588+
" ]\n" +
3589+
" )\n" +
3590+
" ]\n" +
3591+
")")
3592+
3593+
)
3594+
;
3595+
}
3596+
35643597
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
openapi: "3.0.0"
2+
info:
3+
version: 2.0.0
4+
title: test
5+
paths:
6+
/pets:
7+
post:
8+
operationId: postPet
9+
description: Creates a pet
10+
requestBody:
11+
description: Request body to create a pet
12+
required: true
13+
content:
14+
application/vnd.api.v2+json:
15+
schema:
16+
$ref: '#/components/schemas/ObjectSchema'
17+
examples:
18+
V2ReferencedExample:
19+
$ref: '#/components/examples/V2ReferencedExample'
20+
application/vnd.api+json:
21+
schema:
22+
type: object
23+
properties:
24+
name:
25+
type: string
26+
examples:
27+
NonReferencedExample:
28+
description: "Non referenced Example"
29+
value: 'example6 value'
30+
ReferencedExample:
31+
$ref: '#/components/examples/ReferencedExample'
32+
responses:
33+
'200':
34+
description: successful operation
35+
36+
components:
37+
schemas:
38+
ObjectSchema:
39+
type: object
40+
properties:
41+
id:
42+
type: integer
43+
name:
44+
type: string
45+
examples:
46+
ReferencedExample:
47+
summary: An example of ReferencedExample
48+
value:
49+
example_schema_property: example schema property value from referenced example
50+
another_example_schema_property: another example schema property value from referenced example
51+
V2ReferencedExample:
52+
summary: An example of ReferencedExample for version 2
53+
value:
54+
v2_example_schema_property: example schema property value from referenced example
55+
v2_another_example_schema_property: another example schema property value from referenced example

0 commit comments

Comments
 (0)