mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-05-18 15:40:53 +00:00
Merge e2e45e6385d74309833424401ceab0cc48137548 into d6c46342693205f0dae441b45742d9c85d41cf33
This commit is contained in:
commit
f8b2103d3f
@ -69,6 +69,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
|||||||
|useJakartaEe|whether to use Jakarta EE namespace instead of javax| |false|
|
|useJakartaEe|whether to use Jakarta EE namespace instead of javax| |false|
|
||||||
|useOneOfInterfaces|whether to use a java interface to describe a set of oneOf options, where each option is a class that implements the interface| |false|
|
|useOneOfInterfaces|whether to use a java interface to describe a set of oneOf options, where each option is a class that implements the interface| |false|
|
||||||
|withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false|
|
|withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false|
|
||||||
|
|groupByResponseContentType| Group server or client methods by response content types. For example, when openapi operation produces one of "application/json" and "application/xml" content types will be generated only one method for both content types. Otherwise for each content type will be generated different method. **Available only for generatos with supportsDividingOperationsByContentType** | |true|
|
||||||
|
|groupByRequestAndResponseContentType| Group server or client methods by request body and response content types. For example, when openapi operation consumes "application/json" and "application/xml" content type and also api response has content with the same content types, 2 different methods will be generated. The content of the request and response types will match. Otherwise, will be generated 4 methods - for each combination of request body content type and response content type. **Available only for generatos with supportsDividingOperationsByContentType** | |true|
|
||||||
|
|
||||||
## SUPPORTED VENDOR EXTENSIONS
|
## SUPPORTED VENDOR EXTENSIONS
|
||||||
|
|
||||||
|
@ -366,4 +366,5 @@ public interface CodegenConfig {
|
|||||||
|
|
||||||
Set<String> getOpenapiGeneratorIgnoreList();
|
Set<String> getOpenapiGeneratorIgnoreList();
|
||||||
|
|
||||||
|
boolean supportsDividingOperationsByContentType();
|
||||||
}
|
}
|
||||||
|
@ -454,4 +454,17 @@ public class CodegenConstants {
|
|||||||
public static final String WAIT_TIME_OF_THREAD = "waitTimeMillis";
|
public static final String WAIT_TIME_OF_THREAD = "waitTimeMillis";
|
||||||
|
|
||||||
public static final String USE_DEFAULT_VALUES_FOR_REQUIRED_VARS = "useDefaultValuesForRequiredVars";
|
public static final String USE_DEFAULT_VALUES_FOR_REQUIRED_VARS = "useDefaultValuesForRequiredVars";
|
||||||
|
|
||||||
|
public static final String GROUP_BY_RESPONSE_CONTENT_TYPE = "groupByResponseContentType";
|
||||||
|
public static final String GROUP_BY_RESPONSE_CONTENT_TYPE_DESC =
|
||||||
|
"Group server or client methods by response content types. "
|
||||||
|
+ "For example, when openapi operation produces one of \"application/json\" and \"application/xml\" content types "
|
||||||
|
+ "will be generated only one method for both content types. Otherwise for each content type will be generated different method.";
|
||||||
|
|
||||||
|
public static final String GROUP_BY_REQUEST_AND_RESPONSE_CONTENT_TYPE = "groupByRequestAndResponseContentType";
|
||||||
|
public static final String GROUP_BY_REQUEST_AND_RESPONSE_CONTENT_TYPE_DESC =
|
||||||
|
"Group server or client methods by request body and response content types. "
|
||||||
|
+ "For example, when openapi operation consumes \"application/json\" and \"application/xml\" content type and also api response "
|
||||||
|
+ "has content with the same content types, 2 different methods will be generated. The content of the request and response types will match. "
|
||||||
|
+ "Otherwise, will be generated 4 methods - for each combination of request body content type and response content type.";
|
||||||
}
|
}
|
||||||
|
@ -333,6 +333,10 @@ public class DefaultCodegen implements CodegenConfig {
|
|||||||
|
|
||||||
// Whether to automatically hardcode params that are considered Constants by OpenAPI Spec
|
// Whether to automatically hardcode params that are considered Constants by OpenAPI Spec
|
||||||
@Setter protected boolean autosetConstants = false;
|
@Setter protected boolean autosetConstants = false;
|
||||||
|
@Setter
|
||||||
|
protected boolean groupByRequestAndResponseContentType = true;
|
||||||
|
@Setter
|
||||||
|
protected boolean groupByResponseContentType = true;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getAddSuffixToDuplicateOperationNicknames() {
|
public boolean getAddSuffixToDuplicateOperationNicknames() {
|
||||||
@ -392,9 +396,10 @@ public class DefaultCodegen implements CodegenConfig {
|
|||||||
convertPropertyToBooleanAndWriteBack(CodegenConstants.DISALLOW_ADDITIONAL_PROPERTIES_IF_NOT_PRESENT, this::setDisallowAdditionalPropertiesIfNotPresent);
|
convertPropertyToBooleanAndWriteBack(CodegenConstants.DISALLOW_ADDITIONAL_PROPERTIES_IF_NOT_PRESENT, this::setDisallowAdditionalPropertiesIfNotPresent);
|
||||||
convertPropertyToBooleanAndWriteBack(CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE, this::setEnumUnknownDefaultCase);
|
convertPropertyToBooleanAndWriteBack(CodegenConstants.ENUM_UNKNOWN_DEFAULT_CASE, this::setEnumUnknownDefaultCase);
|
||||||
convertPropertyToBooleanAndWriteBack(CodegenConstants.AUTOSET_CONSTANTS, this::setAutosetConstants);
|
convertPropertyToBooleanAndWriteBack(CodegenConstants.AUTOSET_CONSTANTS, this::setAutosetConstants);
|
||||||
|
convertPropertyToBooleanAndWriteBack(CodegenConstants.GROUP_BY_REQUEST_AND_RESPONSE_CONTENT_TYPE, this::setGroupByRequestAndResponseContentType);
|
||||||
|
convertPropertyToBooleanAndWriteBack(CodegenConstants.GROUP_BY_RESPONSE_CONTENT_TYPE, this::setGroupByResponseContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Preset map builder with commonly used Mustache lambdas.
|
* Preset map builder with commonly used Mustache lambdas.
|
||||||
*
|
*
|
||||||
@ -910,7 +915,7 @@ public class DefaultCodegen implements CodegenConfig {
|
|||||||
* @return the sanitized variable name for enum
|
* @return the sanitized variable name for enum
|
||||||
*/
|
*/
|
||||||
public String toEnumVarName(String value, String datatype) {
|
public String toEnumVarName(String value, String datatype) {
|
||||||
if (value.length() == 0) {
|
if (value.isEmpty()) {
|
||||||
return "EMPTY";
|
return "EMPTY";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1011,6 +1016,47 @@ public class DefaultCodegen implements CodegenConfig {
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void preprocessOpenAPI(OpenAPI openAPI) {
|
public void preprocessOpenAPI(OpenAPI openAPI) {
|
||||||
|
|
||||||
|
if (supportsDividingOperationsByContentType() && openAPI.getPaths() != null && !openAPI.getPaths().isEmpty()) {
|
||||||
|
|
||||||
|
for (Map.Entry<String, PathItem> entry : openAPI.getPaths().entrySet()) {
|
||||||
|
String pathStr = entry.getKey();
|
||||||
|
PathItem path = entry.getValue();
|
||||||
|
List<Operation> getOps = divideOperationsByContentType(openAPI, pathStr, PathItem.HttpMethod.GET, path.getGet());
|
||||||
|
if (!getOps.isEmpty()) {
|
||||||
|
path.addExtension("x-get", getOps);
|
||||||
|
}
|
||||||
|
List<Operation> putOps = divideOperationsByContentType(openAPI, pathStr, PathItem.HttpMethod.PUT, path.getPut());
|
||||||
|
if (!putOps.isEmpty()) {
|
||||||
|
path.addExtension("x-put", putOps);
|
||||||
|
}
|
||||||
|
List<Operation> postOps = divideOperationsByContentType(openAPI, pathStr, PathItem.HttpMethod.POST, path.getPost());
|
||||||
|
if (!postOps.isEmpty()) {
|
||||||
|
path.addExtension("x-post", postOps);
|
||||||
|
}
|
||||||
|
List<Operation> deleteOps = divideOperationsByContentType(openAPI, pathStr, PathItem.HttpMethod.DELETE, path.getDelete());
|
||||||
|
if (!deleteOps.isEmpty()) {
|
||||||
|
path.addExtension("x-delete", deleteOps);
|
||||||
|
}
|
||||||
|
List<Operation> optionsOps = divideOperationsByContentType(openAPI, pathStr, PathItem.HttpMethod.OPTIONS, path.getOptions());
|
||||||
|
if (!optionsOps.isEmpty()) {
|
||||||
|
path.addExtension("x-options", optionsOps);
|
||||||
|
}
|
||||||
|
List<Operation> headOps = divideOperationsByContentType(openAPI, pathStr, PathItem.HttpMethod.HEAD, path.getHead());
|
||||||
|
if (!headOps.isEmpty()) {
|
||||||
|
path.addExtension("x-head", headOps);
|
||||||
|
}
|
||||||
|
List<Operation> patchOps = divideOperationsByContentType(openAPI, pathStr, PathItem.HttpMethod.PATCH, path.getPatch());
|
||||||
|
if (!patchOps.isEmpty()) {
|
||||||
|
path.addExtension("x-patch", patchOps);
|
||||||
|
}
|
||||||
|
List<Operation> traceOps = divideOperationsByContentType(openAPI, pathStr, PathItem.HttpMethod.TRACE, path.getTrace());
|
||||||
|
if (!traceOps.isEmpty()) {
|
||||||
|
path.addExtension("x-trace", traceOps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (useOneOfInterfaces && openAPI.getComponents() != null) {
|
if (useOneOfInterfaces && openAPI.getComponents() != null) {
|
||||||
// we process the openapi schema here to find oneOf schemas and create interface models for them
|
// we process the openapi schema here to find oneOf schemas and create interface models for them
|
||||||
Map<String, Schema> schemas = new HashMap<>(openAPI.getComponents().getSchemas());
|
Map<String, Schema> schemas = new HashMap<>(openAPI.getComponents().getSchemas());
|
||||||
@ -1092,6 +1138,261 @@ public class DefaultCodegen implements CodegenConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Operation> divideOperationsByContentType(OpenAPI openAPI, String path, PathItem.HttpMethod httpMethod, Operation op) {
|
||||||
|
|
||||||
|
if (op == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
var operationIndexes = new HashMap<String, Integer>();
|
||||||
|
operationIndexes.put(getOrGenerateOperationId(op, path, httpMethod.name()), 0);
|
||||||
|
|
||||||
|
var additionalOps = new ArrayList<Operation>();
|
||||||
|
divideOperationByRequestBody(openAPI, path, httpMethod, op, additionalOps, operationIndexes);
|
||||||
|
|
||||||
|
// Check responses content types and divide operations by them
|
||||||
|
|
||||||
|
var responses = op.getResponses();
|
||||||
|
if (responses == null || responses.isEmpty()) {
|
||||||
|
return additionalOps;
|
||||||
|
}
|
||||||
|
var unwrappedResponses = new ApiResponses();
|
||||||
|
var allPossibleContentTypes = new ArrayList<String>();
|
||||||
|
for (var responseEntry : responses.entrySet()) {
|
||||||
|
var apiResponse = ModelUtils.getReferencedApiResponse(openAPI, responseEntry.getValue());
|
||||||
|
unwrappedResponses.put(responseEntry.getKey(), apiResponse);
|
||||||
|
if (apiResponse.getContent() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (var contentType : apiResponse.getContent().keySet()) {
|
||||||
|
contentType = contentType.toLowerCase();
|
||||||
|
if (!allPossibleContentTypes.contains(contentType)) {
|
||||||
|
allPossibleContentTypes.add(contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allPossibleContentTypes.isEmpty() || allPossibleContentTypes.size() == 1) {
|
||||||
|
return additionalOps;
|
||||||
|
}
|
||||||
|
op.setResponses(unwrappedResponses);
|
||||||
|
responses = unwrappedResponses;
|
||||||
|
|
||||||
|
var apiResponsesByContentType = new HashMap<String, ApiResponses>();
|
||||||
|
for (var contentType : allPossibleContentTypes) {
|
||||||
|
var apiResponses = new ApiResponses();
|
||||||
|
for (var responseEntry : responses.entrySet()) {
|
||||||
|
var code = responseEntry.getKey();
|
||||||
|
var response = responseEntry.getValue();
|
||||||
|
if (response.getContent() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var mediaType = response.getContent().get(contentType);
|
||||||
|
if (mediaType == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
apiResponses.addApiResponse(code, new ApiResponse()
|
||||||
|
.description(response.getDescription())
|
||||||
|
.headers(response.getHeaders())
|
||||||
|
.links(response.getLinks())
|
||||||
|
.extensions(response.getExtensions() != null ? new LinkedHashMap<>(response.getExtensions()) : new LinkedHashMap<>())
|
||||||
|
.$ref(response.get$ref())
|
||||||
|
.content(new Content()
|
||||||
|
.addMediaType(contentType, mediaType)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
apiResponsesByContentType.put(contentType, apiResponses);
|
||||||
|
}
|
||||||
|
|
||||||
|
var addedContentTypes = new ArrayList<String>();
|
||||||
|
var finalAdditionalOps = new ArrayList<Operation>();
|
||||||
|
divideOperationByResponses(path, httpMethod, op, apiResponsesByContentType, finalAdditionalOps, addedContentTypes, operationIndexes);
|
||||||
|
for (var additionalOp : additionalOps) {
|
||||||
|
finalAdditionalOps.add(additionalOp);
|
||||||
|
divideOperationByResponses(path, httpMethod, additionalOp, apiResponsesByContentType, finalAdditionalOps, addedContentTypes, operationIndexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove correct processed contentTypes
|
||||||
|
apiResponsesByContentType.entrySet().removeIf(stringMediaTypeEntry -> addedContentTypes.contains(stringMediaTypeEntry.getKey()));
|
||||||
|
|
||||||
|
if (!apiResponsesByContentType.isEmpty()) {
|
||||||
|
appendCommonResponseMediaTypes(op, apiResponsesByContentType.values());
|
||||||
|
for (var additionalOp : additionalOps) {
|
||||||
|
appendCommonResponseMediaTypes(additionalOp, apiResponsesByContentType.values());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalAdditionalOps;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void divideOperationByRequestBody(OpenAPI openAPI, String path, PathItem.HttpMethod httpMethod, Operation op,
|
||||||
|
List<Operation> additionalOps, Map<String, Integer> operationIndexes) {
|
||||||
|
RequestBody body = ModelUtils.getReferencedRequestBody(openAPI, op.getRequestBody());
|
||||||
|
if (body == null || body.getContent() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
op.setRequestBody(body);
|
||||||
|
Content content = body.getContent();
|
||||||
|
if (content.size() <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var firstEntry = content.entrySet().iterator().next();
|
||||||
|
var mediaTypesToRemove = new ArrayList<String>();
|
||||||
|
for (var entry : content.entrySet()) {
|
||||||
|
var contentType = entry.getKey();
|
||||||
|
MediaType mediaType = entry.getValue();
|
||||||
|
if (mediaTypesToRemove.contains(contentType) || contentType.equals(firstEntry.getKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var foundSameOpSignature = false;
|
||||||
|
// group by response content type
|
||||||
|
if (groupByResponseContentType) {
|
||||||
|
if (firstEntry.getValue().equals(mediaType)) {
|
||||||
|
if (!groupByRequestAndResponseContentType) {
|
||||||
|
foundSameOpSignature = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var additionalOp : additionalOps) {
|
||||||
|
RequestBody additionalBody = ModelUtils.getReferencedRequestBody(openAPI, additionalOp.getRequestBody());
|
||||||
|
if (additionalBody == null || additionalBody.getContent() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (var addContentEntry : additionalBody.getContent().entrySet()) {
|
||||||
|
if (addContentEntry.getValue().equals(mediaType)) {
|
||||||
|
foundSameOpSignature = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundSameOpSignature) {
|
||||||
|
additionalBody.getContent().put(contentType, mediaType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupByResponseContentType && foundSameOpSignature) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mediaTypesToRemove.add(contentType);
|
||||||
|
|
||||||
|
var apiResponsesCopy = new ApiResponses();
|
||||||
|
apiResponsesCopy.putAll(op.getResponses());
|
||||||
|
|
||||||
|
additionalOps.add(new Operation()
|
||||||
|
.deprecated(op.getDeprecated())
|
||||||
|
.callbacks(op.getCallbacks())
|
||||||
|
.description(op.getDescription())
|
||||||
|
.extensions(op.getExtensions() != null ? new LinkedHashMap<>(op.getExtensions()) : new LinkedHashMap<>())
|
||||||
|
.externalDocs(op.getExternalDocs())
|
||||||
|
.operationId(calcOperationId(path, httpMethod, op, operationIndexes))
|
||||||
|
.parameters(op.getParameters())
|
||||||
|
.responses(apiResponsesCopy)
|
||||||
|
.security(op.getSecurity())
|
||||||
|
.servers(op.getServers())
|
||||||
|
.summary(op.getSummary())
|
||||||
|
.tags(op.getTags())
|
||||||
|
.requestBody(new RequestBody()
|
||||||
|
.description(body.getDescription())
|
||||||
|
.extensions(body.getExtensions())
|
||||||
|
.content(new Content()
|
||||||
|
.addMediaType(contentType, mediaType))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!mediaTypesToRemove.isEmpty()) {
|
||||||
|
content.entrySet().removeIf(stringMediaTypeEntry -> mediaTypesToRemove.contains(stringMediaTypeEntry.getKey()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String calcOperationId(String path, PathItem.HttpMethod httpMethod, Operation op, Map<String, Integer> operationIndexes) {
|
||||||
|
var operationId = getOrGenerateOperationId(op, path, httpMethod.name());
|
||||||
|
var index = operationIndexes.get(operationId);
|
||||||
|
if (index != null) {
|
||||||
|
index++;
|
||||||
|
operationId += "_" + index;
|
||||||
|
operationIndexes.put(operationId, index);
|
||||||
|
} else {
|
||||||
|
operationIndexes.put(operationId, 0);
|
||||||
|
}
|
||||||
|
return operationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void divideOperationByResponses(
|
||||||
|
String path,
|
||||||
|
PathItem.HttpMethod httpMethod,
|
||||||
|
Operation op,
|
||||||
|
Map<String, ApiResponses> apiResponsesByContentType,
|
||||||
|
List<Operation> additionalOps,
|
||||||
|
List<String> addedContentTypes,
|
||||||
|
Map<String, Integer> operationIndexes
|
||||||
|
) {
|
||||||
|
|
||||||
|
if (!groupByResponseContentType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isFirst = true;
|
||||||
|
for (var entry : apiResponsesByContentType.entrySet()) {
|
||||||
|
var contentType = entry.getKey();
|
||||||
|
var apiResponses = entry.getValue();
|
||||||
|
var requestBody = op.getRequestBody();
|
||||||
|
// group by requestBody contentType
|
||||||
|
if (groupByRequestAndResponseContentType
|
||||||
|
&& requestBody != null
|
||||||
|
&& requestBody.getContent() != null
|
||||||
|
&& !requestBody.getContent().containsKey(contentType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addedContentTypes.add(contentType);
|
||||||
|
if (isFirst) {
|
||||||
|
op.setResponses(apiResponses);
|
||||||
|
isFirst = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
additionalOps.add(new Operation()
|
||||||
|
.deprecated(op.getDeprecated())
|
||||||
|
.callbacks(op.getCallbacks())
|
||||||
|
.description(op.getDescription())
|
||||||
|
.extensions(op.getExtensions())
|
||||||
|
.externalDocs(op.getExternalDocs())
|
||||||
|
.operationId(calcOperationId(path, httpMethod, op, operationIndexes))
|
||||||
|
.parameters(op.getParameters())
|
||||||
|
.responses(apiResponses)
|
||||||
|
.security(op.getSecurity())
|
||||||
|
.servers(op.getServers())
|
||||||
|
.summary(op.getSummary())
|
||||||
|
.tags(op.getTags())
|
||||||
|
.requestBody(requestBody)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendCommonResponseMediaTypes(Operation op, Collection<ApiResponses> commonResponsesList) {
|
||||||
|
if (commonResponsesList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var commonResponses : commonResponsesList) {
|
||||||
|
var adOpResponses = op.getResponses();
|
||||||
|
for (var responseEntry : adOpResponses.entrySet()) {
|
||||||
|
var content = responseEntry.getValue().getContent();
|
||||||
|
var commonResponse = commonResponses.get(responseEntry.getKey());
|
||||||
|
if (commonResponse != null && commonResponse.getContent() != null) {
|
||||||
|
if (content == null) {
|
||||||
|
content = new Content();
|
||||||
|
}
|
||||||
|
for (var commonResponseEntry : commonResponse.getContent().entrySet()) {
|
||||||
|
if (!content.containsKey(commonResponseEntry.getKey())) {
|
||||||
|
content.addMediaType(commonResponseEntry.getKey(), commonResponseEntry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// override with any special handling of the entire OpenAPI spec document
|
// override with any special handling of the entire OpenAPI spec document
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@ -1191,8 +1492,7 @@ public class DefaultCodegen implements CodegenConfig {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String escapeUnsafeCharacters(String input) {
|
public String escapeUnsafeCharacters(String input) {
|
||||||
LOGGER.warn("escapeUnsafeCharacters should be overridden in the code generator with proper logic to escape " +
|
LOGGER.warn("escapeUnsafeCharacters should be overridden in the code generator with proper logic to escape unsafe characters");
|
||||||
"unsafe characters");
|
|
||||||
// doing nothing by default and code generator should implement
|
// doing nothing by default and code generator should implement
|
||||||
// the logic to prevent code injection
|
// the logic to prevent code injection
|
||||||
// later we'll make this method abstract to make sure
|
// later we'll make this method abstract to make sure
|
||||||
@ -1208,8 +1508,7 @@ public class DefaultCodegen implements CodegenConfig {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String escapeQuotationMark(String input) {
|
public String escapeQuotationMark(String input) {
|
||||||
LOGGER.warn("escapeQuotationMark should be overridden in the code generator with proper logic to escape " +
|
LOGGER.warn("escapeQuotationMark should be overridden in the code generator with proper logic to escape single/double quote");
|
||||||
"single/double quote");
|
|
||||||
return input.replace("\"", "\\\"");
|
return input.replace("\"", "\\\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1782,6 +2081,12 @@ public class DefaultCodegen implements CodegenConfig {
|
|||||||
// option to change the order of form/body parameter
|
// option to change the order of form/body parameter
|
||||||
cliOptions.add(CliOption.newBoolean(CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS,
|
cliOptions.add(CliOption.newBoolean(CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS,
|
||||||
CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS_DESC).defaultValue(Boolean.FALSE.toString()));
|
CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS_DESC).defaultValue(Boolean.FALSE.toString()));
|
||||||
|
if (supportsDividingOperationsByContentType()) {
|
||||||
|
cliOptions.add(CliOption.newBoolean(CodegenConstants.GROUP_BY_RESPONSE_CONTENT_TYPE,
|
||||||
|
CodegenConstants.GROUP_BY_RESPONSE_CONTENT_TYPE_DESC).defaultValue(Boolean.TRUE.toString()));
|
||||||
|
cliOptions.add(CliOption.newBoolean(CodegenConstants.GROUP_BY_REQUEST_AND_RESPONSE_CONTENT_TYPE,
|
||||||
|
CodegenConstants.GROUP_BY_REQUEST_AND_RESPONSE_CONTENT_TYPE_DESC).defaultValue(Boolean.TRUE.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
// option to change how we process + set the data in the discriminator mapping
|
// option to change how we process + set the data in the discriminator mapping
|
||||||
CliOption legacyDiscriminatorBehaviorOpt = CliOption.newBoolean(CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR, CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR_DESC).defaultValue(Boolean.TRUE.toString());
|
CliOption legacyDiscriminatorBehaviorOpt = CliOption.newBoolean(CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR, CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR_DESC).defaultValue(Boolean.TRUE.toString());
|
||||||
@ -8591,11 +8896,16 @@ public class DefaultCodegen implements CodegenConfig {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
@Override
|
||||||
A function to convert yaml or json ingested strings like property names
|
public boolean supportsDividingOperationsByContentType() {
|
||||||
And convert special characters like newline, tab, carriage return
|
return false;
|
||||||
Into strings that can be rendered in the language that the generator will output to
|
}
|
||||||
*/
|
|
||||||
|
/**
|
||||||
|
* A function to convert yaml or json ingested strings like property names
|
||||||
|
* And convert special characters like newline, tab, carriage return
|
||||||
|
* Into strings that can be rendered in the language that the generator will output to
|
||||||
|
*/
|
||||||
protected String handleSpecialCharacters(String name) {
|
protected String handleSpecialCharacters(String name) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -606,10 +606,10 @@ public class DefaultGenerator implements Generator {
|
|||||||
if (!processedModels.contains(key) && allSchemas.containsKey(key)) {
|
if (!processedModels.contains(key) && allSchemas.containsKey(key)) {
|
||||||
generateModels(files, allModels, unusedModels, aliasModels, processedModels, () -> Set.of(key));
|
generateModels(files, allModels, unusedModels, aliasModels, processedModels, () -> Set.of(key));
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("Type " + variable.getComplexType() + " of variable " + variable.getName() + " could not be resolve because it is not declared as a model.");
|
LOGGER.info("Type {} of variable {} could not be resolve because it is not declared as a model.", variable.getComplexType(), variable.getName());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("Type " + variable.getOpenApiType() + " of variable " + variable.getName() + " could not be resolve because it is not declared as a model.");
|
LOGGER.info("Type {} of variable {} could not be resolve because it is not declared as a model.", variable.getComplexType(), variable.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,7 +1002,7 @@ public class DefaultGenerator implements Generator {
|
|||||||
File ignoreFile = new File(ignoreFileNameTarget);
|
File ignoreFile = new File(ignoreFileNameTarget);
|
||||||
// use the entries provided by the users to pre-populate .openapi-generator-ignore
|
// use the entries provided by the users to pre-populate .openapi-generator-ignore
|
||||||
try {
|
try {
|
||||||
LOGGER.info("Writing file " + ignoreFileNameTarget + " (which is always overwritten when the option `openapiGeneratorIgnoreFile` is enabled.)");
|
LOGGER.info("Writing file {} (which is always overwritten when the option `openapiGeneratorIgnoreFile` is enabled.)", ignoreFileNameTarget);
|
||||||
new File(config.outputFolder()).mkdirs();
|
new File(config.outputFolder()).mkdirs();
|
||||||
if (!ignoreFile.createNewFile()) {
|
if (!ignoreFile.createNewFile()) {
|
||||||
// file may already exist, do nothing
|
// file may already exist, do nothing
|
||||||
@ -1465,6 +1465,9 @@ public class DefaultGenerator implements Generator {
|
|||||||
if (paths == null) {
|
if (paths == null) {
|
||||||
return ops;
|
return ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var divideOperationsByContentType = config.supportsDividingOperationsByContentType();
|
||||||
|
|
||||||
for (Map.Entry<String, PathItem> pathsEntry : paths.entrySet()) {
|
for (Map.Entry<String, PathItem> pathsEntry : paths.entrySet()) {
|
||||||
String resourcePath = pathsEntry.getKey();
|
String resourcePath = pathsEntry.getKey();
|
||||||
PathItem path = pathsEntry.getValue();
|
PathItem path = pathsEntry.getValue();
|
||||||
@ -1476,11 +1479,35 @@ public class DefaultGenerator implements Generator {
|
|||||||
processOperation(resourcePath, "patch", path.getPatch(), ops, path);
|
processOperation(resourcePath, "patch", path.getPatch(), ops, path);
|
||||||
processOperation(resourcePath, "options", path.getOptions(), ops, path);
|
processOperation(resourcePath, "options", path.getOptions(), ops, path);
|
||||||
processOperation(resourcePath, "trace", path.getTrace(), ops, path);
|
processOperation(resourcePath, "trace", path.getTrace(), ops, path);
|
||||||
|
|
||||||
|
if (divideOperationsByContentType) {
|
||||||
|
processAdditionalOperations(resourcePath, "x-get", "get", ops, path);
|
||||||
|
processAdditionalOperations(resourcePath, "x-head", "head", ops, path);
|
||||||
|
processAdditionalOperations(resourcePath, "x-put", "put", ops, path);
|
||||||
|
processAdditionalOperations(resourcePath, "x-post", "post", ops, path);
|
||||||
|
processAdditionalOperations(resourcePath, "x-delete", "delete", ops, path);
|
||||||
|
processAdditionalOperations(resourcePath, "x-patch", "patch", ops, path);
|
||||||
|
processAdditionalOperations(resourcePath, "x-options", "options", ops, path);
|
||||||
|
processAdditionalOperations(resourcePath, "x-trace", "trace", ops, path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ops;
|
return ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, List<CodegenOperation>> processWebhooks(Map<String, PathItem> webhooks) {
|
protected void processAdditionalOperations(String resourcePath, String extName, String httpMethod, Map<String, List<CodegenOperation>> ops, PathItem path) {
|
||||||
|
if (path.getExtensions() == null || !path.getExtensions().containsKey(extName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var xOps = (List<Operation>) path.getExtensions().get(extName);
|
||||||
|
if (xOps == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Operation op : xOps) {
|
||||||
|
processOperation(resourcePath, httpMethod, op, ops, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<CodegenOperation>> processWebhooks(Map<String, PathItem> webhooks) {
|
||||||
Map<String, List<CodegenOperation>> ops = new TreeMap<>();
|
Map<String, List<CodegenOperation>> ops = new TreeMap<>();
|
||||||
// when input file is not valid and doesn't contain any paths
|
// when input file is not valid and doesn't contain any paths
|
||||||
if (webhooks == null) {
|
if (webhooks == null) {
|
||||||
|
@ -2461,4 +2461,9 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
|
|||||||
throw new RuntimeException(sb.toString());
|
throw new RuntimeException(sb.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsDividingOperationsByContentType() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import lombok.Setter;
|
|||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.openapitools.codegen.*;
|
import org.openapitools.codegen.*;
|
||||||
|
import org.openapitools.codegen.config.GlobalSettings;
|
||||||
import org.openapitools.codegen.model.ModelMap;
|
import org.openapitools.codegen.model.ModelMap;
|
||||||
import org.openapitools.codegen.model.ModelsMap;
|
import org.openapitools.codegen.model.ModelsMap;
|
||||||
import org.openapitools.codegen.templating.mustache.EscapeChar;
|
import org.openapitools.codegen.templating.mustache.EscapeChar;
|
||||||
@ -1157,4 +1158,9 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsDividingOperationsByContentType() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1004,7 +1004,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
|||||||
|
|
||||||
// add Pageable import only if x-spring-paginated explicitly used
|
// add Pageable import only if x-spring-paginated explicitly used
|
||||||
// this allows to use a custom Pageable schema without importing Spring Pageable.
|
// this allows to use a custom Pageable schema without importing Spring Pageable.
|
||||||
if (Boolean.TRUE.equals(operation.getExtensions().get("x-spring-paginated"))) {
|
if (operation.getExtensions() != null && Boolean.TRUE.equals(operation.getExtensions().get("x-spring-paginated"))) {
|
||||||
importMapping.put("Pageable", "org.springframework.data.domain.Pageable");
|
importMapping.put("Pageable", "org.springframework.data.domain.Pageable");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1093,7 +1093,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
|||||||
|
|
||||||
private Set<String> reformatProvideArgsParams(Operation operation) {
|
private Set<String> reformatProvideArgsParams(Operation operation) {
|
||||||
Set<String> provideArgsClassSet = new HashSet<>();
|
Set<String> provideArgsClassSet = new HashSet<>();
|
||||||
Object argObj = operation.getExtensions().get("x-spring-provide-args");
|
Object argObj = operation.getExtensions() != null ? operation.getExtensions().get("x-spring-provide-args") : null;
|
||||||
if (argObj instanceof List) {
|
if (argObj instanceof List) {
|
||||||
List<String> provideArgs = (List<String>) argObj;
|
List<String> provideArgs = (List<String>) argObj;
|
||||||
if (!provideArgs.isEmpty()) {
|
if (!provideArgs.isEmpty()) {
|
||||||
@ -1122,7 +1122,7 @@ public class SpringCodegen extends AbstractJavaCodegen
|
|||||||
formattedArgs.add(newArg);
|
formattedArgs.add(newArg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
operation.getExtensions().put("x-spring-provide-args", formattedArgs);
|
operation.addExtension("x-spring-provide-args", formattedArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return provideArgsClassSet;
|
return provideArgsClassSet;
|
||||||
|
@ -20,7 +20,6 @@ import static java.util.stream.Collectors.groupingBy;
|
|||||||
import static org.openapitools.codegen.TestUtils.newTempFolder;
|
import static org.openapitools.codegen.TestUtils.newTempFolder;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
public class JavaMicronautClientCodegenTest extends AbstractMicronautCodegenTest {
|
public class JavaMicronautClientCodegenTest extends AbstractMicronautCodegenTest {
|
||||||
@Test
|
@Test
|
||||||
public void clientOptsUnicity() {
|
public void clientOptsUnicity() {
|
||||||
@ -326,13 +325,13 @@ public class JavaMicronautClientCodegenTest extends AbstractMicronautCodegenTest
|
|||||||
public void shouldGenerateCorrectXmlAnnotations() {
|
public void shouldGenerateCorrectXmlAnnotations() {
|
||||||
// Arrange
|
// Arrange
|
||||||
final CodegenConfigurator config = new CodegenConfigurator()
|
final CodegenConfigurator config = new CodegenConfigurator()
|
||||||
.addAdditionalProperty(CodegenConstants.WITH_XML, true)
|
.addAdditionalProperty(CodegenConstants.WITH_XML, true)
|
||||||
.addGlobalProperty(CodegenConstants.MODELS, "Pet")
|
.addGlobalProperty(CodegenConstants.MODELS, "Pet")
|
||||||
.addGlobalProperty(CodegenConstants.MODEL_DOCS, null)
|
.addGlobalProperty(CodegenConstants.MODEL_DOCS, null)
|
||||||
.addGlobalProperty(CodegenConstants.MODEL_TESTS, null)
|
.addGlobalProperty(CodegenConstants.MODEL_TESTS, null)
|
||||||
.setGeneratorName(JavaMicronautClientCodegen.NAME)
|
.setGeneratorName(JavaMicronautClientCodegen.NAME)
|
||||||
.setInputSpec("src/test/resources/3_0/java/xml-annotations-test.yaml")
|
.setInputSpec("src/test/resources/3_0/java/xml-annotations-test.yaml")
|
||||||
.setOutputDir(newTempFolder().toString());
|
.setOutputDir(newTempFolder().toString());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
final List<File> files = new DefaultGenerator().opts(config.toClientOptInput()).generate();
|
final List<File> files = new DefaultGenerator().opts(config.toClientOptInput()).generate();
|
||||||
@ -457,4 +456,320 @@ public class JavaMicronautClientCodegenTest extends AbstractMicronautCodegenTest
|
|||||||
.hasAnnotation("JacksonXmlProperty", Map.of("localName", "\"item\""))
|
.hasAnnotation("JacksonXmlProperty", Map.of("localName", "\"item\""))
|
||||||
.hasAnnotation("JacksonXmlElementWrapper", Map.of("localName", "\"activities-array\""));
|
.hasAnnotation("JacksonXmlElementWrapper", Map.of("localName", "\"activities-array\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleContentTypesToPathTrueTrue() {
|
||||||
|
|
||||||
|
var codegen = new JavaMicronautClientCodegen();
|
||||||
|
codegen.setGroupByRequestAndResponseContentType(true);
|
||||||
|
codegen.setGroupByResponseContentType(true);
|
||||||
|
String outputPath = generateFiles(codegen, "src/test/resources/3_0/java/multiple-content-types.yaml", CodegenConstants.APIS, CodegenConstants.MODELS);
|
||||||
|
|
||||||
|
assertFileContains(outputPath + "/src/main/java/org/openapitools/api/DefaultApi.java",
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"application/json\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"application/xml\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_1(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\", \"application/xml\", \"text/json\"})\n" +
|
||||||
|
" @Produces({\"multipart/form-data\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_2(\n" +
|
||||||
|
" @Nullable @Valid Coordinates coordinates, \n" +
|
||||||
|
" @Nullable File _file\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"application/yaml\", \"text/json\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_3(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleContentTypesToPathTrueFalse() {
|
||||||
|
|
||||||
|
var codegen = new JavaMicronautClientCodegen();
|
||||||
|
codegen.setGroupByRequestAndResponseContentType(true);
|
||||||
|
codegen.setGroupByResponseContentType(false);
|
||||||
|
String outputPath = generateFiles(codegen, "src/test/resources/3_0/java/multiple-content-types.yaml", CodegenConstants.APIS, CodegenConstants.MODELS);
|
||||||
|
|
||||||
|
assertFileContains(outputPath + "/src/main/java/org/openapitools/api/DefaultApi.java",
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"application/json\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"application/xml\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_1(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\", \"application/xml\", \"text/json\"})\n" +
|
||||||
|
" @Produces({\"multipart/form-data\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_2(\n" +
|
||||||
|
" @Nullable @Valid Coordinates coordinates, \n" +
|
||||||
|
" @Nullable File _file\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\", \"application/xml\", \"text/json\"})\n" +
|
||||||
|
" @Produces({\"application/yaml\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_3(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"text/json\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_4(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleContentTypesToPathFalseTrue() {
|
||||||
|
|
||||||
|
var codegen = new JavaMicronautClientCodegen();
|
||||||
|
codegen.setGroupByRequestAndResponseContentType(false);
|
||||||
|
codegen.setGroupByResponseContentType(true);
|
||||||
|
String outputPath = generateFiles(codegen, "src/test/resources/3_0/java/multiple-content-types.yaml", CodegenConstants.APIS, CodegenConstants.MODELS);
|
||||||
|
|
||||||
|
assertFileContains(outputPath + "/src/main/java/org/openapitools/api/DefaultApi.java",
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"application/json\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"application/json\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_1(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"application/json\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_2(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"application/yaml\", \"text/json\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_3(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"application/xml\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_4(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"application/xml\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_5(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"application/xml\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_6(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"multipart/form-data\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_7(\n" +
|
||||||
|
" @Nullable @Valid Coordinates coordinates, \n" +
|
||||||
|
" @Nullable File _file\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"multipart/form-data\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_8(\n" +
|
||||||
|
" @Nullable @Valid Coordinates coordinates, \n" +
|
||||||
|
" @Nullable File _file\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"multipart/form-data\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_9(\n" +
|
||||||
|
" @Nullable @Valid Coordinates coordinates, \n" +
|
||||||
|
" @Nullable File _file\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"application/yaml\", \"text/json\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_10(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"application/yaml\", \"text/json\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_11(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleContentTypesToPathFalseFalse() {
|
||||||
|
|
||||||
|
var codegen = new JavaMicronautClientCodegen();
|
||||||
|
codegen.setGroupByRequestAndResponseContentType(false);
|
||||||
|
codegen.setGroupByResponseContentType(false);
|
||||||
|
String outputPath = generateFiles(codegen, "src/test/resources/3_0/java/multiple-content-types.yaml", CodegenConstants.APIS, CodegenConstants.MODELS);
|
||||||
|
|
||||||
|
assertFileContains(outputPath + "/src/main/java/org/openapitools/api/DefaultApi.java",
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"application/json\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"application/json\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_1(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"application/json\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_2(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"application/yaml\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_3(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"text/json\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_4(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"text/json\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_5(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"text/json\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_6(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"application/xml\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_7(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"application/xml\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_8(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"application/xml\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_9(\n" +
|
||||||
|
" @Body @Nullable @Valid Coordinates coordinates\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"multipart/form-data\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_10(\n" +
|
||||||
|
" @Nullable @Valid Coordinates coordinates, \n" +
|
||||||
|
" @Nullable File _file\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"multipart/form-data\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_11(\n" +
|
||||||
|
" @Nullable @Valid Coordinates coordinates, \n" +
|
||||||
|
" @Nullable File _file\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"text/json\"})\n" +
|
||||||
|
" @Produces({\"multipart/form-data\"})\n" +
|
||||||
|
" Mono<MySchema> myOp_12(\n" +
|
||||||
|
" @Nullable @Valid Coordinates coordinates, \n" +
|
||||||
|
" @Nullable File _file\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/xml\"})\n" +
|
||||||
|
" @Produces({\"application/yaml\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_13(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );",
|
||||||
|
|
||||||
|
" @Post(uri=\"/multiplecontentpath\")\n" +
|
||||||
|
" @Consumes({\"application/json\"})\n" +
|
||||||
|
" @Produces({\"application/yaml\"})\n" +
|
||||||
|
" Mono<Coordinates> myOp_14(\n" +
|
||||||
|
" @Body @Nullable @Valid MySchema mySchema\n" +
|
||||||
|
" );"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleContentTypesWithRefs() {
|
||||||
|
|
||||||
|
var codegen = new JavaMicronautClientCodegen();
|
||||||
|
codegen.setGroupByRequestAndResponseContentType(true);
|
||||||
|
codegen.setGroupByResponseContentType(true);
|
||||||
|
String outputPath = generateFiles(codegen, "src/test/resources/3_0/java/multiple-content-types-2.yaml", CodegenConstants.APIS, CodegenConstants.MODELS);
|
||||||
|
|
||||||
|
assertFileContains(outputPath + "/src/main/java/org/openapitools/api/DefaultApi.java",
|
||||||
|
""
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,4 +487,5 @@ public class JavaMicronautServerCodegenTest extends AbstractMicronautCodegenTest
|
|||||||
.hasAnnotation("JacksonXmlProperty", Map.of("localName", "\"item\""))
|
.hasAnnotation("JacksonXmlProperty", Map.of("localName", "\"item\""))
|
||||||
.hasAnnotation("JacksonXmlElementWrapper", Map.of("localName", "\"activities-array\""));
|
.hasAnnotation("JacksonXmlElementWrapper", Map.of("localName", "\"activities-array\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
openapi: 3.0.3
|
||||||
|
info:
|
||||||
|
version: "1"
|
||||||
|
title: Multiple Content Types for same request
|
||||||
|
paths:
|
||||||
|
/pet:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- pet
|
||||||
|
summary: Add a new pet to the store
|
||||||
|
description: ''
|
||||||
|
operationId: addPet
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
$ref: "#/components/responses/200"
|
||||||
|
'405':
|
||||||
|
description: Invalid input
|
||||||
|
security:
|
||||||
|
- petstore_auth:
|
||||||
|
- 'write:pets'
|
||||||
|
- 'read:pets'
|
||||||
|
requestBody:
|
||||||
|
$ref: '#/components/requestBodies/Pet'
|
||||||
|
components:
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: successful operation
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
application/yaml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/MySchema'
|
||||||
|
requestBodies:
|
||||||
|
Pet:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Pet'
|
||||||
|
text/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/MySchema'
|
||||||
|
description: Pet object that needs to be added to the store
|
||||||
|
required: true
|
||||||
|
schemas:
|
||||||
|
MySchema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
Pet:
|
||||||
|
title: a Pet
|
||||||
|
description: A pet for sale in the pet store
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- photoUrls
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example: doggie
|
@ -0,0 +1,67 @@
|
|||||||
|
openapi: 3.0.3
|
||||||
|
info:
|
||||||
|
version: "1"
|
||||||
|
title: Multiple Content Types for same request
|
||||||
|
paths:
|
||||||
|
/multiplecontentpath:
|
||||||
|
post:
|
||||||
|
operationId: myOp
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/coordinates'
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/coordinates'
|
||||||
|
multipart/form-data:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
coordinates:
|
||||||
|
$ref: '#/components/schemas/coordinates'
|
||||||
|
file:
|
||||||
|
type: string
|
||||||
|
format: binary
|
||||||
|
application/yaml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/MySchema'
|
||||||
|
text/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/MySchema'
|
||||||
|
responses:
|
||||||
|
201:
|
||||||
|
description: Successfully created
|
||||||
|
headers:
|
||||||
|
Location:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/coordinates'
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/coordinates'
|
||||||
|
text/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/MySchema'
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
coordinates:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- lat
|
||||||
|
- long
|
||||||
|
properties:
|
||||||
|
lat:
|
||||||
|
type: number
|
||||||
|
long:
|
||||||
|
type: number
|
||||||
|
MySchema:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- lat
|
||||||
|
properties:
|
||||||
|
lat:
|
||||||
|
type: number
|
Loading…
x
Reference in New Issue
Block a user