Skip to content

Commit 230e288

Browse files
authored
[Core] Support map/object format for x-enum-varnames and x-enum-descriptions (#23540)
The generator crashes with a ClassCastException when these vendor extensions are provided as a JSON object (map) instead of an array. Both formats are valid conventions used in the ecosystem (Redocly, Speakeasy, etc.). For map format, keys are matched to enum values via toEnumValue(key, dataType) to ensure correct matching regardless of language-specific value transformations.
1 parent e317a7a commit 230e288

3 files changed

Lines changed: 98 additions & 16 deletions

File tree

modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7028,17 +7028,31 @@ private String getUniqueEnumName(String name, List<Map<String, Object>> enumVars
70287028

70297029
protected void updateEnumVarsWithExtensions(List<Map<String, Object>> enumVars, Map<String, Object> vendorExtensions, String dataType) {
70307030
if (vendorExtensions != null) {
7031-
updateEnumVarsWithExtensions(enumVars, vendorExtensions, "x-enum-varnames", "name");
7032-
updateEnumVarsWithExtensions(enumVars, vendorExtensions, "x-enum-descriptions", "enumDescription");
7031+
updateEnumVarsWithExtensions(enumVars, vendorExtensions, "x-enum-varnames", "name", dataType);
7032+
updateEnumVarsWithExtensions(enumVars, vendorExtensions, "x-enum-descriptions", "enumDescription", dataType);
70337033
}
70347034
}
70357035

7036-
private void updateEnumVarsWithExtensions(List<Map<String, Object>> enumVars, Map<String, Object> vendorExtensions, String extensionKey, String key) {
7036+
private void updateEnumVarsWithExtensions(List<Map<String, Object>> enumVars, Map<String, Object> vendorExtensions, String extensionKey, String key, String dataType) {
70377037
if (vendorExtensions.containsKey(extensionKey)) {
7038-
List<String> values = (List<String>) vendorExtensions.get(extensionKey);
7039-
int size = Math.min(enumVars.size(), values.size());
7040-
for (int i = 0; i < size; i++) {
7041-
enumVars.get(i).put(key, values.get(i));
7038+
Object extensionValue = vendorExtensions.get(extensionKey);
7039+
if (extensionValue instanceof List) {
7040+
List<String> values = (List<String>) extensionValue;
7041+
int size = Math.min(enumVars.size(), values.size());
7042+
for (int i = 0; i < size; i++) {
7043+
enumVars.get(i).put(key, values.get(i));
7044+
}
7045+
} else if (extensionValue instanceof Map) {
7046+
Map<String, String> valueMap = (Map<String, String>) extensionValue;
7047+
for (Map<String, Object> enumVar : enumVars) {
7048+
String enumValue = (String) enumVar.get("value");
7049+
for (Map.Entry<String, String> entry : valueMap.entrySet()) {
7050+
if (toEnumValue(entry.getKey(), dataType).equals(enumValue)) {
7051+
enumVar.put(key, entry.getValue());
7052+
break;
7053+
}
7054+
}
7055+
}
70427056
}
70437057
}
70447058
}

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -754,19 +754,46 @@ public void setParameterExampleValue(CodegenParameter p) {
754754
protected void updateEnumVarsWithExtensions(List<Map<String, Object>> enumVars, Map<String, Object> vendorExtensions, String dataType) {
755755
if (vendorExtensions != null) {
756756
if (vendorExtensions.containsKey("x-enum-varnames")) {
757-
List<String> values = (List<String>) vendorExtensions.get("x-enum-varnames");
758-
int size = Math.min(enumVars.size(), values.size());
759-
760-
for (int i = 0; i < size; i++) {
761-
enumVars.get(i).put("name", toEnumVarName(values.get(i), dataType));
757+
Object extensionValue = vendorExtensions.get("x-enum-varnames");
758+
if (extensionValue instanceof List) {
759+
List<String> values = (List<String>) extensionValue;
760+
int size = Math.min(enumVars.size(), values.size());
761+
for (int i = 0; i < size; i++) {
762+
enumVars.get(i).put("name", toEnumVarName(values.get(i), dataType));
763+
}
764+
} else if (extensionValue instanceof Map) {
765+
Map<String, String> valueMap = (Map<String, String>) extensionValue;
766+
for (Map<String, Object> enumVar : enumVars) {
767+
String enumValue = (String) enumVar.get("value");
768+
for (Map.Entry<String, String> entry : valueMap.entrySet()) {
769+
if (toEnumValue(entry.getKey(), dataType).equals(enumValue)) {
770+
enumVar.put("name", toEnumVarName(entry.getValue(), dataType));
771+
break;
772+
}
773+
}
774+
}
762775
}
763776
}
764777

765778
if (vendorExtensions.containsKey("x-enum-descriptions")) {
766-
List<String> values = (List<String>) vendorExtensions.get("x-enum-descriptions");
767-
int size = Math.min(enumVars.size(), values.size());
768-
for (int i = 0; i < size; i++) {
769-
enumVars.get(i).put("enumDescription", values.get(i));
779+
Object extensionValue = vendorExtensions.get("x-enum-descriptions");
780+
if (extensionValue instanceof List) {
781+
List<String> values = (List<String>) extensionValue;
782+
int size = Math.min(enumVars.size(), values.size());
783+
for (int i = 0; i < size; i++) {
784+
enumVars.get(i).put("enumDescription", values.get(i));
785+
}
786+
} else if (extensionValue instanceof Map) {
787+
Map<String, String> valueMap = (Map<String, String>) extensionValue;
788+
for (Map<String, Object> enumVar : enumVars) {
789+
String enumValue = (String) enumVar.get("value");
790+
for (Map.Entry<String, String> entry : valueMap.entrySet()) {
791+
if (toEnumValue(entry.getKey(), dataType).equals(enumValue)) {
792+
enumVar.put("enumDescription", entry.getValue());
793+
break;
794+
}
795+
}
796+
}
770797
}
771798
}
772799
}

modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,26 @@ public void postProcessModelsEnumWithExtension() {
995995
assertEquals("This is a cat", enumVars.get(1).getOrDefault("enumDescription", ""));
996996
}
997997

998+
@Test
999+
public void postProcessModelsEnumWithMapExtension() {
1000+
final DefaultCodegen codegen = new DefaultCodegen();
1001+
ModelsMap objs = codegenModelWithXEnumVarNameAsMap();
1002+
CodegenModel cm = objs.getModels().get(0).getModel();
1003+
1004+
codegen.postProcessModelsEnum(objs);
1005+
1006+
List<Map<String, Object>> enumVars = (List<Map<String, Object>>) cm.getAllowableValues().get("enumVars");
1007+
Assertions.assertNotNull(enumVars);
1008+
Assertions.assertNotNull(enumVars.get(0));
1009+
assertEquals("DOGVAR", enumVars.get(0).getOrDefault("name", ""));
1010+
assertEquals("\"dog\"", enumVars.get(0).getOrDefault("value", ""));
1011+
assertEquals("This is a dog", enumVars.get(0).getOrDefault("enumDescription", ""));
1012+
Assertions.assertNotNull(enumVars.get(1));
1013+
assertEquals("CATVAR", enumVars.get(1).getOrDefault("name", ""));
1014+
assertEquals("\"cat\"", enumVars.get(1).getOrDefault("value", ""));
1015+
assertEquals("This is a cat", enumVars.get(1).getOrDefault("enumDescription", ""));
1016+
}
1017+
9981018
@Test
9991019
public void testExample1() {
10001020
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/examples.yaml");
@@ -2314,6 +2334,27 @@ private ModelsMap codegenModelWithXEnumVarName() {
23142334
return TestUtils.createCodegenModelWrapper(cm);
23152335
}
23162336

2337+
private ModelsMap codegenModelWithXEnumVarNameAsMap() {
2338+
final CodegenModel cm = new CodegenModel();
2339+
cm.isEnum = true;
2340+
final HashMap<String, Object> allowableValues = new HashMap<>();
2341+
allowableValues.put("values", Arrays.asList("dog", "cat"));
2342+
cm.setAllowableValues(allowableValues);
2343+
cm.dataType = "String";
2344+
Map<String, String> aliases = new LinkedHashMap<>();
2345+
aliases.put("dog", "DOGVAR");
2346+
aliases.put("cat", "CATVAR");
2347+
Map<String, String> descriptions = new LinkedHashMap<>();
2348+
descriptions.put("dog", "This is a dog");
2349+
descriptions.put("cat", "This is a cat");
2350+
Map<String, Object> extensions = new HashMap<>();
2351+
extensions.put("x-enum-varnames", aliases);
2352+
extensions.put("x-enum-descriptions", descriptions);
2353+
cm.setVendorExtensions(extensions);
2354+
cm.setVars(Collections.emptyList());
2355+
return TestUtils.createCodegenModelWrapper(cm);
2356+
}
2357+
23172358
@Test
23182359
public void objectQueryParamIdentifyAsObject() {
23192360
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/objectQueryParam.yaml");

0 commit comments

Comments
 (0)