Skip to content
Draft
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 @@ -34,6 +34,7 @@
import org.openapitools.codegen.model.OperationMap;
import org.openapitools.codegen.model.OperationsMap;
import org.openapitools.codegen.templating.mustache.SpringHttpStatusLambda;
import org.openapitools.codegen.utils.ExamplesUtils;
import org.openapitools.codegen.utils.ModelUtils;
import org.openapitools.codegen.utils.URLPathUtils;
import org.slf4j.Logger;
Expand Down Expand Up @@ -999,6 +1000,20 @@ public void setReturnContainer(final String returnContainer) {
});
});
}
if (operation.bodyParam != null && operation.bodyParam.getContent() != null && !operation.bodyParam.getContent().isEmpty()) {
List<Map<String,Object>> contentList = new ArrayList<>();
operation.bodyParam.getContent().forEach((mediaType, mediaTypeObject) -> {
Map<String,Object> entry = new HashMap<>();
entry.put("mediaType", mediaType);
entry.put("schema", mediaTypeObject.getSchema());
if (mediaTypeObject.getExamples() != null && !mediaTypeObject.getExamples().isEmpty()) {
entry.put("examples", ExamplesUtils.unaliasExamples(openAPI, mediaTypeObject.getExamples()));
}
contentList.add(entry);
});
operation.bodyParam.vendorExtensions.put("content", contentList);

}

final List<CodegenParameter> allParams = operation.allParams;
if (allParams != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) v
summary = "{{{summary}}}",
operationId = "{{{operationId}}}",
description = """{{{unescapedNotes}}}""",
requestBody = {{>requestBody}},
responses = [{{#responses}}
ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{#baseType}}, content = [Content({{#isArray}}array = ArraySchema({{/isArray}}schema = Schema(implementation = {{{baseType}}}::class)){{#isArray}}){{/isArray}}]{{/baseType}}){{^-last}},{{/-last}}{{/responses}} ]{{#hasAuthMethods}},
security = [ {{#authMethods}}SecurityRequirement(name = "{{name}}"{{#isOAuth}}, scopes = [ {{#scopes}}"{{scope}}"{{^-last}}, {{/-last}}{{/scopes}} ]{{/isOAuth}}){{^-last}},{{/-last}}{{/authMethods}} ]{{/hasAuthMethods}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ interface {{classname}} {
summary = "{{{summary}}}",
operationId = "{{{operationId}}}",
description = """{{{unescapedNotes}}}""",
requestBody = {{>requestBody}},
responses = [{{#responses}}
ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{#baseType}}, content = [Content({{#isArray}}array = ArraySchema({{/isArray}}schema = Schema(implementation = {{{baseType}}}::class)){{#isArray}}){{/isArray}}]{{/baseType}}){{^-last}},{{/-last}}{{/responses}}
]{{#hasAuthMethods}},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@SwaggerRequestBody(
description = "{{{bodyParam.description}}}",
content = [
{{#bodyParam.vendorExtensions.content}}
Content(
mediaType = "{{mediaType}}",
examples = [
{{#examples}}
Example(name = "{{{exampleName}}}", value = "{{{exampleValue}}}"){{^-last}},{{/-last}}
{{/examples}}
]
){{^-last}},{{/-last}}
{{/bodyParam.vendorExtensions.content}}
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.openapitools.codegen.kotlin.assertions;

import org.assertj.core.util.CanIgnoreReturnValue;
import org.jetbrains.kotlin.psi.KtAnnotationEntry;

@CanIgnoreReturnValue
public class MethodAnnotationAssert extends AbstractAnnotationAssert<MethodAnnotationAssert> {
private final MethodAssert methodAssert;

MethodAnnotationAssert(final MethodAssert methodAssert, final KtAnnotationEntry annotationEntry) {
super(annotationEntry, MethodAnnotationAssert.class);
this.methodAssert = methodAssert;
}

public MethodAssert toMethod() {
return methodAssert;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.Assertions;
import org.assertj.core.util.CanIgnoreReturnValue;
import org.jetbrains.kotlin.psi.KtAnnotationEntry;
import org.jetbrains.kotlin.psi.KtNamedFunction;
import org.jetbrains.kotlin.psi.KtParameter;

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

public MethodAnnotationAssert assertAnnotation(final String annotationName) {
final List<KtAnnotationEntry> annotations = actual.getAnnotationEntries().stream()
.filter(
p -> Objects.equals(p.getTypeReference() != null ? p.getTypeReference().getText() : null, annotationName)
)
.collect(Collectors.toList());
Assertions.assertThat(annotations)
.withFailMessage("Expected class to have a single annotation %s, but found %s", annotationName, annotations.size())
.hasSize(1);

return new MethodAnnotationAssert(this, annotations.get(0));
}

public ClassAssert toClass() {
return classAssert;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3561,4 +3561,37 @@ private Map<String, File> generateFromContract(
return generator.opts(input).generate().stream()
.collect(Collectors.toMap(File::getName, Function.identity()));
}

@Test
public void testRequestBodyExamplesAreGenerated() throws IOException {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put(ANNOTATION_LIBRARY, AnnotationLibrary.SWAGGER2.toCliOptValue());
final Map<String, File> files = generateFromContract("src/test/resources/bugs/issue_20009.yaml", additionalProperties);
KotlinFileAssert.assertThat(files.get("PetsApiController.kt"))
.assertClass("PetsApiController")
.assertMethod("postPet")
.assertAnnotation("Operation")
.hasAttributes(ImmutableMap.of("requestBody", "@SwaggerRequestBody(\n" +
" description = \"Request body to create a pet\",\n" +
" content = [\n" +
" Content(\n" +
" mediaType = \"application/vnd.api.v2+json\",\n" +
" examples = [\n" +
" 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" +
" ]\n" +
" ),\n" +
" Content(\n" +
" mediaType = \"application/vnd.api+json\",\n" +
" examples = [\n" +
" Example(name = \"\", value = \"\\\"example6 value\\\"\"),\n" +
" 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" +
" ]\n" +
" )\n" +
" ]\n" +
")")

)
;
}

}
55 changes: 55 additions & 0 deletions modules/openapi-generator/src/test/resources/bugs/issue_20009.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
openapi: "3.0.0"
info:
version: 2.0.0
title: test
paths:
/pets:
post:
operationId: postPet
description: Creates a pet
requestBody:
description: Request body to create a pet
required: true
content:
application/vnd.api.v2+json:
schema:
$ref: '#/components/schemas/ObjectSchema'
examples:
V2ReferencedExample:
$ref: '#/components/examples/V2ReferencedExample'
application/vnd.api+json:
schema:
type: object
properties:
name:
type: string
examples:
NonReferencedExample:
description: "Non referenced Example"
value: 'example6 value'
ReferencedExample:
$ref: '#/components/examples/ReferencedExample'
responses:
'200':
description: successful operation

components:
schemas:
ObjectSchema:
type: object
properties:
id:
type: integer
name:
type: string
examples:
ReferencedExample:
summary: An example of ReferencedExample
value:
example_schema_property: example schema property value from referenced example
another_example_schema_property: another example schema property value from referenced example
V2ReferencedExample:
summary: An example of ReferencedExample for version 2
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