Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.languages;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.ComposedSchema;
import io.swagger.v3.oas.models.media.FileSchema;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.XML;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.servers.Server;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.utils.ModelUtils;
import org.openapitools.codegen.utils.URLPathUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.openapitools.codegen.utils.StringUtils.camelize;
import static org.openapitools.codegen.utils.StringUtils.underscore;
public class RustServerCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(RustServerCodegen.class);
private HashMap modelXmlNames = new HashMap();
private static final String NO_FORMAT = "%%NO_FORMAT";
protected String apiVersion = "1.0.0";
protected String serverHost = "localhost";
protected int serverPort = 8080;
protected String projectName = "openapi-server";
protected String apiPath = "rust-server";
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
protected String packageName;
protected String packageVersion;
protected String externCrateName;
protected Map> pathSetMap = new HashMap();
protected Map> callbacksPathSetMap = new HashMap();
private static final String uuidType = "uuid::Uuid";
private static final String bytesType = "swagger::ByteArray";
private static final String xmlMimeType = "application/xml";
private static final String textXmlMimeType = "text/xml";
private static final String octetMimeType = "application/octet-stream";
private static final String plainTextMimeType = "text/plain";
private static final String jsonMimeType = "application/json";
// RFC 7386 support
private static final String mergePatchJsonMimeType = "application/merge-patch+json";
// RFC 7807 Support
private static final String problemJsonMimeType = "application/problem+json";
private static final String problemXmlMimeType = "application/problem+xml";
public RustServerCodegen() {
super();
modifyFeatureSet(features -> features
.includeDocumentationFeatures(DocumentationFeature.Readme)
.wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON, WireFormatFeature.XML, WireFormatFeature.Custom))
.securityFeatures(EnumSet.of(
SecurityFeature.ApiKey,
SecurityFeature.BasicAuth,
SecurityFeature.BearerToken,
SecurityFeature.OAuth2_Implicit
))
.excludeGlobalFeatures(
GlobalFeature.LinkObjects,
GlobalFeature.ParameterStyling
)
.excludeSchemaSupportFeatures(
SchemaSupportFeature.Polymorphism
)
.excludeParameterFeatures(
ParameterFeature.Cookie
)
.includeClientModificationFeatures(
ClientModificationFeature.BasePath
)
);
// Show the generation timestamp by default
hideGenerationTimestamp = Boolean.FALSE;
// set the output folder here
outputFolder = "generated-code/rust-server";
/*
* Models. You can write model files using the modelTemplateFiles map.
* if you want to create one template for file, you can do so here.
* for multiple files for model, just put another entry in the `modelTemplateFiles` with
* a different extension
*/
modelTemplateFiles.clear();
/*
* Api classes. You can write classes for each Api file with the apiTemplateFiles map.
* as with models, add multiple entries with different extensions for multiple files per
* class
*/
apiTemplateFiles.clear();
modelDocTemplateFiles.put("model_doc.mustache", ".md");
apiDocTemplateFiles.put("api_doc.mustache", ".md");
/*
* Template Location. This is the location which templates will be read from. The generator
* will use the resource stream to attempt to read the templates.
*/
embeddedTemplateDir = templateDir = "rust-server";
/*
* Reserved words. Override this with reserved words specific to your language
*/
setReservedWordsLowerCase(
Arrays.asList(
// From https://doc.rust-lang.org/grammar.html#keywords
"abstract", "alignof", "as", "become", "box", "break", "const",
"continue", "crate", "do", "else", "enum", "extern", "false",
"final", "fn", "for", "if", "impl", "in", "let", "loop", "macro",
"match", "mod", "move", "mut", "offsetof", "override", "priv",
"proc", "pub", "pure", "ref", "return", "Self", "self", "sizeof",
"static", "struct", "super", "trait", "true", "type", "typeof",
"unsafe", "unsized", "use", "virtual", "where", "while", "yield"
)
);
defaultIncludes = new HashSet(
Arrays.asList(
"map",
"array")
);
languageSpecificPrimitives = new HashSet(
Arrays.asList(
"bool",
"char",
"i8",
"i16",
"i32",
"i64",
"u8",
"u16",
"u32",
"u64",
"isize",
"usize",
"f32",
"f64",
"str",
"String")
);
instantiationTypes.clear();
instantiationTypes.put("array", "Vec");
instantiationTypes.put("map", "std::collections::HashMap");
typeMapping.clear();
typeMapping.put("number", "f64");
typeMapping.put("integer", "i32");
typeMapping.put("long", "i64");
typeMapping.put("float", "f32");
typeMapping.put("double", "f64");
typeMapping.put("string", "String");
typeMapping.put("UUID", uuidType);
typeMapping.put("URI", "String");
typeMapping.put("byte", "u8");
typeMapping.put("ByteArray", bytesType);
typeMapping.put("binary", bytesType);
typeMapping.put("boolean", "bool");
typeMapping.put("date", "chrono::DateTime::");
typeMapping.put("DateTime", "chrono::DateTime::");
typeMapping.put("password", "String");
typeMapping.put("File", bytesType);
typeMapping.put("file", bytesType);
typeMapping.put("array", "Vec");
typeMapping.put("map", "std::collections::HashMap");
typeMapping.put("object", "serde_json::Value");
typeMapping.put("AnyType", "serde_json::Value");
importMapping = new HashMap();
cliOptions.clear();
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME,
"Rust crate name (convention: snake_case).")
.defaultValue("openapi_client"));
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_VERSION,
"Rust crate version."));
/*
* Additional Properties. These values can be passed to the templates and
* are available in models, apis, and supporting files
*/
additionalProperties.put("apiVersion", apiVersion);
additionalProperties.put("apiPath", apiPath);
/*
* Supporting Files. You can write single files for the generator with the
* entire object tree available. If the input file has a suffix of `.mustache
* it will be processed by the template engine. Otherwise, it will be copied
*/
supportingFiles.add(new SupportingFile("openapi.mustache", "api", "openapi.yaml"));
supportingFiles.add(new SupportingFile("Cargo.mustache", "", "Cargo.toml"));
supportingFiles.add(new SupportingFile("cargo-config", ".cargo", "config"));
supportingFiles.add(new SupportingFile("gitignore", "", ".gitignore"));
supportingFiles.add(new SupportingFile("lib.mustache", "src", "lib.rs"));
supportingFiles.add(new SupportingFile("context.mustache", "src", "context.rs"));
supportingFiles.add(new SupportingFile("models.mustache", "src", "models.rs"));
supportingFiles.add(new SupportingFile("header.mustache", "src", "header.rs"));
supportingFiles.add(new SupportingFile("server-mod.mustache", "src/server", "mod.rs"));
supportingFiles.add(new SupportingFile("client-mod.mustache", "src/client", "mod.rs"));
supportingFiles.add(new SupportingFile("example-server-main.mustache", "examples/server", "main.rs"));
supportingFiles.add(new SupportingFile("example-server-server.mustache", "examples/server", "server.rs"));
supportingFiles.add(new SupportingFile("example-client-main.mustache", "examples/client", "main.rs"));
supportingFiles.add(new SupportingFile("example-ca.pem", "examples", "ca.pem"));
supportingFiles.add(new SupportingFile("example-server-chain.pem", "examples", "server-chain.pem"));
supportingFiles.add(new SupportingFile("example-server-key.pem", "examples", "server-key.pem"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")
.doNotOverwrite());
}
@Override
public void processOpts() {
super.processOpts();
if (StringUtils.isEmpty(System.getenv("RUST_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable RUST_POST_PROCESS_FILE not defined. rustfmt will be used" +
" by default. To choose a different tool, try" +
" 'export RUST_POST_PROCESS_FILE=\"/usr/local/bin/rustfmt\"' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` " +
" (--enable-post-process-file for CLI).");
}
if (!Boolean.TRUE.equals(ModelUtils.isGenerateAliasAsModel())) {
LOGGER.warn("generateAliasAsModel is set to false, which means array/map will be generated as model instead and the resulting code may have issues. Please enable `generateAliasAsModel` to address the issue.");
}
setPackageName((String) additionalProperties.getOrDefault(CodegenConstants.PACKAGE_NAME, "openapi_client"));
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_VERSION)) {
setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION));
}
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
additionalProperties.put("externCrateName", externCrateName);
}
public void setPackageName(String packageName) {
this.packageName = packageName;
// Also set the extern crate name, which has any '-' replace with a '_'.
this.externCrateName = packageName.replace('-', '_');
}
public void setPackageVersion(String packageVersion) {
this.packageVersion = packageVersion;
}
@Override
public String apiPackage() {
return apiPath;
}
/**
* Configures the type of generator.
*
* @return the CodegenType for this generator
* @see org.openapitools.codegen.CodegenType
*/
@Override
public CodegenType getTag() {
return CodegenType.SERVER;
}
/**
* Configures a friendly name for the generator. This will be used by the generator
* to select the library with the -g flag.
*
* @return the friendly name for the generator
*/
@Override
public String getName() {
return "rust-server";
}
/**
* Returns human-friendly help for the generator. Provide the consumer with help
* tips, parameters here
*
* @return A string value for the help message
*/
@Override
public String getHelp() {
return "Generates a Rust client/server library (beta) using the openapi-generator project.";
}
@Override
public void preprocessOpenAPI(OpenAPI openAPI) {
Info info = openAPI.getInfo();
URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
additionalProperties.put("serverHost", url.getHost());
additionalProperties.put("serverPort", URLPathUtils.getPort(url, serverPort));
if (packageVersion == null || "".equals(packageVersion)) {
List versionComponents = new ArrayList<>(Arrays.asList(info.getVersion().split("[.]")));
if (versionComponents.size() < 1) {
versionComponents.add("1");
}
while (versionComponents.size() < 3) {
versionComponents.add("0");
}
setPackageVersion(StringUtils.join(versionComponents, "."));
}
additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);
}
@Override
public String toApiName(String name) {
if (name.isEmpty()) {
return "default";
}
return underscore(name);
}
/**
* Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
* those terms here. This logic is only called if a variable matches the reserved words
*
* @return the escaped term
*/
@Override
public String escapeReservedWord(String name) {
if (this.reservedWordsMappings().containsKey(name)) {
return this.reservedWordsMappings().get(name);
}
return name + "_"; // add an underscore _suffix_ to the name - a prefix implies unused
}
/**
* Location to write api files. You can use the apiPackage() as defined when the class is
* instantiated
*/
@Override
public String apiFileFolder() {
return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar);
}
@Override
public String toModelName(String name) {
// camelize the model name
// phone_number => PhoneNumber
String camelizedName = camelize(toModelFilename(name));
// model name cannot use reserved keyword, e.g. return
if (isReservedWord(camelizedName)) {
camelizedName = "Model" + camelizedName;
LOGGER.warn(camelizedName + " (reserved word) cannot be used as model name. Renamed to " + camelizedName);
}
// model name starts with number
else if (camelizedName.matches("^\\d.*")) {
// e.g. 200Response => Model200Response (after camelize)
camelizedName = "Model" + camelizedName;
LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + camelizedName);
}
return camelizedName;
}
@Override
public String toParamName(String name) {
// should be the same as variable name (stolen from RubyClientCodegen)
return toVarName(name);
}
@Override
public String toVarName(String name) {
String sanitizedName = super.sanitizeName(name);
// for reserved word, append _
if (isReservedWord(sanitizedName)) {
sanitizedName = escapeReservedWord(sanitizedName);
}
// for word starting with number, prepend "param_"
else if (sanitizedName.matches("^\\d.*")) {
sanitizedName = "param_" + sanitizedName;
}
return underscore(sanitizedName);
}
@Override
public String toOperationId(String operationId) {
// method name cannot use reserved keyword, e.g. return
if (isReservedWord(operationId)) {
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + camelize("call_" + operationId));
operationId = "call_" + operationId;
} else if (operationId.matches("\\d.*")) {
LOGGER.warn(operationId + " cannot be used as method name because it starts with a digit. Renamed to " + camelize("call_" + operationId));
operationId = "call_" + operationId;
}
return camelize(operationId);
}
@Override
public String toModelFilename(String name) {
if (!StringUtils.isEmpty(modelNamePrefix)) {
name = modelNamePrefix + "_" + name;
}
if (!StringUtils.isEmpty(modelNameSuffix)) {
name = name + "_" + modelNameSuffix;
}
name = sanitizeName(name);
// model name cannot use reserved keyword, e.g. return
if (isReservedWord(name)) {
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + name));
name = "model_" + name; // e.g. return => ModelReturn (after camelize)
}
return underscore(name);
}
@Override
public String toEnumName(CodegenProperty property) {
return sanitizeName(camelize(property.name)) + "Enum";
}
@Override
public String toEnumVarName(String value, String datatype) {
String var = null;
if (value.isEmpty()) {
var = "EMPTY";
}
// for symbol, e.g. $, #
else if (getSymbolName(value) != null) {
var = getSymbolName(value).toUpperCase(Locale.ROOT);
}
// number
else if ("Integer".equals(datatype) || "Long".equals(datatype) ||
"Float".equals(datatype) || "Double".equals(datatype)) {
String varName = "NUMBER_" + value;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
varName = varName.replaceAll("\\.", "_DOT_");
var = varName;
}
// string
else {
var = value.replaceAll("\\W+", "_").toUpperCase(Locale.ROOT);
if (var.matches("\\d.*")) {
var = "_" + var;
} else {
var = sanitizeName(var);
}
}
return var;
}
@Override
public String toEnumValue(String value, String datatype) {
if ("Integer".equals(datatype) || "Long".equals(datatype) ||
"Float".equals(datatype) || "Double".equals(datatype)) {
return value;
} else {
return "\"" + escapeText(value) + "\"";
}
}
@Override
public String toApiFilename(String name) {
// replace - with _ e.g. created-at => created_at
name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
// e.g. PetApi.go => pet_api.go
return underscore(name);
}
@Override
public String apiDocFileFolder() {
return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar);
}
@Override
public String modelDocFileFolder() {
return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar);
}
@Override
public String toModelDocFilename(String name) {
return toModelName(name);
}
@Override
public String toApiDocFilename(String name) {
return toApiName(name) + "_api";
}
@Override
public String escapeQuotationMark(String input) {
// remove " to avoid code injection
return input.replace("\"", "");
}
@Override
public String escapeUnsafeCharacters(String input) {
return input.replace("*/", "*_/").replace("/*", "/_*");
}
private boolean isMimetypeXml(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith(xmlMimeType) ||
mimetype.toLowerCase(Locale.ROOT).startsWith(problemXmlMimeType) ||
mimetype.toLowerCase(Locale.ROOT).startsWith(textXmlMimeType);
}
private boolean isMimetypeJson(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith(jsonMimeType) ||
mimetype.toLowerCase(Locale.ROOT).startsWith(mergePatchJsonMimeType) ||
mimetype.toLowerCase(Locale.ROOT).startsWith(problemJsonMimeType);
}
private boolean isMimetypeWwwFormUrlEncoded(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith("application/x-www-form-urlencoded");
}
private boolean isMimetypeMultipartFormData(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith("multipart/form-data");
}
private boolean isMimetypeOctetStream(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith(octetMimeType);
}
private boolean isMimetypeMultipartRelated(String mimetype) {
return mimetype.toLowerCase(Locale.ROOT).startsWith("multipart/related");
}
private boolean isMimetypeUnknown(String mimetype) {
return mimetype.equals("*/*");
}
/**
* Do we have any special handling for this mimetype?
*/
boolean isMimetypePlain(String mimetype) {
boolean result = !(isMimetypeUnknown(mimetype) ||
isMimetypeXml(mimetype) ||
isMimetypeJson(mimetype) ||
isMimetypeWwwFormUrlEncoded(mimetype) ||
isMimetypeMultipartFormData(mimetype) ||
isMimetypeMultipartRelated(mimetype));
return result;
}
private String tidyUpRuntimeCallbackParam(String param) {
return underscore(param.replace("-", "_").replace(".", "_").replace("{", "").replace("#", "_").replace("/", "_").replace("}", "").replace("$", "").replaceAll("_+", "_"));
}
@Override
public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List servers) {
Map definitions = ModelUtils.getSchemas(this.openAPI);
CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers);
String pathFormatString = op.path;
for (CodegenParameter param : op.pathParams) {
// Replace {baseName} with {paramName} for format string
String paramSearch = "{" + param.baseName + "}";
String paramReplace = "{" + param.paramName + "}";
pathFormatString = pathFormatString.replace(paramSearch, paramReplace);
}
op.vendorExtensions.put("x-path-format-string", pathFormatString);
// The Rust code will need to contain a series of regular expressions.
// For performance, we'll construct these at start-of-day and re-use
// them. That means we need labels for them.
//
// Construct a Rust constant (uppercase) token name, and ensure it's
// unique using a numeric tie-breaker if required.
String basePathId = sanitizeName(op.path.replace("/", "_").replace("{", "").replace("}", "").replaceAll("^_", "")).toUpperCase(Locale.ROOT);
String pathId = basePathId;
int pathIdTiebreaker = 2;
boolean found = false;
Map> pathSetMap;
// The callback API is logically distinct from the main API, so
// it uses a separate path set map.
if (op.isCallbackRequest) {
pathSetMap = this.callbacksPathSetMap;
} else {
pathSetMap = this.pathSetMap;
}
while (pathSetMap.containsKey(pathId)) {
Map pathSetEntry = pathSetMap.get(pathId);
if (pathSetEntry.get("path").equals(op.path)) {
found = true;
break;
}
pathId = basePathId + pathIdTiebreaker;
pathIdTiebreaker++;
}
boolean hasPathParams = !op.pathParams.isEmpty();
// String for matching for path using a regex
// Don't prefix with '^' so that the templates can put the
// basePath on the front.
String regex = op.path;
// String for formatting the path for a client to make a request
String formatPath = op.path;
for (CodegenParameter param : op.pathParams) {
// Replace {baseName} with {paramName} for format string
String paramSearch = "{" + param.baseName + "}";
String paramReplace = "{" + param.paramName + "}";
formatPath = formatPath.replace(paramSearch, paramReplace);
}
// Handle runtime callback parameters. Runtime callback parameters
// are different from regular path parameters:
// - They begin with a "{$" sequence, which allows us to identify them.
// - They can contain multiple path segments, so we need to use a different
// regular expression.
// - They may contain special characters such as "#", "." and "/" which aren't
// valid in Rust identifiers.
// In the future, we may support parsing them directly
if (op.isCallbackRequest) {
formatPath = formatPath.substring(1); // Callback paths are absolute so strip initial '/'
List params = new ArrayList();
Matcher match = Pattern.compile("\\{\\$[^}{]*\\}").matcher(op.path);
while (match.find()) {
String param = match.group();
// Convert to a rust variable name
String rustParam = tidyUpRuntimeCallbackParam(param);
params.add(rustParam);
// Convert to a format arg
String formatParam = "{" + rustParam + "}";
formatPath = formatPath.replace(param, formatParam);
// Convert to a regex
String newParam = "(?P<" + rustParam + ">.*)";
regex = regex.replace(param, newParam);
hasPathParams = true;
}
op.vendorExtensions.put("x-callback-params", params);
}
// Save off the regular expression and path details in the relevant
// "pathSetMap", which we'll add to the source document that will be
// processed by the templates.
if (!found) {
Map pathSetEntry = new HashMap();
pathSetEntry.put("path", op.path);
pathSetEntry.put("PATH_ID", pathId);
if (hasPathParams) {
pathSetEntry.put("hasPathParams", "true");
}
// Don't prefix with '^' so that the templates can put the
// basePath on the front.
for (CodegenParameter param : op.pathParams) {
// Replace {baseName} with (?P[^/?#]*) for regex
String paramSearch = "{" + param.baseName + "}";
String paramReplace = "(?P<" + param.baseName + ">[^/?#]*)";
regex = regex.replace(paramSearch, paramReplace);
}
pathSetEntry.put("pathRegEx", regex + "$");
pathSetMap.put(pathId, pathSetEntry);
}
String underscoredOperationId = underscore(op.operationId);
op.vendorExtensions.put("x-operation-id", underscoredOperationId);
op.vendorExtensions.put("x-uppercase-operation-id", underscoredOperationId.toUpperCase(Locale.ROOT));
String vendorExtensionPath = op.path.replace("{", ":").replace("}", "");
op.vendorExtensions.put("x-path", vendorExtensionPath);
op.vendorExtensions.put("x-path-id", pathId);
op.vendorExtensions.put("x-has-path-params", hasPathParams);
op.vendorExtensions.put("x-path-format-string", formatPath);
String vendorExtensionHttpMethod = op.httpMethod.toUpperCase(Locale.ROOT);
op.vendorExtensions.put("x-http-method", vendorExtensionHttpMethod);
if (!op.vendorExtensions.containsKey("x-must-use-response")) {
// If there's more than one response, than by default the user must explicitly handle them
op.vendorExtensions.put("x-must-use-response", op.responses.size() > 1);
}
for (CodegenParameter param : op.allParams) {
processParam(param, op);
}
// We keep track of the 'default' model type for this API. If there are
// *any* XML responses, then we set the default to XML, otherwise we
// let the default be JSON. It would be odd for an API to want to use
// both XML and JSON on a single operation, and if we don't know
// anything then JSON is a more modern (ergo reasonable) choice.
boolean defaultsToXml = false;
// Determine the types that this operation produces. `getProducesInfo`
// simply lists all the types, and then we add the correct imports to
// the generated library.
List produces = new ArrayList(getProducesInfo(openAPI, operation));
boolean producesXml = false;
boolean producesPlainText = false;
if (produces != null && !produces.isEmpty()) {
List