diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java
index c854389be7b2..8ae213842acf 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java
@@ -187,6 +187,12 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti
public boolean isDiscriminator;
public boolean isNew; // true when this property overrides an inherited property
public Boolean isOverridden; // true if the property is a parent property (not defined in child/current schema)
+ /**
+ * The type alias name to use when this property references a deduplicated inline model.
+ * When non-null, code generators may emit a type alias declaration.
+ */
+ @Getter @Setter
+ public String dataTypeAlias;
@Getter @Setter
public List _enum;
@Getter @Setter
@@ -980,6 +986,7 @@ public String toString() {
sb.append(", setter='").append(setter).append('\'');
sb.append(", description='").append(description).append('\'');
sb.append(", dataType='").append(dataType).append('\'');
+ sb.append(", dataTypeAlias='").append(dataTypeAlias).append('\'');
sb.append(", datatypeWithEnum='").append(datatypeWithEnum).append('\'');
sb.append(", dataFormat='").append(dataFormat).append('\'');
sb.append(", name='").append(name).append('\'');
@@ -1167,6 +1174,7 @@ public boolean equals(Object o) {
Objects.equals(setter, that.setter) &&
Objects.equals(description, that.description) &&
Objects.equals(dataType, that.dataType) &&
+ Objects.equals(dataTypeAlias, that.dataTypeAlias) &&
Objects.equals(datatypeWithEnum, that.datatypeWithEnum) &&
Objects.equals(dataFormat, that.dataFormat) &&
Objects.equals(name, that.name) &&
@@ -1211,7 +1219,7 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash(openApiType, baseName, complexType, getter, setter, description,
- dataType, datatypeWithEnum, dataFormat, name, min, max, defaultValue,
+ dataType, dataTypeAlias, datatypeWithEnum, dataFormat, name, min, max, defaultValue,
defaultValueWithParam, baseType, containerType, containerTypeMapped, title, unescapedDescription,
maxLength, minLength, pattern, example, jsonSchema, minimum, maximum,
exclusiveMinimum, exclusiveMaximum, required, deprecated,
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
index 2002667a31ce..86e2edc0cda7 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
@@ -4193,6 +4193,15 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo
String type = getSchemaType(p);
setNonArrayMapProperty(property, type);
property.isModel = (ModelUtils.isComposedSchema(referencedSchema) || ModelUtils.isObjectSchema(referencedSchema)) && ModelUtils.isModel(referencedSchema);
+
+ // Check if this property is reusing a model type that was generated/deduplicated by InlineModelResolver
+ // InlineModelResolver marks deduplicated schemas with x-alias-name vendor extension
+ if (p.get$ref() != null && original != null && original.getExtensions() != null) {
+ String dedupedName = (String) original.getExtensions().get("x-alias-name");
+ if (dedupedName != null && ModelUtils.isModel(referencedSchema)) {
+ property.dataTypeAlias = toModelName(dedupedName);
+ }
+ }
}
// restore original schema with default value, nullable, readonly etc
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java
index 777fed9b2cb4..64f81ff3137d 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java
@@ -667,6 +667,7 @@ private void flattenComposedChildren(String key, List children, boolean
listIterator.set(schema);
} else {
Schema schema = new Schema().$ref(existing);
+ schema.addExtension("x-alias-name", applyInlineSchemaNameMapping(innerModelName));
schema.setRequired(component.getRequired());
listIterator.set(schema);
}
@@ -826,6 +827,7 @@ private void flattenProperties(OpenAPI openAPI, Map properties,
String existing = matchGenerated(model);
if (existing != null) {
Schema schema = new Schema().$ref(existing);
+ schema.addExtension("x-alias-name", applyInlineSchemaNameMapping(modelName));
schema.setRequired(op.getRequired());
propsToUpdate.put(key, schema);
} else {
@@ -846,6 +848,7 @@ private void flattenProperties(OpenAPI openAPI, Map properties,
String existing = matchGenerated(innerModel);
if (existing != null) {
Schema schema = new Schema().$ref(existing);
+ schema.addExtension("x-alias-name", applyInlineSchemaNameMapping(modelName));
schema.setRequired(op.getRequired());
property.setItems(schema);
} else {
@@ -876,6 +879,7 @@ private void flattenProperties(OpenAPI openAPI, Map properties,
String existing = matchGenerated(innerModel);
if (existing != null) {
Schema schema = new Schema().$ref(existing);
+ schema.addExtension("x-alias-name", applyInlineSchemaNameMapping(modelName));
schema.setRequired(op.getRequired());
property.setAdditionalProperties(schema);
} else {
@@ -985,6 +989,19 @@ private Schema modelFromProperty(OpenAPI openAPI, Schema object, String path) {
return model;
}
+ /**
+ * Apply inlineSchemaNameMapping if configured.
+ *
+ * @param name the inline schema name to map
+ * @return the mapped name if mapping exists, otherwise the original name
+ */
+ private String applyInlineSchemaNameMapping(String name) {
+ if (inlineSchemaNameMapping.containsKey(name)) {
+ return inlineSchemaNameMapping.get(name);
+ }
+ return name;
+ }
+
/**
* Move schema to components (if new) and return $ref to schema or
* existing schema.
@@ -998,6 +1015,7 @@ private Schema makeSchemaInComponents(String name, Schema schema) {
Schema refSchema;
if (existing != null) {
refSchema = new Schema().$ref(existing);
+ refSchema.addExtension("x-alias-name", applyInlineSchemaNameMapping(name));
} else {
if (resolveInlineEnums && schema.getEnum() != null && schema.getEnum().size() > 0) {
LOGGER.warn("Model " + name + " promoted to its own schema due to resolveInlineEnums=true");
@@ -1035,6 +1053,10 @@ private void copyVendorExtensions(Schema source, Schema target) {
return;
}
for (String extName : vendorExtensions.keySet()) {
+ // Don't overwrite x-alias-name that was set during deduplication
+ if ("x-alias-name".equals(extName) && target.getExtensions() != null && target.getExtensions().containsKey("x-alias-name")) {
+ continue;
+ }
target.addExtension(extName, vendorExtensions.get(extName));
}
}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractGoCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractGoCodegen.java
index 16b909eab448..b7711d709e56 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractGoCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractGoCodegen.java
@@ -736,6 +736,21 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
property.vendorExtensions.put("x-golang-is-container", true);
}
}
+
+ private void swapDataTypeAndAlias(CodegenProperty property, Map typeAliasesMap) {
+ if (property.dataTypeAlias != null) {
+ String dedupedType = property.dataType;
+ String aliasName = property.dataTypeAlias;
+ // Swap: field uses the alias, alias definition points to deduplicated type
+ property.dataType = aliasName;
+ property.dataTypeAlias = dedupedType;
+
+ // Collect type alias (after swap, dataType is alias name, dataTypeAlias is target)
+ if (!property.isContainer && !typeAliasesMap.containsKey(property.dataType)) {
+ typeAliasesMap.put(property.dataType, property.dataTypeAlias);
+ }
+ }
+ }
@Override
public ModelsMap postProcessModels(ModelsMap objs) {
@@ -775,7 +790,25 @@ public ModelsMap postProcessModels(ModelsMap objs) {
codegenProperties.addAll(inheritedProperties);
}
+ // Collect reused model properties for type alias generation
+ Map typeAliasesMap = new LinkedHashMap<>();
+
for (CodegenProperty cp : codegenProperties) {
+ // Swap dataType and dataTypeAlias so fields use the alias name
+ swapDataTypeAndAlias(cp, typeAliasesMap);
+
+ // Also swap for array items and update the array's dataType
+ if (cp.items != null && cp.items.dataTypeAlias != null) {
+ String oldItemsDataType = cp.items.dataType;
+ swapDataTypeAndAlias(cp.items, typeAliasesMap);
+ String newItemsDataType = cp.items.dataType;
+
+ // Update the array's dataType to use the new items dataType
+ if (cp.dataType != null && cp.dataType.contains(oldItemsDataType)) {
+ cp.dataType = cp.dataType.replace(oldItemsDataType, newItemsDataType);
+ }
+ }
+
if (!addedTimeImport && ("time.Time".equals(cp.dataType) || (cp.items != null && "time.Time".equals(cp.items.complexType)))) {
imports.add(createMapping("import", "time"));
addedTimeImport = true;
@@ -855,6 +888,23 @@ public ModelsMap postProcessModels(ModelsMap objs) {
if (generateUnmarshalJSON) {
model.vendorExtensions.putIfAbsent("x-go-generate-unmarshal-json", true);
}
+
+ // Convert type aliases map to list for template usage
+ if (!typeAliasesMap.isEmpty()) {
+ List
*
*
- * Response headers: [CodegenProperty{openApiType='string', baseName='Set-Cookie', complexType='null', getter='getSetCookie', setter='setSetCookie', description='Cookie authentication key for use with the `api_key` apiKey authentication.', dataType='String', datatypeWithEnum='String', dataFormat='null', name='setCookie', min='null', max='null', defaultValue='null', defaultValueWithParam=' = data.Set-Cookie;', baseType='String', containerType='null', containerTypeMapped='null', title='null', unescapedDescription='Cookie authentication key for use with the `api_key` apiKey authentication.', maxLength=null, minLength=null, pattern='null', example='AUTH_KEY=abcde12345; Path=/; HttpOnly', jsonSchema='{
+ *
Response headers: [CodegenProperty{openApiType='string', baseName='Set-Cookie', complexType='null', getter='getSetCookie', setter='setSetCookie', description='Cookie authentication key for use with the `api_key` apiKey authentication.', dataType='String', dataTypeAlias='null', datatypeWithEnum='String', dataFormat='null', name='setCookie', min='null', max='null', defaultValue='null', defaultValueWithParam=' = data.Set-Cookie;', baseType='String', containerType='null', containerTypeMapped='null', title='null', unescapedDescription='Cookie authentication key for use with the `api_key` apiKey authentication.', maxLength=null, minLength=null, pattern='null', example='AUTH_KEY=abcde12345; Path=/; HttpOnly', jsonSchema='{
"example" : "AUTH_KEY=abcde12345; Path=/; HttpOnly",
"type" : "string"
-}', minimum='null', maximum='null', exclusiveMinimum=false, exclusiveMaximum=false, required=false, deprecated=false, isPrimitiveType=true, isModel=false, isContainer=false, isString=true, isNumeric=false, isInteger=false, isShort=false, isLong=false, isUnboundedInteger=false, isNumber=false, isFloat=false, isDouble=false, isDecimal=false, isByteArray=false, isBinary=false, isFile=false, isBoolean=false, isDate=false, isDateTime=false, isUuid=false, isUri=false, isEmail=false, isPassword=false, isFreeFormObject=false, isArray=false, isMap=false, isOptional=false, isEnum=false, isInnerEnum=false, isEnumRef=false, isAnyType=false, isReadOnly=false, isWriteOnly=false, isNullable=false, isSelfReference=false, isCircularReference=false, isDiscriminator=false, isNew=false, isOverridden=null, _enum=null, allowableValues=null, items=null, additionalProperties=null, vars=[], requiredVars=[], mostInnerItems=null, vendorExtensions={}, hasValidation=false, isInherited=false, discriminatorValue='null', nameInCamelCase='setCookie', nameInPascalCase='SetCookie', nameInSnakeCase='SET_COOKIE', enumName='null', maxItems=null, minItems=null, maxProperties=null, minProperties=null, uniqueItems=false, uniqueItemsBoolean=null, multipleOf=null, isXmlAttribute=false, xmlPrefix='null', xmlName='null', xmlNamespace='null', isXmlWrapped=false, isNull=false, isVoid=false, getAdditionalPropertiesIsAnyType=false, getHasVars=false, getHasRequired=false, getHasDiscriminatorWithNonEmptyMapping=false, composedSchemas=null, hasMultipleTypes=false, hasSanitizedName=true, requiredVarsMap=null, ref=null, schemaIsFromAdditionalProperties=false, isBooleanSchemaTrue=false, isBooleanSchemaFalse=false, format=null, dependentRequired=null, contains=null}, CodegenProperty{openApiType='integer', baseName='X-Rate-Limit', complexType='null', getter='getxRateLimit', setter='setxRateLimit', description='calls per hour allowed by the user', dataType='Integer', datatypeWithEnum='Integer', dataFormat='int32', name='xRateLimit', min='null', max='null', defaultValue='null', defaultValueWithParam=' = data.X-Rate-Limit;', baseType='Integer', containerType='null', containerTypeMapped='null', title='null', unescapedDescription='calls per hour allowed by the user', maxLength=null, minLength=null, pattern='null', example='null', jsonSchema='{
+}', minimum='null', maximum='null', exclusiveMinimum=false, exclusiveMaximum=false, required=false, deprecated=false, isPrimitiveType=true, isModel=false, isContainer=false, isString=true, isNumeric=false, isInteger=false, isShort=false, isLong=false, isUnboundedInteger=false, isNumber=false, isFloat=false, isDouble=false, isDecimal=false, isByteArray=false, isBinary=false, isFile=false, isBoolean=false, isDate=false, isDateTime=false, isUuid=false, isUri=false, isEmail=false, isPassword=false, isFreeFormObject=false, isArray=false, isMap=false, isOptional=false, isEnum=false, isInnerEnum=false, isEnumRef=false, isAnyType=false, isReadOnly=false, isWriteOnly=false, isNullable=false, isSelfReference=false, isCircularReference=false, isDiscriminator=false, isNew=false, isOverridden=null, _enum=null, allowableValues=null, items=null, additionalProperties=null, vars=[], requiredVars=[], mostInnerItems=null, vendorExtensions={}, hasValidation=false, isInherited=false, discriminatorValue='null', nameInCamelCase='setCookie', nameInPascalCase='SetCookie', nameInSnakeCase='SET_COOKIE', enumName='null', maxItems=null, minItems=null, maxProperties=null, minProperties=null, uniqueItems=false, uniqueItemsBoolean=null, multipleOf=null, isXmlAttribute=false, xmlPrefix='null', xmlName='null', xmlNamespace='null', isXmlWrapped=false, isNull=false, isVoid=false, getAdditionalPropertiesIsAnyType=false, getHasVars=false, getHasRequired=false, getHasDiscriminatorWithNonEmptyMapping=false, composedSchemas=null, hasMultipleTypes=false, hasSanitizedName=true, requiredVarsMap=null, ref=null, schemaIsFromAdditionalProperties=false, isBooleanSchemaTrue=false, isBooleanSchemaFalse=false, format=null, dependentRequired=null, contains=null}, CodegenProperty{openApiType='integer', baseName='X-Rate-Limit', complexType='null', getter='getxRateLimit', setter='setxRateLimit', description='calls per hour allowed by the user', dataType='Integer', dataTypeAlias='null', datatypeWithEnum='Integer', dataFormat='int32', name='xRateLimit', min='null', max='null', defaultValue='null', defaultValueWithParam=' = data.X-Rate-Limit;', baseType='Integer', containerType='null', containerTypeMapped='null', title='null', unescapedDescription='calls per hour allowed by the user', maxLength=null, minLength=null, pattern='null', example='null', jsonSchema='{
"format" : "int32",
"type" : "integer"
-}', minimum='null', maximum='null', exclusiveMinimum=false, exclusiveMaximum=false, required=false, deprecated=false, isPrimitiveType=true, isModel=false, isContainer=false, isString=false, isNumeric=true, isInteger=true, isShort=true, isLong=false, isUnboundedInteger=false, isNumber=false, isFloat=false, isDouble=false, isDecimal=false, isByteArray=false, isBinary=false, isFile=false, isBoolean=false, isDate=false, isDateTime=false, isUuid=false, isUri=false, isEmail=false, isPassword=false, isFreeFormObject=false, isArray=false, isMap=false, isOptional=false, isEnum=false, isInnerEnum=false, isEnumRef=false, isAnyType=false, isReadOnly=false, isWriteOnly=false, isNullable=false, isSelfReference=false, isCircularReference=false, isDiscriminator=false, isNew=false, isOverridden=null, _enum=null, allowableValues=null, items=null, additionalProperties=null, vars=[], requiredVars=[], mostInnerItems=null, vendorExtensions={}, hasValidation=false, isInherited=false, discriminatorValue='null', nameInCamelCase='xRateLimit', nameInPascalCase='XRateLimit', nameInSnakeCase='X_RATE_LIMIT', enumName='null', maxItems=null, minItems=null, maxProperties=null, minProperties=null, uniqueItems=false, uniqueItemsBoolean=null, multipleOf=null, isXmlAttribute=false, xmlPrefix='null', xmlName='null', xmlNamespace='null', isXmlWrapped=false, isNull=false, isVoid=false, getAdditionalPropertiesIsAnyType=false, getHasVars=false, getHasRequired=false, getHasDiscriminatorWithNonEmptyMapping=false, composedSchemas=null, hasMultipleTypes=false, hasSanitizedName=true, requiredVarsMap=null, ref=null, schemaIsFromAdditionalProperties=false, isBooleanSchemaTrue=false, isBooleanSchemaFalse=false, format=int32, dependentRequired=null, contains=null}, CodegenProperty{openApiType='string', baseName='X-Expires-After', complexType='Date', getter='getxExpiresAfter', setter='setxExpiresAfter', description='date in UTC when token expires', dataType='Date', datatypeWithEnum='Date', dataFormat='date-time', name='xExpiresAfter', min='null', max='null', defaultValue='null', defaultValueWithParam=' = data.X-Expires-After;', baseType='Date', containerType='null', containerTypeMapped='null', title='null', unescapedDescription='date in UTC when token expires', maxLength=null, minLength=null, pattern='null', example='null', jsonSchema='{
+}', minimum='null', maximum='null', exclusiveMinimum=false, exclusiveMaximum=false, required=false, deprecated=false, isPrimitiveType=true, isModel=false, isContainer=false, isString=false, isNumeric=true, isInteger=true, isShort=true, isLong=false, isUnboundedInteger=false, isNumber=false, isFloat=false, isDouble=false, isDecimal=false, isByteArray=false, isBinary=false, isFile=false, isBoolean=false, isDate=false, isDateTime=false, isUuid=false, isUri=false, isEmail=false, isPassword=false, isFreeFormObject=false, isArray=false, isMap=false, isOptional=false, isEnum=false, isInnerEnum=false, isEnumRef=false, isAnyType=false, isReadOnly=false, isWriteOnly=false, isNullable=false, isSelfReference=false, isCircularReference=false, isDiscriminator=false, isNew=false, isOverridden=null, _enum=null, allowableValues=null, items=null, additionalProperties=null, vars=[], requiredVars=[], mostInnerItems=null, vendorExtensions={}, hasValidation=false, isInherited=false, discriminatorValue='null', nameInCamelCase='xRateLimit', nameInPascalCase='XRateLimit', nameInSnakeCase='X_RATE_LIMIT', enumName='null', maxItems=null, minItems=null, maxProperties=null, minProperties=null, uniqueItems=false, uniqueItemsBoolean=null, multipleOf=null, isXmlAttribute=false, xmlPrefix='null', xmlName='null', xmlNamespace='null', isXmlWrapped=false, isNull=false, isVoid=false, getAdditionalPropertiesIsAnyType=false, getHasVars=false, getHasRequired=false, getHasDiscriminatorWithNonEmptyMapping=false, composedSchemas=null, hasMultipleTypes=false, hasSanitizedName=true, requiredVarsMap=null, ref=null, schemaIsFromAdditionalProperties=false, isBooleanSchemaTrue=false, isBooleanSchemaFalse=false, format=int32, dependentRequired=null, contains=null}, CodegenProperty{openApiType='string', baseName='X-Expires-After', complexType='Date', getter='getxExpiresAfter', setter='setxExpiresAfter', description='date in UTC when token expires', dataType='Date', dataTypeAlias='null', datatypeWithEnum='Date', dataFormat='date-time', name='xExpiresAfter', min='null', max='null', defaultValue='null', defaultValueWithParam=' = data.X-Expires-After;', baseType='Date', containerType='null', containerTypeMapped='null', title='null', unescapedDescription='date in UTC when token expires', maxLength=null, minLength=null, pattern='null', example='null', jsonSchema='{
"format" : "date-time",
"type" : "string"
}', minimum='null', maximum='null', exclusiveMinimum=false, exclusiveMaximum=false, required=false, deprecated=false, isPrimitiveType=false, isModel=false, isContainer=false, isString=false, isNumeric=false, isInteger=false, isShort=false, isLong=false, isUnboundedInteger=false, isNumber=false, isFloat=false, isDouble=false, isDecimal=false, isByteArray=false, isBinary=false, isFile=false, isBoolean=false, isDate=false, isDateTime=true, isUuid=false, isUri=false, isEmail=false, isPassword=false, isFreeFormObject=false, isArray=false, isMap=false, isOptional=false, isEnum=false, isInnerEnum=false, isEnumRef=false, isAnyType=false, isReadOnly=false, isWriteOnly=false, isNullable=false, isSelfReference=false, isCircularReference=false, isDiscriminator=false, isNew=false, isOverridden=null, _enum=null, allowableValues=null, items=null, additionalProperties=null, vars=[], requiredVars=[], mostInnerItems=null, vendorExtensions={}, hasValidation=false, isInherited=false, discriminatorValue='null', nameInCamelCase='xExpiresAfter', nameInPascalCase='XExpiresAfter', nameInSnakeCase='X_EXPIRES_AFTER', enumName='null', maxItems=null, minItems=null, maxProperties=null, minProperties=null, uniqueItems=false, uniqueItemsBoolean=null, multipleOf=null, isXmlAttribute=false, xmlPrefix='null', xmlName='null', xmlNamespace='null', isXmlWrapped=false, isNull=false, isVoid=false, getAdditionalPropertiesIsAnyType=false, getHasVars=false, getHasRequired=false, getHasDiscriminatorWithNonEmptyMapping=false, composedSchemas=null, hasMultipleTypes=false, hasSanitizedName=true, requiredVarsMap=null, ref=null, schemaIsFromAdditionalProperties=false, isBooleanSchemaTrue=false, isBooleanSchemaFalse=false, format=date-time, dependentRequired=null, contains=null}]