Skip to content

Commit 8dabae4

Browse files
refactor: centralize logic for inherited enum x-enum-as-string escape hatch (#25451)
1 parent 85db0eb commit 8dabae4

6 files changed

Lines changed: 53 additions & 54 deletions

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,8 @@ public static enum ENUM_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case,
526526
public static final String X_MODIFIER_PREFIX = "x-modifier-";
527527
public static final String X_MODEL_IS_MUTABLE = "x-model-is-mutable";
528528
public static final String X_MODEL_IS_OPERATION_INPUT = "x-model-is-operation-input";
529+
public static final String X_ENUM_AS_STRING = "x-enum-as-string";
530+
public static final String X_IS_JACKSON_OPTIONAL_NULLABLE = "x-is-jackson-optional-nullable";
529531
public static final String X_IMPLEMENTS = "x-implements";
530532
public static final String X_IS_ONE_OF_INTERFACE = "x-is-one-of-interface";
531533
public static final String USE_ENUM_VALUE_INTERFACE = "useEnumValueInterface";

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

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,14 @@
4545
import org.openapitools.codegen.languages.features.BeanValidationFeatures;
4646
import org.openapitools.codegen.languages.features.DocumentationProviderFeatures;
4747
import org.openapitools.codegen.meta.features.*;
48+
import org.openapitools.codegen.model.EnumVarMap;
4849
import org.openapitools.codegen.model.ModelMap;
4950
import org.openapitools.codegen.model.ModelsMap;
5051
import org.openapitools.codegen.model.OperationMap;
5152
import org.openapitools.codegen.model.OperationsMap;
5253
import org.openapitools.codegen.templating.mustache.EscapeJavaDocLambda;
5354
import org.openapitools.codegen.utils.CamelizeOption;
55+
import org.openapitools.codegen.utils.EnumUtils;
5456
import org.openapitools.codegen.utils.ModelUtils;
5557
import org.slf4j.Logger;
5658
import org.slf4j.LoggerFactory;
@@ -2356,6 +2358,41 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
23562358
return objs;
23572359
}
23582360

