Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
* If a query parameter should be serialized as json
*/
public boolean queryIsJsonMimeType;
/**
* True when a header parameter uses a JSON media type in Parameter.content.
*/
public boolean headerIsJsonMimeType;
/**
* datatype is the generic inner parameter of a std::optional for C++, or Optional (Java)
*/
Expand Down Expand Up @@ -270,6 +274,7 @@ public CodegenParameter copy() {
output.isArray = this.isArray;
output.isMap = this.isMap;
output.queryIsJsonMimeType = this.queryIsJsonMimeType;
output.headerIsJsonMimeType = this.headerIsJsonMimeType;
output.isOptional = this.isOptional;
output.isExplode = this.isExplode;
output.style = this.style;
Expand All @@ -294,15 +299,15 @@ public int hashCode() {
isFormStyle, isSpaceDelimited, isPipeDelimited,
jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal,
isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isPassword,
isFreeFormObject, isAnyType, isArray, isMap, queryIsJsonMimeType, isOptional, isFile, isEnum, isEnumRef, _enum, allowableValues,
items, mostInnerItems, additionalProperties, vars, requiredVars, vendorExtensions, hasValidation,
getMaxProperties(), getMinProperties(), isNullable, isDeprecated, required, getMaximum(),
getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(), getMaxLength(), getMinLength(),
getPattern(), getMaxItems(), getMinItems(), getUniqueItems(), contentType, multipleOf, isNull, isVoid,
additionalPropertiesIsAnyType, hasVars, hasRequired, isShort, isUnboundedInteger,
hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes, schema, content,
requiredVarsMap, ref, uniqueItemsBoolean, schemaIsFromAdditionalProperties,
nameInPascalCase, nameInCamelCase, nameInLowerCase, nameInSnakeCase);
isFreeFormObject, isAnyType, isArray, isMap, queryIsJsonMimeType, headerIsJsonMimeType, isOptional,
isFile, isEnum, isEnumRef, _enum, allowableValues, items, mostInnerItems, additionalProperties, vars,
requiredVars, vendorExtensions, hasValidation, getMaxProperties(), getMinProperties(), isNullable,
isDeprecated, required, getMaximum(), getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(),
getMaxLength(), getMinLength(), getPattern(), getMaxItems(), getMinItems(), getUniqueItems(),
contentType, multipleOf, isNull, isVoid, additionalPropertiesIsAnyType, hasVars, hasRequired, isShort,
isUnboundedInteger, hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes, schema,
content, requiredVarsMap, ref, uniqueItemsBoolean, schemaIsFromAdditionalProperties, nameInPascalCase,
nameInCamelCase, nameInLowerCase, nameInSnakeCase);
}

