Add enum name mapping to Java generators (#17018)

* add enum name mapping to java generators

* update doc

* update description
This commit is contained in:
William Cheng 2023-11-13 10:53:50 +08:00 committed by GitHub
parent 7e529926a6
commit ec3c484ce9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 163 additions and 2 deletions

View File

@ -14,3 +14,6 @@ additionalProperties:
hideGenerationTimestamp: "true"
useOneOfDiscriminatorLookup: "true"
disallowAdditionalPropertiesIfNotPresent: false
enumNameMappings:
s: LOWER_CASE_S
S: UPPER_CASE_S

View File

@ -421,7 +421,13 @@ java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generat
```
will rename the `Tag` schema to `Label` instead.
Not all generators support thess features yet. Please give it a try to confirm the behaviour and open an issue (ticket) to let us know which generators you would like to have this feature enabled and we'll prioritize accordingly. We also welcome PRs to add these features to generators. Related PRs for reference: #16209, #16234 (modelNameMappings), #16194, #16206 (nameMappings, parameterNameMappings).
To map enum names, use `enumNameMappings` option, e.g.
```sh
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -o /tmp/java/ --enum-name-mappings sold=UNAVAILABLE
```
will rename SOLD to UNAVAILABLE instead.
Not all generators support thess features yet. Please give it a try to confirm the behaviour and open an issue (ticket) to let us know which generators you would like to have this feature enabled and we'll prioritize accordingly. We also welcome PRs to add these features to generators. Related PRs for reference: #16209, #16234 (modelNameMappings), #16194, #16206 (nameMappings, parameterNameMappings), #17108 (enumNameMappings).
NOTE: some generators use `baseName` (original name obtained direclty from OpenAPI spec, e.g. `shipping-date`) mustache tag in the templates so the mapping feature won't work.

View File

@ -89,6 +89,9 @@ public class ConfigHelp extends OpenApiGeneratorCommand {
@Option(name = {"--model-name-mappings"}, title = "model name mappings", description = "displays the model name mappings (none)")
private Boolean modelNameMappings;
@Option(name = {"--enum-name-mappings"}, title = "enum name mappings", description = "displays the enum name mappings (none)")
private Boolean enumNameMappings;
@Option(name = {"--openapi-normalizer"}, title = "openapi normalizer rules", description = "displays the OpenAPI normalizer rules (none)")
private Boolean openapiNormalizer;
@ -542,6 +545,18 @@ public class ConfigHelp extends OpenApiGeneratorCommand {
sb.append(newline);
}
if (Boolean.TRUE.equals(enumNameMappings)) {
sb.append(newline).append("ENUM NAME MAPPING").append(newline).append(newline);
Map<String, String> map = config.enumNameMapping()
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> {
throw new IllegalStateException(String.format(Locale.ROOT, "Duplicated options! %s and %s", a, b));
}, TreeMap::new));
writePlainTextFromMap(sb, map, optIndent, optNestedIndent, "enum name", "Mapped to");
sb.append(newline);
}
if (Boolean.TRUE.equals(openapiNormalizer)) {
sb.append(newline).append("OPENAPI NORMALIZER RULES").append(newline).append(newline);
Map<String, String> map = config.openapiNormalizer()

View File

@ -209,6 +209,13 @@ public class Generate extends OpenApiGeneratorCommand {
+ " You can also have multiple occurrences of this option.")
private List<String> modelNameMappings = new ArrayList<>();
@Option(
name = {"--enum-name-mappings"},
title = "enum name mappings",
description = "specifies mappings between the enum name and the new name in the format of enum_name=AnotherName,enum_name2=OtherName2."
+ " You can also have multiple occurrences of this option.")
private List<String> enumNameMappings = new ArrayList<>();
@Option(
name = {"--openapi-normalizer"},
title = "OpenAPI normalizer rules",
@ -492,6 +499,7 @@ public class Generate extends OpenApiGeneratorCommand {
applyNameMappingsKvpList(nameMappings, configurator);
applyParameterNameMappingsKvpList(parameterNameMappings, configurator);
applyModelNameMappingsKvpList(modelNameMappings, configurator);
applyEnumNameMappingsKvpList(enumNameMappings, configurator);
applyOpenAPINormalizerKvpList(openapiNormalizer, configurator);
applyTypeMappingsKvpList(typeMappings, configurator);
applyAdditionalPropertiesKvpList(additionalProperties, configurator);

View File

@ -56,6 +56,7 @@ public final class GeneratorSettings implements Serializable {
private final Map<String, String> nameMappings;
private final Map<String, String> parameterNameMappings;
private final Map<String, String> modelNameMappings;
private final Map<String, String> enumNameMappings;
private final Map<String, String> openapiNormalizer;
private final Set<String> languageSpecificPrimitives;
private final Map<String, String> reservedWordsMappings;
@ -295,6 +296,15 @@ public final class GeneratorSettings implements Serializable {
return modelNameMappings;
}
/**
* Gets enum name mappings between an enum name and the new name.
*
* @return the enum name mappings
*/
public Map<String, String> getEnumNameMappings() {
return enumNameMappings;
}
/**
* Gets OpenAPI normalizer rules
*
@ -425,6 +435,7 @@ public final class GeneratorSettings implements Serializable {
nameMappings = Collections.unmodifiableMap(builder.nameMappings);
parameterNameMappings = Collections.unmodifiableMap(builder.parameterNameMappings);
modelNameMappings = Collections.unmodifiableMap(builder.modelNameMappings);
enumNameMappings = Collections.unmodifiableMap(builder.enumNameMappings);
openapiNormalizer = Collections.unmodifiableMap(builder.openapiNormalizer);
languageSpecificPrimitives = Collections.unmodifiableSet(builder.languageSpecificPrimitives);
reservedWordsMappings = Collections.unmodifiableMap(builder.reservedWordsMappings);
@ -502,6 +513,7 @@ public final class GeneratorSettings implements Serializable {
nameMappings = Collections.unmodifiableMap(new HashMap<>(0));
parameterNameMappings = Collections.unmodifiableMap(new HashMap<>(0));
modelNameMappings = Collections.unmodifiableMap(new HashMap<>(0));
enumNameMappings = Collections.unmodifiableMap(new HashMap<>(0));
openapiNormalizer = Collections.unmodifiableMap(new HashMap<>(0));
languageSpecificPrimitives = Collections.unmodifiableSet(new HashSet<>(0));
reservedWordsMappings = Collections.unmodifiableMap(new HashMap<>(0));
@ -572,6 +584,9 @@ public final class GeneratorSettings implements Serializable {
if (copy.getModelNameMappings() != null) {
builder.modelNameMappings.putAll(copy.getModelNameMappings());
}
if (copy.getEnumNameMappings() != null) {
builder.enumNameMappings.putAll(copy.getEnumNameMappings());
}
if (copy.getOpenAPINormalizer() != null) {
builder.openapiNormalizer.putAll(copy.getOpenAPINormalizer());
}
@ -620,6 +635,7 @@ public final class GeneratorSettings implements Serializable {
private Map<String, String> nameMappings;
private Map<String, String> parameterNameMappings;
private Map<String, String> modelNameMappings;
private Map<String, String> enumNameMappings;
private Map<String, String> openapiNormalizer;
private Set<String> languageSpecificPrimitives;
private Map<String, String> reservedWordsMappings;
@ -644,6 +660,7 @@ public final class GeneratorSettings implements Serializable {
nameMappings = new HashMap<>();
parameterNameMappings = new HashMap<>();
modelNameMappings = new HashMap<>();
enumNameMappings = new HashMap<>();
openapiNormalizer = new HashMap<>();
languageSpecificPrimitives = new HashSet<>();
reservedWordsMappings = new HashMap<>();
@ -1043,6 +1060,32 @@ public final class GeneratorSettings implements Serializable {
return this;
}
/**
* Sets the {@code enumNameMappings} and returns a reference to this Builder so that the methods can be chained together.
*
* @param enumNameMappings the {@code enumNameMappings} to set
* @return a reference to this Builder
*/
public Builder withEnumNameMappings(Map<String, String> enumNameMappings) {
this.enumNameMappings = enumNameMappings;
return this;
}
/**
* Sets a single {@code enumNameMappings} and returns a reference to this Builder so that the methods can be chained together.
*
* @param key A key for the name mapping
* @param value The value of name mapping
* @return a reference to this Builder
*/
public Builder withEnumNameMapping(String key, String value) {
if (this.enumNameMappings == null) {
this.enumNameMappings = new HashMap<>();
}
this.enumNameMappings.put(key, value);
return this;
}
/**
* Sets the {@code openapiNormalizer} and returns a reference to this Builder so that the methods can be chained together.
*
@ -1259,6 +1302,7 @@ public final class GeneratorSettings implements Serializable {
Objects.equals(getNameMappings(), that.getNameMappings()) &&
Objects.equals(getParameterNameMappings(), that.getParameterNameMappings()) &&
Objects.equals(getModelNameMappings(), that.getModelNameMappings()) &&
Objects.equals(getEnumNameMappings(), that.getEnumNameMappings()) &&
Objects.equals(getOpenAPINormalizer(), that.getOpenAPINormalizer()) &&
Objects.equals(getLanguageSpecificPrimitives(), that.getLanguageSpecificPrimitives()) &&
Objects.equals(getReservedWordsMappings(), that.getReservedWordsMappings()) &&
@ -1294,6 +1338,7 @@ public final class GeneratorSettings implements Serializable {
getNameMappings(),
getParameterNameMappings(),
getModelNameMappings(),
getEnumNameMappings(),
getOpenAPINormalizer(),
getLanguageSpecificPrimitives(),
getReservedWordsMappings(),

View File

@ -182,6 +182,11 @@ open class OpenApiGeneratorGenerateExtension(project: Project) {
*/
val modelNameMappings = project.objects.mapProperty<String, String>()
/**
* Specifies mappings between an enum name and the new name
*/
val enumNameMappings = project.objects.mapProperty<String, String>()
/**
* Specifies mappings (rules) in OpenAPI normalizer
*/

View File

@ -293,6 +293,13 @@ open class GenerateTask @Inject constructor(private val objectFactory: ObjectFac
@Input
val modelNameMappings = project.objects.mapProperty<String, String>()
/**
* Specifies mappings between the enum name and the new name
*/
@Optional
@Input
val enumNameMappings = project.objects.mapProperty<String, String>()
/**
* Specifies mappings (rules) in OpenAPI normalizer
*/
@ -852,6 +859,12 @@ open class GenerateTask @Inject constructor(private val objectFactory: ObjectFac
}
}
if (enumNameMappings.isPresent) {
enumNameMappings.get().forEach { entry ->
configurator.addEnumNameMapping(entry.key, entry.value)
}
}
if (openapiNormalizer.isPresent) {
openapiNormalizer.get().forEach { entry ->
configurator.addOpenAPINormalizer(entry.key, entry.value)

View File

@ -350,6 +350,12 @@ public class CodeGenMojo extends AbstractMojo {
@Parameter(name = "modelNameMappings", property = "openapi.generator.maven.plugin.modelNameMappings")
private List<String> modelNameMappings;
/**
* A map of enum names and the new names
*/
@Parameter(name = "enumNameMappings", property = "openapi.generator.maven.plugin.enumNameMappings")
private List<String> enumNameMappings;
/**
* A set of rules for OpenAPI normalizer
*/
@ -834,6 +840,11 @@ public class CodeGenMojo extends AbstractMojo {
applyModelNameMappingsKvpList(modelNameMappings, configurator);
}
// Apply Enum Name Mappings
if (enumNameMappings != null && (configOptions == null || !configOptions.containsKey("enum-name-mappings"))) {
applyEnumNameMappingsKvpList(enumNameMappings, configurator);
}
// Apply OpenAPI normalizer rules
if (openapiNormalizer != null && (configOptions == null || !configOptions.containsKey("openapi-normalizer"))) {
applyOpenAPINormalizerKvpList(openapiNormalizer, configurator);

View File

@ -155,6 +155,8 @@ public interface CodegenConfig {
Map<String, String> modelNameMapping();
Map<String, String> enumNameMapping();
Map<String, String> openapiNormalizer();
Map<String, String> apiTemplateFiles();

View File

@ -173,6 +173,8 @@ public class DefaultCodegen implements CodegenConfig {
protected Map<String, String> parameterNameMapping = new HashMap<>();
// a map to store the mapping between model name and the name provided by the user
protected Map<String, String> modelNameMapping = new HashMap<>();
// a map to store the mapping between enum name and the name provided by the user
protected Map<String, String> enumNameMapping = new HashMap<>();
// a map to store the rules in OpenAPI Normalizer
protected Map<String, String> openapiNormalizer = new HashMap<>();
protected String modelPackage = "", apiPackage = "", fileSuffix;
@ -1244,6 +1246,11 @@ public class DefaultCodegen implements CodegenConfig {
return modelNameMapping;
}
@Override
public Map<String, String> enumNameMapping() {
return enumNameMapping;
}
@Override
public Map<String, String> openapiNormalizer() {
return openapiNormalizer;

View File

@ -74,6 +74,7 @@ public class CodegenConfigurator {
private Map<String, String> nameMappings = new HashMap<>();
private Map<String, String> parameterNameMappings = new HashMap<>();
private Map<String, String> modelNameMappings = new HashMap<>();
private Map<String, String> enumNameMappings = new HashMap<>();
private Map<String, String> openapiNormalizer = new HashMap<>();
private Set<String> languageSpecificPrimitives = new HashSet<>();
private Map<String, String> reservedWordsMappings = new HashMap<>();
@ -136,6 +137,9 @@ public class CodegenConfigurator {
if(generatorSettings.getModelNameMappings() != null) {
configurator.modelNameMappings.putAll(generatorSettings.getModelNameMappings());
}
if(generatorSettings.getEnumNameMappings() != null) {
configurator.enumNameMappings.putAll(generatorSettings.getEnumNameMappings());
}
if(generatorSettings.getOpenAPINormalizer() != null) {
configurator.openapiNormalizer.putAll(generatorSettings.getOpenAPINormalizer());
}
@ -244,6 +248,12 @@ public class CodegenConfigurator {
return this;
}
public CodegenConfigurator addEnumNameMapping(String key, String value) {
this.enumNameMappings.put(key, value);
generatorSettingsBuilder.withEnumNameMapping(key, value);
return this;
}
public CodegenConfigurator addOpenAPINormalizer(String key, String value) {
this.openapiNormalizer.put(key, value);
generatorSettingsBuilder.withOpenAPINormalizer(key, value);
@ -440,6 +450,12 @@ public class CodegenConfigurator {
return this;
}
public CodegenConfigurator setEnumNameMappings(Map<String, String> enumNameMappings) {
this.enumNameMappings = enumNameMappings;
generatorSettingsBuilder.withEnumNameMappings(enumNameMappings);
return this;
}
public CodegenConfigurator setOpenAPINormalizer(Map<String, String> openapiNormalizer) {
this.openapiNormalizer = openapiNormalizer;
generatorSettingsBuilder.withOpenAPINormalizer(openapiNormalizer);
@ -728,6 +744,7 @@ public class CodegenConfigurator {
config.nameMapping().putAll(generatorSettings.getNameMappings());
config.parameterNameMapping().putAll(generatorSettings.getParameterNameMappings());
config.modelNameMapping().putAll(generatorSettings.getModelNameMappings());
config.enumNameMapping().putAll(generatorSettings.getEnumNameMappings());
config.openapiNormalizer().putAll(generatorSettings.getOpenAPINormalizer());
config.languageSpecificPrimitives().addAll(generatorSettings.getLanguageSpecificPrimitives());
config.reservedWordsMappings().putAll(generatorSettings.getReservedWordsMappings());

View File

@ -159,6 +159,19 @@ public final class CodegenConfiguratorUtils {
}
}
public static void applyEnumNameMappingsKvpList(List<String> enumNameMappings, CodegenConfigurator configurator) {
for (String propString : enumNameMappings) {
applyEnumNameMappingsKvp(propString, configurator);
}
}
public static void applyEnumNameMappingsKvp(String enumNameMappings, CodegenConfigurator configurator) {
final Map<String, String> map = createMapFromKeyValuePairs(enumNameMappings);
for (Map.Entry<String, String> entry : map.entrySet()) {
configurator.addEnumNameMapping(entry.getKey().trim(), entry.getValue().trim());
}
}
public static void applyOpenAPINormalizerKvpList(List<String> openapiNormalizer, CodegenConfigurator configurator) {
for (String propString : openapiNormalizer) {
applyOpenAPINormalizerKvp(propString, configurator);

View File

@ -1689,6 +1689,10 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Override
public String toEnumVarName(String value, String datatype) {
if (enumNameMapping.containsKey(value)) {
return enumNameMapping.get(value);
}
if (value.length() == 0) {
return "EMPTY";
}

View File

@ -1836,6 +1836,8 @@ components:
- placed
- approved
- delivered
- s
- S
OuterEnumInteger:
type: integer
enum:

View File

@ -1861,6 +1861,8 @@ components:
- placed
- approved
- delivered
- s
- S
nullable: true
type: string
OuterEnumInteger:

View File

@ -11,5 +11,9 @@
* `DELIVERED` (value: `"delivered"`)
* `LOWER_CASE_S` (value: `"s"`)
* `UPPER_CASE_S` (value: `"S"`)

View File

@ -33,7 +33,11 @@ public enum OuterEnum {
APPROVED("approved"),
DELIVERED("delivered");
DELIVERED("delivered"),
LOWER_CASE_S("s"),
UPPER_CASE_S("S");
private String value;