Consider '$ref' for 'getProducesInfo' and 'getConsumesInfo' (#176)

This commit is contained in:
Jérémie Bresson 2018-04-21 15:45:43 +02:00 committed by GitHub
parent 2e50780e1d
commit 72ffc95d6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 161 additions and 71 deletions

View File

@ -2147,19 +2147,19 @@ public class DefaultCodegen implements CodegenConfig {
ArraySchema as = (ArraySchema) responseSchema;
if (as.getItems() != null && StringUtils.isEmpty(as.getItems().get$ref())) { // arary of primtive types
op.examples = new ExampleGenerator(schemas).generate((Map<String, Object>) responseSchema.getExample(),
new ArrayList<String>(getProducesInfo(operation)), as.getItems(), openAPI);
new ArrayList<String>(getProducesInfo(openAPI, operation)), as.getItems(), openAPI);
} else if (as.getItems() != null && !StringUtils.isEmpty(as.getItems().get$ref())) { // array of model
op.examples = new ExampleGenerator(schemas).generate((Map<String, Object>) responseSchema.getExample(),
new ArrayList<String>(getProducesInfo(operation)), getSimpleRef(as.getItems().get$ref()), openAPI);
new ArrayList<String>(getProducesInfo(openAPI, operation)), getSimpleRef(as.getItems().get$ref()), openAPI);
} else {
// TODO log warning message as such case is not handled at the moment
}
} else if (StringUtils.isEmpty(responseSchema.get$ref())) { // primtiive type (e.g. integer, string)
op.examples = new ExampleGenerator(schemas).generate((Map<String, Object>) responseSchema.getExample(),
new ArrayList<String>(getProducesInfo(operation)), responseSchema, openAPI);
new ArrayList<String>(getProducesInfo(openAPI, operation)), responseSchema, openAPI);
} else { // model
op.examples = new ExampleGenerator(schemas).generate((Map<String, Object>) responseSchema.getExample(),
new ArrayList<String>(getProducesInfo(operation)), getSimpleRef(responseSchema.get$ref()), openAPI);
new ArrayList<String>(getProducesInfo(openAPI, operation)), getSimpleRef(responseSchema.get$ref()), openAPI);
}
op.defaultResponse = toDefaultValue(responseSchema);
@ -2234,7 +2234,7 @@ public class DefaultCodegen implements CodegenConfig {
// add example
if (schemas != null) {
op.requestBodyExamples = new ExampleGenerator(schemas).generate(null, new ArrayList<String>(getConsumesInfo(operation)), bodyParam.baseType, openAPI);
op.requestBodyExamples = new ExampleGenerator(schemas).generate(null, new ArrayList<String>(getConsumesInfo(openAPI, operation)), bodyParam.baseType, openAPI);
}
}
}
@ -3886,62 +3886,39 @@ public class DefaultCodegen implements CodegenConfig {
}
}
public static Set<String> getConsumesInfo(Operation operation) {
if (operation.getRequestBody() == null || operation.getRequestBody().getContent() == null || operation.getRequestBody().getContent().isEmpty()) {
public static Set<String> getConsumesInfo(OpenAPI openAPI, Operation operation) {
RequestBody requestBody = ModelUtils.getReferencedRequestBody(openAPI, operation.getRequestBody());
if (requestBody == null || requestBody.getContent() == null || requestBody.getContent().isEmpty()) {
return Collections.emptySet(); // return emtpy set
}
return operation.getRequestBody().getContent().keySet();
return requestBody.getContent().keySet();
}
public Boolean hasFormParameter(Operation operation) {
Set<String> consumesInfo = getConsumesInfo(operation);
public boolean hasFormParameter(OpenAPI openAPI, Operation operation) {
Set<String> consumesInfo = getConsumesInfo(openAPI, operation);
if (consumesInfo == null || consumesInfo.isEmpty()) {
return Boolean.FALSE;
return false;
}
List<String> consumes = new ArrayList<String>(consumesInfo);
if (consumes == null) {
return Boolean.FALSE;
}
for (String consume : consumes) {
for (String consume : consumesInfo) {
if ("application/x-www-form-urlencoded".equalsIgnoreCase(consume) || "multipart/form-data".equalsIgnoreCase(consume)) {
return Boolean.TRUE;
return true;
}
}
return Boolean.FALSE;
return false;
}
public boolean hasBodyParameter(OpenAPI openAPI, Operation operation) {
RequestBody requestBody = operation.getRequestBody();
RequestBody requestBody = ModelUtils.getReferencedRequestBody(openAPI, operation.getRequestBody());
if (requestBody == null) {
return false;
}
if (StringUtils.isNotEmpty(requestBody.get$ref())) {
String name = ModelUtils.getSimpleRef(requestBody.get$ref());
requestBody = ModelUtils.getRequestBody(openAPI, name);
if (requestBody == null) {
return false;
}
}
Schema schema = getSchemaFromBody(requestBody);
if (schema == null) {
return false;
}
if (StringUtils.isNotEmpty(schema.get$ref())) {
String name = ModelUtils.getSimpleRef(schema.get$ref());
schema = ModelUtils.getSchema(openAPI, name);
if (schema == null) {
return false;
}
}
return true;
return ModelUtils.getReferencedSchema(openAPI, schema) != null;
}
private void addProducesInfo(ApiResponse response, CodegenOperation codegenOperation) {
@ -3978,18 +3955,20 @@ public class DefaultCodegen implements CodegenConfig {
/**
* returns the list of MIME types the APIs can produce
*
* @param openAPI
* @param operation Operation
*
* @return a set of MIME types
*/
public static Set<String> getProducesInfo(Operation operation) {
public static Set<String> getProducesInfo(OpenAPI openAPI, Operation operation) {
if (operation.getResponses() == null || operation.getResponses().isEmpty()) {
return null;
}
Set<String> produces = new TreeSet<String>();
for (ApiResponse response : operation.getResponses().values()) {
for (ApiResponse r : operation.getResponses().values()) {
ApiResponse response = ModelUtils.getReferencedApiResponse(openAPI, r);
if (response.getContent() != null) {
produces.addAll(response.getContent().keySet());
}

View File

@ -933,23 +933,23 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
continue;
}
for (Operation operation : path.readOperations()) {
if (hasBodyParameter(openAPI, operation) || hasFormParameter(operation)) {
String defaultContentType = hasFormParameter(operation) ? "application/x-www-form-urlencoded" : "application/json";
List<String> consumes = new ArrayList<String>(getConsumesInfo(operation));
if (hasBodyParameter(openAPI, operation) || hasFormParameter(openAPI, operation)) {
String defaultContentType = hasFormParameter(openAPI, operation) ? "application/x-www-form-urlencoded" : "application/json";
List<String> consumes = new ArrayList<String>(getConsumesInfo(openAPI, operation));
String contentType = consumes == null || consumes.isEmpty() ? defaultContentType : consumes.get(0);
operation.addExtension("x-contentType", contentType);
}
String accepts = getAccept(operation);
String accepts = getAccept(openAPI, operation);
operation.addExtension("x-accepts", accepts);
}
}
}
protected static String getAccept(Operation operation) {
protected static String getAccept(OpenAPI openAPI, Operation operation) {
String accepts = null;
String defaultContentType = "application/json";
ArrayList<String> produces = new ArrayList<String>(getProducesInfo(operation));
ArrayList<String> produces = new ArrayList<String>(getProducesInfo(openAPI, operation));
if (produces != null && !produces.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (String produce : produces) {

View File

@ -606,8 +606,8 @@ public class BashClientCodegen extends DefaultCodegen implements CodegenConfig {
* If the operation produces Json and has nonempty example
* try to reformat it.
*/
if (getConsumesInfo(operation) != null
&& getConsumesInfo(operation).contains("application/json")
if (getConsumesInfo(openAPI, operation) != null
&& getConsumesInfo(openAPI, operation).contains("application/json")
&& definitions.get(p.dataType).getExample() != null) {
ObjectMapper mapper = new ObjectMapper();

View File

@ -507,7 +507,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
boolean consumesXml = false;
// if "consumes" is defined (per operation or using global definition)
if (consumes != null && !consumes.isEmpty()) {
consumes.addAll(getConsumesInfo(operation));
consumes.addAll(getConsumesInfo(openAPI, operation));
List<Map<String, String>> c = new ArrayList<Map<String, String>>();
for (String mimeType : consumes) {
Map<String, String> mediaType = new HashMap<String, String>();
@ -529,7 +529,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
}
List<String> produces = new ArrayList<String>(getProducesInfo(operation));
List<String> produces = new ArrayList<String>(getProducesInfo(openAPI, operation));
// if "consumes" is defined (per operation or using global definition)
/*
if (operation.getProduces() != null) {

View File

@ -3,9 +3,29 @@ package org.openapitools.codegen.utils;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.BinarySchema;
import io.swagger.v3.oas.models.media.BooleanSchema;
import io.swagger.v3.oas.models.media.ByteArraySchema;
import io.swagger.v3.oas.models.media.ComposedSchema;
import io.swagger.v3.oas.models.media.DateSchema;
import io.swagger.v3.oas.models.media.DateTimeSchema;
import io.swagger.v3.oas.models.media.EmailSchema;
import io.swagger.v3.oas.models.media.FileSchema;
import io.swagger.v3.oas.models.media.IntegerSchema;
import io.swagger.v3.oas.models.media.MapSchema;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.NumberSchema;
import io.swagger.v3.oas.models.media.ObjectSchema;
import io.swagger.v3.oas.models.media.PasswordSchema;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.media.UUIDSchema;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CodegenModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -15,8 +35,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
public class ModelUtils {
static Logger LOGGER = LoggerFactory.getLogger(ModelUtils.class);
@ -99,7 +117,6 @@ public class ModelUtils {
return unusedSchemas;
}
// todo change it to public later
public static String getSimpleRef(String ref) {
if (ref.startsWith("#/components/")) {
ref = ref.substring(ref.lastIndexOf("/") + 1);
@ -309,28 +326,79 @@ public class ModelUtils {
return false;
}
public static Schema getSchema(OpenAPI openapi, String name) {
if (name == null) {
return null;
/**
* If a Schema contains a reference to an other Schema with '$ref', returns the referenced Schema or the actual Schema in the other cases.
* @param openAPI
* @param schema potentially containing a '$ref'
* @return schema without '$ref'
*/
public static Schema getReferencedSchema(OpenAPI openAPI, Schema schema) {
if (schema != null && StringUtils.isNotEmpty(schema.get$ref())) {
String name = getSimpleRef(schema.get$ref());
return getSchema(openAPI, name);
}
if (openapi != null && openapi.getComponents() != null && openapi.getComponents().getSchemas() != null) {
return openapi.getComponents().getSchemas().get(name);
}
return null;
return schema;
}
public static RequestBody getRequestBody(OpenAPI openapi, String name) {
public static Schema getSchema(OpenAPI openAPI, String name) {
if (name == null) {
return null;
}
if (openapi != null && openapi.getComponents() != null && openapi.getComponents().getRequestBodies() != null) {
return openapi.getComponents().getRequestBodies().get(name);
if (openAPI != null && openAPI.getComponents() != null && openAPI.getComponents().getSchemas() != null) {
return openAPI.getComponents().getSchemas().get(name);
}
return null;
}
/**
* If a RequestBody contains a reference to an other RequestBody with '$ref', returns the referenced RequestBody or the actual RequestBody in the other cases.
* @param openAPI
* @param requestBody potentially containing a '$ref'
* @return requestBody without '$ref'
*/
public static RequestBody getReferencedRequestBody(OpenAPI openAPI, RequestBody requestBody) {
if (requestBody != null && StringUtils.isNotEmpty(requestBody.get$ref())) {
String name = getSimpleRef(requestBody.get$ref());
return getRequestBody(openAPI, name);
}
return requestBody;
}
public static RequestBody getRequestBody(OpenAPI openAPI, String name) {
if (name == null) {
return null;
}
if (openAPI != null && openAPI.getComponents() != null && openAPI.getComponents().getRequestBodies() != null) {
return openAPI.getComponents().getRequestBodies().get(name);
}
return null;
}
/**
* If a ApiResponse contains a reference to an other ApiResponse with '$ref', returns the referenced ApiResponse or the actual ApiResponse in the other cases.
* @param openAPI
* @param apiResponse potentially containing a '$ref'
* @return apiResponse without '$ref'
*/
public static ApiResponse getReferencedApiResponse(OpenAPI openAPI, ApiResponse apiResponse) {
if (apiResponse != null && StringUtils.isNotEmpty(apiResponse.get$ref())) {
String name = getSimpleRef(apiResponse.get$ref());
return getApiResponse(openAPI, name);
}
return apiResponse;
}
public static ApiResponse getApiResponse(OpenAPI openAPI, String name) {
if (name == null) {
return null;
}
if (openAPI != null && openAPI.getComponents() != null && openAPI.getComponents().getRequestBodies() != null) {
return openAPI.getComponents().getResponses().get(name);
}
return null;
}
}

View File

@ -14,6 +14,8 @@ import io.swagger.v3.oas.models.responses.ApiResponses;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.Set;
public class DefaultCodegenTest {
@Test
@ -39,6 +41,47 @@ public class DefaultCodegenTest {
Assert.assertEquals(codegen.hasBodyParameter(openAPI, pingOperation), false);
Assert.assertEquals(codegen.hasBodyParameter(openAPI, createOperation), true);
}
@Test
public void testGetConsumesInfoAndGetProducesInfo() throws Exception {
final Schema refSchema = new Schema<>().$ref("#/components/schemas/Pet");
OpenAPI openAPI = new OpenAPI();
openAPI.setComponents(new Components());
openAPI.getComponents().addSchemas("Pet", new ObjectSchema());
openAPI.getComponents().addRequestBodies("MyRequestBody", new RequestBody()
.content(new Content().addMediaType("application/json",
new MediaType().schema(refSchema))));
openAPI.getComponents().addResponses("MyResponse", new ApiResponse()
.description("Ok response")
.content(new Content().addMediaType("application/xml",
new MediaType().schema(refSchema))));
Operation createOperation = new Operation()
.requestBody(new RequestBody()
.content(new Content()
.addMediaType("application/json", new MediaType().schema(refSchema))
.addMediaType("application/xml", new MediaType().schema(refSchema))
))
.responses(
new ApiResponses().addApiResponse("201", new ApiResponse()
.description("Created response")));
Set<String> createConsumesInfo = DefaultCodegen.getConsumesInfo(openAPI, createOperation);
Assert.assertEquals(createConsumesInfo.size(), 2);
Assert.assertTrue(createConsumesInfo.contains("application/json"), "contains 'application/json'");
Assert.assertTrue(createConsumesInfo.contains("application/xml"), "contains 'application/xml'");
Set<String> createProducesInfo = DefaultCodegen.getProducesInfo(openAPI, createOperation);
Assert.assertEquals(createProducesInfo.size(), 0);
Operation updateOperationWithRef = new Operation()
.requestBody(new RequestBody().$ref("#/components/requestBodies/MyRequestBody"))
.responses(new ApiResponses().addApiResponse("201", new ApiResponse().$ref("#/components/responses/MyResponse")));
Set<String> updateConsumesInfo = DefaultCodegen.getConsumesInfo(openAPI, updateOperationWithRef);
Assert.assertEquals(updateConsumesInfo.size(), 1);
Assert.assertTrue(updateConsumesInfo.contains("application/json"), "contains 'application/json'");
Set<String> updateProducesInfo = DefaultCodegen.getProducesInfo(openAPI, updateOperationWithRef);
Assert.assertEquals(updateProducesInfo.size(), 1);
Assert.assertTrue(updateProducesInfo.contains("application/xml"), "contains 'application/xml'");
}
@Test
public void testInitialConfigValues() throws Exception {