@Override
Expand Down Expand Up @@ -345,6 +350,7 @@ public boolean equals(Object o) {
isArray == that.isArray &&
isMap == that.isMap &&
queryIsJsonMimeType == that.queryIsJsonMimeType &&
headerIsJsonMimeType == that.headerIsJsonMimeType &&
isOptional == that.isOptional &&
isFile == that.isFile &&
isEnum == that.isEnum &&
Expand Down Expand Up @@ -486,6 +492,7 @@ public String toString() {
sb.append(", isArray=").append(isArray);
sb.append(", isMap=").append(isMap);
sb.append(", queryIsJsonMimeType=").append(queryIsJsonMimeType);
sb.append(", headerIsJsonMimeType=").append(headerIsJsonMimeType);
sb.append(", isOptional=").append(isOptional);
sb.append(", isFile=").append(isFile);
sb.append(", isEnum=").append(isEnum);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5722,6 +5722,8 @@ public CodegenParameter fromParameter(Parameter parameter, Set<String> imports)
codegenParameter.isPathParam = true;
} else if (parameter instanceof HeaderParameter || "header".equalsIgnoreCase(parameter.getIn())) {
codegenParameter.isHeaderParam = true;
codegenParameter.headerIsJsonMimeType = isJsonMimeType(codegenParameter.contentType)
|| isJsonVendorMimeType(codegenParameter.contentType);
} else if (parameter instanceof CookieParameter || "cookie".equalsIgnoreCase(parameter.getIn())) {
codegenParameter.isCookieParam = true;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@

import com.google.common.collect.ImmutableMap;
import com.samskivert.mustache.Mustache;
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.Schema;
import io.swagger.v3.oas.models.parameters.HeaderParameter;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
Expand All @@ -34,6 +37,7 @@
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.ModelsMap;
import org.openapitools.codegen.model.OperationsMap;
import org.openapitools.codegen.model.WebhooksMap;
import org.openapitools.codegen.templating.mustache.IndentedLambda;
import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger;
Expand Down Expand Up @@ -355,6 +359,7 @@ public void processOpts() {
if (!withoutRuntimeChecks) {
this.modelTemplateFiles.put("models.mustache", ".ts");
}
additionalProperties.put("modelSerializersEnabled", !withoutRuntimeChecks);

// `date` needs the model (de)serialization to convert with, which
// withoutRuntimeChecks removes: the raw string would just be cast to Date.
Expand Down Expand Up @@ -708,7 +713,81 @@ public List<CodegenParameter> fromRequestBodyToFormParameters(RequestBody body,
@Override
public ExtendedCodegenParameter fromParameter(Parameter parameter, Set<String> imports) {
CodegenParameter cp = super.fromParameter(parameter, imports);
return new ExtendedCodegenParameter(cp);
ExtendedCodegenParameter result = new ExtendedCodegenParameter(cp);
Parameter resolvedParameter = ModelUtils.getReferencedParameter(openAPI, parameter);
result.jsonHeaderUsesModelSerializer = cp.headerIsJsonMimeType && cp.isModel
&& hasGeneratedModelHeaderSchema(openAPI, resolvedParameter);
return result;
}

@Override
public void processOpenAPI(OpenAPI openAPI) {
super.processOpenAPI(openAPI);
if (!withoutRuntimeChecks) {
return;
}
if (openAPI.getPaths() != null) {
for (PathItem path : openAPI.getPaths().values()) {
if (hasJsonContentModelHeader(openAPI, path)) {
enableJsonHeaderModelSerializers();
return;
}
}
}
if (openAPI.getWebhooks() != null) {
for (PathItem webhook : openAPI.getWebhooks().values()) {
if (hasJsonContentModelHeader(openAPI, webhook)) {
enableJsonHeaderModelSerializers();
return;
}
}
}
}

private boolean hasJsonContentModelHeader(OpenAPI openAPI, PathItem path) {
if (hasJsonContentModelHeader(openAPI, path.getParameters())) {
return true;
}
for (Operation operation : path.readOperations()) {
if (hasJsonContentModelHeader(openAPI, operation.getParameters())) {
return true;
}
}
return false;
}

private boolean hasJsonContentModelHeader(OpenAPI openAPI, List<Parameter> parameters) {
return parameters != null && parameters.stream()
.map(parameter -> ModelUtils.getReferencedParameter(openAPI, parameter))
.anyMatch(parameter -> isJsonContentHeader(parameter)
&& hasGeneratedModelHeaderSchema(openAPI, parameter));
}

private boolean isJsonContentHeader(Parameter parameter) {
if (parameter == null
|| !(parameter instanceof HeaderParameter || "header".equalsIgnoreCase(parameter.getIn()))
|| parameter.getSchema() != null
|| parameter.getContent() == null
|| parameter.getContent().isEmpty()) {
return false;
}
String contentType = parameter.getContent().keySet().iterator().next();
return isJsonMimeType(contentType) || isJsonVendorMimeType(contentType);
}

private boolean hasGeneratedModelHeaderSchema(OpenAPI openAPI, Parameter parameter) {
if (parameter.getContent() == null || parameter.getContent().isEmpty()) {
return false;
}
Schema schema = parameter.getContent().values().iterator().next().getSchema();
return schema != null && schema.get$ref() != null
&& ModelUtils.isModel(ModelUtils.getReferencedSchema(openAPI, schema));
}

private void enableJsonHeaderModelSerializers() {
modelTemplateFiles.put("models.mustache", ".ts");
additionalProperties.put("jsonHeaderModelSerializers", true);
additionalProperties.put("modelSerializersEnabled", true);
}

@Override
Expand Down Expand Up @@ -875,6 +954,20 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap operations, L
return operations;
}

@Override
public WebhooksMap postProcessWebhooksWithModels(WebhooksMap webhooks, List<ModelMap> allModels) {
if (webhooks.getWebhooks().getOperation().stream()
.anyMatch(operation -> operation.headerParams != null && operation.headerParams.stream()
.anyMatch(parameter -> ((ExtendedCodegenParameter) parameter).jsonHeaderUsesModelSerializer))) {
for (Map<String, String> im : webhooks.getImports()) {
String className = im.get("import").replace(modelPackage() + ".", "");
im.put("className", className);
im.put("classFileName", convertUsingFileNamingConvention(className));
}
}
return webhooks;
}

@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
Map<String, Object> parentObjs = super.postProcessSupportingFileData(objs);
Expand Down Expand Up @@ -1539,6 +1632,7 @@ private static String getItemsDataType(CodegenProperty items) {

public class ExtendedCodegenParameter extends CodegenParameter {
public String dataTypeAlternate;
public boolean jsonHeaderUsesModelSerializer;
public boolean isUniqueId; // this parameter represents a unique id (x-isUniqueId: true)
public List<CodegenProperty> readOnlyVars; // a list of read-only properties
public boolean hasReadOnly = false; // indicates the type has at least one read-only property
Expand Down Expand Up @@ -1567,6 +1661,7 @@ public ExtendedCodegenParameter(CodegenParameter cp) {
this.isQueryParam = cp.isQueryParam;
this.isPathParam = cp.isPathParam;
this.isHeaderParam = cp.isHeaderParam;
this.headerIsJsonMimeType = cp.headerIsJsonMimeType;
this.isCookieParam = cp.isCookieParam;
this.isBodyParam = cp.isBodyParam;
this.isContainer = cp.isContainer;
Expand Down Expand Up @@ -1655,6 +1750,7 @@ public ExtendedCodegenParameter copy() {
CodegenParameter superCopy = super.copy();
ExtendedCodegenParameter output = new ExtendedCodegenParameter(superCopy);
output.dataTypeAlternate = this.dataTypeAlternate;
output.jsonHeaderUsesModelSerializer = this.jsonHeaderUsesModelSerializer;
output.isUniqueId = this.isUniqueId;
return output;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import type {
{{className}},
{{/imports}}
} from '../models/index{{importFileExtension}}';
{{#jsonHeaderModelSerializers}}
{{#imports}}
import { {{className}}ToJSON } from '../models/{{classFileName}}{{importFileExtension}}';
{{/imports}}
{{/jsonHeaderModelSerializers}}
{{/withoutRuntimeChecks}}
{{^withoutRuntimeChecks}}
{{#imports}}
Expand Down Expand Up @@ -250,6 +255,15 @@ export class {{classname}} extends runtime.BaseAPI {
{{/bodyParam}}
{{/hasContentTypeRequestVariants}}
{{#headerParams}}
{{#headerIsJsonMimeType}}
{{#jsonHeaderUsesModelSerializer}}
if (requestParameters['{{paramName}}'] !== undefined) {
headerParameters['{{baseName}}'] = JSON.stringify({{dataType}}ToJSON(requestParameters['{{paramName}}']));
}

{{/jsonHeaderUsesModelSerializer}}
{{/headerIsJsonMimeType}}
{{^jsonHeaderUsesModelSerializer}}
{{#isArray}}
if (requestParameters['{{paramName}}'] != null) {
headerParameters['{{baseName}}'] = {{#uniqueItems}}Array.from({{/uniqueItems}}requestParameters['{{paramName}}']{{#uniqueItems}}){{/uniqueItems}}!.join(runtime.COLLECTION_FORMATS["{{collectionFormat}}"]);
Expand All @@ -262,6 +276,7 @@ export class {{classname}} extends runtime.BaseAPI {
}

{{/isArray}}
{{/jsonHeaderUsesModelSerializer}}
{{/headerParams}}
{{#authMethods}}
{{#isBasic}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ export function parseDateTime(value: any): Date {
{{/isDateLibraryDate}}
{{/isDateLibraryTemporal}}

{{^withoutRuntimeChecks}}
{{#modelSerializersEnabled}}
export function mapValues(data: any, fn: (item: any) => any) {
const result: { [key: string]: any } = {};
for (const key of Object.keys(data)) {
Expand All @@ -465,7 +465,7 @@ export function mapValues(data: any, fn: (item: any) => any) {
export function anyToJSON(value: any): any {
return value;
}
{{/withoutRuntimeChecks}}
{{/modelSerializersEnabled}}

export function canConsumeForm(consumes: Consume[]): boolean {
for (const consume of consumes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,14 @@ export class {{classname}} {

{{/queryParams}}
{{#headerParams}}
{{#headerIsJsonMimeType}}
if ({{paramName}} !== undefined) {
Comment thread
AndreyVMarkelov marked this conversation as resolved.
localVarHeaderParams['{{baseName}}'] = JSON.stringify(ObjectSerializer.serialize({{paramName}}, "{{{dataType}}}"));
}
{{/headerIsJsonMimeType}}
{{^headerIsJsonMimeType}}
localVarHeaderParams['{{baseName}}'] = ObjectSerializer.serialize({{paramName}}, "{{{dataType}}}");
{{/headerIsJsonMimeType}}
{{/headerParams}}
(<any>Object).assign(localVarHeaderParams, options.headers);

Expand Down
Loading
Loading