fix discriminator model lookup when used with model name suffix (#23363)

This commit is contained in:
Jan Škrášek
2026-04-01 10:06:09 +02:00
committed by GitHub
parent 8a2f1bb8de
commit e1c4fdbe19
3 changed files with 57 additions and 6 deletions

View File

@@ -76,18 +76,27 @@ public class CodegenDiscriminator {
// is converted to a sanitized, internal representation within codegen.
@Getter @Setter
private String modelName;
// The raw schema name as it appears in the OAS document, before any
// modelNamePrefix/Suffix transformation.
@Getter
private String schemaName;
@Getter @Setter
private CodegenModel model;
private final boolean explicitMapping;
public MappedModel(String mappingName, String modelName, boolean explicitMapping) {
public MappedModel(String mappingName, String modelName, String schemaName, boolean explicitMapping) {
this.mappingName = mappingName;
this.modelName = modelName;
this.schemaName = schemaName;
this.explicitMapping = explicitMapping;
}
public MappedModel(String mappingName, String modelName, boolean explicitMapping) {
this(mappingName, modelName, null, explicitMapping);
}
public boolean isExplicitMapping() {
return explicitMapping;
}

View File

@@ -507,7 +507,8 @@ public class DefaultCodegen implements CodegenConfig {
// add the model to the discriminator's mapping so templates have access to more than just the string to string mapping
if (model.discriminator != null && model.discriminator.getMappedModels() != null) {
for (CodegenDiscriminator.MappedModel mappedModel : model.discriminator.getMappedModels()) {
CodegenModel mappedCodegenModel = ModelUtils.getModelByName(mappedModel.getModelName(), objs);
String lookupName = mappedModel.getSchemaName() != null ? mappedModel.getSchemaName() : mappedModel.getModelName();
CodegenModel mappedCodegenModel = ModelUtils.getModelByName(lookupName, objs);
mappedModel.setModel(mappedCodegenModel);
}
}
@@ -3574,7 +3575,7 @@ public class DefaultCodegen implements CodegenConfig {
once(LOGGER).warn("'{}' defines discriminator '{}', but the referenced schema '{}' is incorrect. {}",
composedSchemaName, discPropName, modelName, msgSuffix);
}
MappedModel mm = new MappedModel(modelName, toModelName(modelName));
MappedModel mm = new MappedModel(modelName, toModelName(modelName), modelName, false);
descendentSchemas.add(mm);
Schema cs = ModelUtils.getSchema(openAPI, modelName);
if (cs == null) { // cannot lookup the model based on the name
@@ -3583,7 +3584,7 @@ public class DefaultCodegen implements CodegenConfig {
Map<String, Object> vendorExtensions = cs.getExtensions();
if (vendorExtensions != null && !vendorExtensions.isEmpty() && vendorExtensions.containsKey(X_DISCRIMINATOR_VALUE)) {
String xDiscriminatorValue = (String) vendorExtensions.get(X_DISCRIMINATOR_VALUE);
mm = new MappedModel(xDiscriminatorValue, toModelName(modelName), true);
mm = new MappedModel(xDiscriminatorValue, toModelName(modelName), modelName, true);
descendentSchemas.add(mm);
}
}
@@ -3641,7 +3642,7 @@ public class DefaultCodegen implements CodegenConfig {
.map(ve -> ve.get(X_DISCRIMINATOR_VALUE))
.map(discriminatorValue -> (String) discriminatorValue)
.orElse(currentSchemaName);
MappedModel mm = new MappedModel(mappingName, toModelName(currentSchemaName), !mappingName.equals(currentSchemaName));
MappedModel mm = new MappedModel(mappingName, toModelName(currentSchemaName), currentSchemaName, !mappingName.equals(currentSchemaName));
descendentSchemas.add(mm);
}
return descendentSchemas;
@@ -3687,7 +3688,7 @@ public class DefaultCodegen implements CodegenConfig {
} else {
name = e.getValue();
}
uniqueDescendants.add(new MappedModel(e.getKey(), toModelName(name), true));
uniqueDescendants.add(new MappedModel(e.getKey(), toModelName(name), name, true));
}
}

View File

@@ -1680,6 +1680,47 @@ public class DefaultCodegenTest {
assertThat(cm.discriminator.getPropertyType()).isEqualTo("TransferFruitTypeEnumDto");
}
@Test
public void testDiscriminatorMappedModelWithModelNameSuffix() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/oneOfDiscriminator.yaml");
DefaultCodegen codegen = new DefaultCodegen();
codegen.setLegacyDiscriminatorBehavior(false);
codegen.setOpenAPI(openAPI);
codegen.setModelNameSuffix("Dto");
// Build allProcessedModels map keyed by raw schema name (as DefaultGenerator does)
Map<String, ModelsMap> allProcessedModels = new TreeMap<>();
String[] schemaNames = {"FruitReqDisc", "AppleReqDisc", "BananaReqDisc"};
for (String name : schemaNames) {
Schema schema = openAPI.getComponents().getSchemas().get(name);
CodegenModel cm = codegen.fromModel(name, schema);
ModelMap mo = new ModelMap();
mo.setModel(cm);
ModelsMap models = new ModelsMap();
models.setModels(Collections.singletonList(mo));
allProcessedModels.put(name, models);
}
// Verify schemaName is stored and differs from modelName
CodegenModel fruitModel = ModelUtils.getModelByName("FruitReqDisc", allProcessedModels);
assertNotNull(fruitModel.discriminator);
for (CodegenDiscriminator.MappedModel mm : fruitModel.discriminator.getMappedModels()) {
assertNotNull(mm.getSchemaName(),
"MappedModel.getSchemaName() should not be null for " + mm.getModelName());
assertNotEquals(mm.getSchemaName(), mm.getModelName(),
"schemaName should differ from modelName when modelNameSuffix is set");
}
// Verify postProcessAllModels resolves MappedModel.model via schemaName
Map<String, ModelsMap> result = codegen.postProcessAllModels(allProcessedModels);
fruitModel = ModelUtils.getModelByName("FruitReqDisc", result);
for (CodegenDiscriminator.MappedModel mm : fruitModel.discriminator.getMappedModels()) {
assertNotNull(mm.getModel(),
"MappedModel.getModel() should not be null for " + mm.getModelName()
+ " (mappingName=" + mm.getMappingName() + ")");
}
}
@Test
public void testComposedSchemaMyPetsOneOfDiscriminatorMap() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/allOf_composition_discriminator.yaml");