2361+
/**
2362+
* Applies string-based enum rendering adjustments to a property that has already
2363+
* been marked with {@code x-enum-as-string} by upstream processing.
2364+
* <p>
2365+
* This method updates Java generation details by switching
2366+
* {@code datatypeWithEnum} to the plain data type, converting enum constant
2367+
* defaults to their string literal values, and adding {@code Set}/{@code HashSet}
2368+
* imports used by string-value validation logic in Java templates.
2369+
* <p>
2370+
* It does not set the {@code x-enum-as-string} vendor extension itself.
2371+
*/
2372+
protected void handleEnumAsString(CodegenProperty var, CodegenModel cm, List<Map<String, String>> imports) {
2373+
// treat enum string as just string
2374+
var.datatypeWithEnum = var.dataType;
2375+
2376+
if (StringUtils.isNotEmpty(var.defaultValue)) { // has default value
2377+
String defaultValue = var.defaultValue.substring(var.defaultValue.lastIndexOf('.') + 1);
2378+
for (EnumVarMap enumVars : EnumUtils.getEnumVars(var.allowableValues)) {
2379+
if (defaultValue.equals(enumVars.getEnumName())) {
2380+
// update default to use the string directly instead of enum string
2381+
var.defaultValue = (String) enumVars.getEnumValue();
2382+
}
2383+
}
2384+
}
2385+
2386+
// add import for Set, HashSet
2387+
cm.imports.add("Set");
2388+
Map<String, String> importsSet = new HashMap<>();
2389+
importsSet.put("import", "java.util.Set");
2390+
imports.add(importsSet);
2391+
Map<String, String> importsHashSet = new HashMap<>();
2392+
importsHashSet.put("import", "java.util.HashSet");
2393+
imports.add(importsHashSet);
2394+
}
2395+
23592396
/**
23602397
* Normalizes a model property vendor extension across all property collections.
23612398
* In this context, normalization means converting a missing value, a single string, or a list value
@@ -2931,9 +2968,9 @@ public boolean isAddNullableImports(CodegenModel cm, boolean addImports, Codegen
29312968
boolean isOptionalNullable = Boolean.FALSE.equals(var.required) && Boolean.TRUE.equals(var.isNullable);
29322969
// only add JsonNullable and related imports to optional and nullable values
29332970
addImports |= isOptionalNullable;
2934-
var.getVendorExtensions().put("x-is-jackson-optional-nullable", isOptionalNullable);
2971+
var.getVendorExtensions().put(X_IS_JACKSON_OPTIONAL_NULLABLE, isOptionalNullable);
29352972
findByName(var.name, cm.readOnlyVars)
2936-
.ifPresent(p -> p.getVendorExtensions().put("x-is-jackson-optional-nullable", isOptionalNullable));
2973+
.ifPresent(p -> p.getVendorExtensions().put(X_IS_JACKSON_OPTIONAL_NULLABLE, isOptionalNullable));
29372974
}
29382975
return addImports;
29392976
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
import java.util.List;
3636
import java.util.Map;
3737

38+
import static org.openapitools.codegen.CodegenConstants.X_IS_JACKSON_OPTIONAL_NULLABLE;
39+
3840
/**
3941
* <p>Mustache templates are located in {@code src/main/resources/JavaJaxRS/cxf/}.
4042
*/
@@ -184,9 +186,9 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
184186
//Add JsonNullable import and mark property nullable for templating if necessary
185187
if (openApiNullable) {
186188
if (Boolean.FALSE.equals(property.required) && Boolean.TRUE.equals(property.isNullable)) {
187-
property.getVendorExtensions().put("x-is-jackson-optional-nullable", true);
189+
property.getVendorExtensions().put(X_IS_JACKSON_OPTIONAL_NULLABLE, true);
188190
findByName(property.name, model.readOnlyVars)
189-
.ifPresent(p -> p.getVendorExtensions().put("x-is-jackson-optional-nullable", true));
191+
.ifPresent(p -> p.getVendorExtensions().put(X_IS_JACKSON_OPTIONAL_NULLABLE, true));
190192
model.imports.add("JsonNullable");
191193
model.imports.add("JsonIgnore");
192194
}

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

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
package org.openapitools.codegen.languages;
1919

20-
import com.samskivert.mustache.Mustache;
2120
import io.swagger.v3.oas.models.Operation;
2221
import io.swagger.v3.oas.models.media.Schema;
2322
import io.swagger.v3.oas.models.servers.Server;
@@ -1295,28 +1294,9 @@ public ModelsMap postProcessModels(ModelsMap objs) {
12951294

12961295
for (CodegenProperty var : cm.vars) {
12971296
addNullableImports = isAddNullableImports(cm, addNullableImports, var);
1298-
if (Boolean.TRUE.equals(var.getVendorExtensions().get("x-enum-as-string"))) {
1299-
// treat enum string as just string
1300-
var.datatypeWithEnum = var.dataType;
1301-
1302-
if (StringUtils.isNotEmpty(var.defaultValue)) { // has default value
1303-
String defaultValue = var.defaultValue.substring(var.defaultValue.lastIndexOf('.') + 1);
1304-
for (EnumVarMap enumVars : EnumUtils.getEnumVars(var.allowableValues)) {
1305-
if (defaultValue.equals(enumVars.getEnumName())) {
1306-
// update default to use the string directly instead of enum string
1307-
var.defaultValue = (String) enumVars.getEnumValue();
1308-
}
1309-
}
1310-
}
13111297

1312-
// add import for Set, HashSet
1313-
cm.imports.add("Set");
1314-
Map<String, String> importsSet = new HashMap<>();
1315-
importsSet.put("import", "java.util.Set");
1316-
imports.add(importsSet);
1317-
Map<String, String> importsHashSet = new HashMap<>();
1318-
importsHashSet.put("import", "java.util.HashSet");
1319-
imports.add(importsHashSet);
1298+
if (Boolean.TRUE.equals(var.getVendorExtensions().get(X_ENUM_AS_STRING))) {
1299+
handleEnumAsString(var, cm, imports);
13201300
}
13211301

13221302
}

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

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,14 @@
2323
import lombok.Getter;
2424
import lombok.Setter;
2525
import org.apache.commons.lang3.BooleanUtils;
26-
import org.apache.commons.lang3.StringUtils;
2726
import org.openapitools.codegen.*;
2827
import org.openapitools.codegen.meta.GeneratorMetadata;
2928
import org.openapitools.codegen.meta.Stability;
3029
import org.openapitools.codegen.meta.features.DocumentationFeature;
3130
import org.openapitools.codegen.meta.features.GlobalFeature;
32-
import org.openapitools.codegen.model.EnumVarMap;
3331
import org.openapitools.codegen.model.ModelMap;
3432
import org.openapitools.codegen.model.ModelsMap;
3533
import org.openapitools.codegen.model.OperationsMap;
36-
import org.openapitools.codegen.utils.EnumUtils;
3734
import org.slf4j.Logger;
3835
import org.slf4j.LoggerFactory;
3936

@@ -405,31 +402,11 @@ public ModelsMap postProcessModels(ModelsMap objs) {
405402
boolean isOptionalNullable = Boolean.FALSE.equals(var.required) && Boolean.TRUE.equals(var.isNullable);
406403
// only add JsonNullable and related imports to optional and nullable values
407404
addImports |= isOptionalNullable;
408-
var.getVendorExtensions().put("x-is-jackson-optional-nullable", isOptionalNullable);
405+
var.getVendorExtensions().put(X_IS_JACKSON_OPTIONAL_NULLABLE, isOptionalNullable);
409406
}
410407

411-
if (Boolean.TRUE.equals(var.getVendorExtensions().get("x-enum-as-string"))) {
412-
// treat enum string as just string
413-
var.datatypeWithEnum = var.dataType;
414-
415-
if (StringUtils.isNotEmpty(var.defaultValue)) { // has default value
416-
String defaultValue = var.defaultValue.substring(var.defaultValue.lastIndexOf('.') + 1);
417-
for (EnumVarMap enumVars : EnumUtils.getEnumVars(var.getAllowableValues())) {
418-
if (defaultValue.equals(enumVars.getEnumName())) {
419-
// update default to use the string directly instead of enum string
420-
var.defaultValue = (String) enumVars.getEnumValue();
421-
}
422-
}
423-
}
424-
425-
// add import for Set, HashSet
426-
cm.imports.add("Set");
427-
Map<String, String> importsSet = new HashMap<>();
428-
importsSet.put("import", "java.util.Set");
429-
imports.add(importsSet);
430-
Map<String, String> importsHashSet = new HashMap<>();
431-
importsHashSet.put("import", "java.util.HashSet");
432-
imports.add(importsHashSet);
408+
if (Boolean.TRUE.equals(var.getVendorExtensions().get(X_ENUM_AS_STRING))) {
409+
handleEnumAsString(var, cm, imports);
433410
}
434411

435412
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454

5555
import static org.openapitools.codegen.CodegenConstants.INTERFACE_ONLY;
5656
import static org.openapitools.codegen.CodegenConstants.INTERFACE_ONLY_DESC;
57+
import static org.openapitools.codegen.CodegenConstants.X_IS_JACKSON_OPTIONAL_NULLABLE;
5758
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
5859
import static org.openapitools.codegen.utils.StringUtils.camelize;
5960

@@ -1462,7 +1463,7 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
14621463
// Scenario 4: optional + nullable with openApiNullable → use JsonNullable<T> = JsonNullable.undefined()
14631464
// so callers can distinguish between a missing key and an explicitly provided null.
14641465
if (openApiNullable && !property.required && property.isNullable) {
1465-
property.vendorExtensions.put("x-is-jackson-optional-nullable", true);
1466+
property.vendorExtensions.put(X_IS_JACKSON_OPTIONAL_NULLABLE, true);
14661467
model.imports.add("JsonNullable");
14671468
}
14681469

@@ -1800,7 +1801,7 @@ public ModelsMap postProcessModelsEnum(ModelsMap objs) {
18001801
optionalNonNullPropertyJsonSetterNulls, openApiNullable, true);
18011802
// Scenario 4: optional + nullable with openApiNullable → use JsonNullable<T>
18021803
if (openApiNullable && !var.required && var.isNullable) {
1803-
var.vendorExtensions.put("x-is-jackson-optional-nullable", true);
1804+
var.vendorExtensions.put(X_IS_JACKSON_OPTIONAL_NULLABLE, true);
18041805
}
18051806
resolveJsonIncludePolicy(cm, var);
18061807
}

0 commit comments

Comments
 (0)