Add new option to customize inline model naming convention (#12562)

* temp fix

* add support to customize inline schema naming convention

* Revert "temp fix"

This reverts commit e3bca56bfbb0032d382fe79cd2a8565f4aad630c.

* minor fix, add tests

* update description
This commit is contained in:
William Cheng 2022-06-11 09:12:22 +08:00 committed by GitHub
parent aeb40ab0ae
commit ee9b9843db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 177 additions and 6 deletions

View File

@ -74,6 +74,9 @@ public class ConfigHelp extends OpenApiGeneratorCommand {
@Option(name = {"--inline-schema-name-mappings"}, title = "inline schema name mappings", description = "displays the inline schema name mappings (none)")
private Boolean inlineSchemaNameMappings;
@Option(name = {"--inline-schema-name-defaults"}, title = "inline schema name defaults", description = "default values used when naming inline schema name")
private Boolean inlineSchemaNameDefaults;
@Option(name = {"--metadata"}, title = "metadata", description = "displays the generator metadata like the help txt for the generator and generator type etc")
private Boolean metadata;
@ -464,6 +467,18 @@ public class ConfigHelp extends OpenApiGeneratorCommand {
sb.append(newline);
}
if (Boolean.TRUE.equals(inlineSchemaNameDefaults)) {
sb.append(newline).append("INLINE SCHEMA NAME DEFAULTS").append(newline).append(newline);
Map<String, String> map = config.inlineSchemaNameDefault()
.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, "Inline scheme naming convention", "Defaulted to");
sb.append(newline);
}
if (Boolean.TRUE.equals(instantiationTypes)) {
sb.append(newline).append("INSTANTIATION TYPES").append(newline).append(newline);
Map<String, String> map = config.instantiationTypes()

View File

@ -166,6 +166,13 @@ public class Generate extends OpenApiGeneratorCommand {
+ " You can also have multiple occurrences of this option.")
private List<String> inlineSchemaNameMappings = new ArrayList<>();
@Option(
name = {"--inline-schema-name-defaults"},
title = "inline schema name defaults",
description = "specifies the default values used when naming inline schema as such array items in the format of arrayItemSuffix=_inner,mapItemSuffix=_value. "
+ " ONLY arrayItemSuffix, mapItemSuffix at the moment.")
private List<String> inlineSchemaNameDefaults = new ArrayList<>();
@Option(
name = {"--server-variables"},
title = "server variables",
@ -431,6 +438,7 @@ public class Generate extends OpenApiGeneratorCommand {
applyInstantiationTypesKvpList(instantiationTypes, configurator);
applyImportMappingsKvpList(importMappings, configurator);
applyInlineSchemaNameMappingsKvpList(inlineSchemaNameMappings, configurator);
applyInlineSchemaNameDefaultsKvpList(inlineSchemaNameDefaults, configurator);
applyTypeMappingsKvpList(typeMappings, configurator);
applyAdditionalPropertiesKvpList(additionalProperties, configurator);
applyLanguageSpecificPrimitivesCsvList(languageSpecificPrimitives, configurator);

View File

@ -51,6 +51,7 @@ public final class GeneratorSettings implements Serializable {
private final Map<String, Object> additionalProperties;
private final Map<String, String> importMappings;
private final Map<String, String> inlineSchemaNameMappings;
private final Map<String, String> inlineSchemaNameDefaults;
private final Set<String> languageSpecificPrimitives;
private final Map<String, String> reservedWordsMappings;
private final Map<String, String> serverVariables;
@ -244,6 +245,15 @@ public final class GeneratorSettings implements Serializable {
return inlineSchemaNameMappings;
}
/**
* Gets inline schema name defaults between an inline schema naming convention and the default values.
*
* @return the inline schema name defaults
*/
public Map<String, String> getInlineSchemaNameDefaults() {
return inlineSchemaNameDefaults;
}
/**
* Gets language specific primitives. These are in addition to the "base" primitives defined in a generator.
* <p>
@ -360,6 +370,7 @@ public final class GeneratorSettings implements Serializable {
typeMappings = Collections.unmodifiableMap(builder.typeMappings);
importMappings = Collections.unmodifiableMap(builder.importMappings);
inlineSchemaNameMappings = Collections.unmodifiableMap(builder.inlineSchemaNameMappings);
inlineSchemaNameDefaults = Collections.unmodifiableMap(builder.inlineSchemaNameDefaults);
languageSpecificPrimitives = Collections.unmodifiableSet(builder.languageSpecificPrimitives);
reservedWordsMappings = Collections.unmodifiableMap(builder.reservedWordsMappings);
serverVariables = Collections.unmodifiableMap(builder.serverVariables);
@ -431,6 +442,7 @@ public final class GeneratorSettings implements Serializable {
additionalProperties = Collections.unmodifiableMap(new HashMap<>(0));
importMappings = Collections.unmodifiableMap(new HashMap<>(0));
inlineSchemaNameMappings = Collections.unmodifiableMap(new HashMap<>(0));
inlineSchemaNameDefaults = Collections.unmodifiableMap(new HashMap<>(0));
languageSpecificPrimitives = Collections.unmodifiableSet(new HashSet<>(0));
reservedWordsMappings = Collections.unmodifiableMap(new HashMap<>(0));
serverVariables = Collections.unmodifiableMap(new HashMap<>(0));
@ -485,6 +497,9 @@ public final class GeneratorSettings implements Serializable {
if (copy.getInlineSchemaNameMappings() != null) {
builder.inlineSchemaNameMappings.putAll(copy.getInlineSchemaNameMappings());
}
if (copy.getInlineSchemaNameDefaults() != null) {
builder.inlineSchemaNameDefaults.putAll(copy.getInlineSchemaNameDefaults());
}
if (copy.getLanguageSpecificPrimitives() != null) {
builder.languageSpecificPrimitives.addAll(copy.getLanguageSpecificPrimitives());
}
@ -525,6 +540,7 @@ public final class GeneratorSettings implements Serializable {
private Map<String, Object> additionalProperties;
private Map<String, String> importMappings;
private Map<String, String> inlineSchemaNameMappings;
private Map<String, String> inlineSchemaNameDefaults;
private Set<String> languageSpecificPrimitives;
private Map<String, String> reservedWordsMappings;
private Map<String, String> serverVariables;
@ -543,6 +559,7 @@ public final class GeneratorSettings implements Serializable {
additionalProperties = new HashMap<>();
importMappings = new HashMap<>();
inlineSchemaNameMappings = new HashMap<>();
inlineSchemaNameDefaults = new HashMap<>();
languageSpecificPrimitives = new HashSet<>();
reservedWordsMappings = new HashMap<>();
serverVariables = new HashMap<>();
@ -785,6 +802,32 @@ public final class GeneratorSettings implements Serializable {
return this;
}
/**
* Sets the {@code inlineSchemaNameDefaults} and returns a reference to this Builder so that the methods can be chained together.
*
* @param inlineSchemaNameDefaults the {@code inlineSchemaNameDefaults} to set
* @return a reference to this Builder
*/
public Builder withInlineSchemaNameDefaults(Map<String, String> inlineSchemaNameDefaults) {
this.inlineSchemaNameDefaults = inlineSchemaNameDefaults;
return this;
}
/**
* Sets a single {@code inlineSchemaNameDefaults} and returns a reference to this Builder so that the methods can be chained together.
*
* @param key Default naming convention
* @param value The value
* @return a reference to this Builder
*/
public Builder withInlineSchemaNameDefault(String key, String value) {
if (this.inlineSchemaNameDefaults == null) {
this.inlineSchemaNameDefaults = new HashMap<>();
}
this.inlineSchemaNameDefaults.put(key, value);
return this;
}
/**
* Sets the {@code inlineSchemaNameMappings} and returns a reference to this Builder so that the methods can be chained together.
*
@ -799,8 +842,8 @@ public final class GeneratorSettings implements Serializable {
/**
* Sets a single {@code inlineSchemaNameMappings} and returns a reference to this Builder so that the methods can be chained together.
*
* @param key A key for some import mapping
* @param value The value of some import mapping
* @param key A key for the inline schema mapping
* @param value The value of inline schema mapping
* @return a reference to this Builder
*/
public Builder withInlineSchemaNameMapping(String key, String value) {
@ -997,6 +1040,7 @@ public final class GeneratorSettings implements Serializable {
Objects.equals(getAdditionalProperties(), that.getAdditionalProperties()) &&
Objects.equals(getImportMappings(), that.getImportMappings()) &&
Objects.equals(getInlineSchemaNameMappings(), that.getInlineSchemaNameMappings()) &&
Objects.equals(getInlineSchemaNameDefaults(), that.getInlineSchemaNameDefaults()) &&
Objects.equals(getLanguageSpecificPrimitives(), that.getLanguageSpecificPrimitives()) &&
Objects.equals(getReservedWordsMappings(), that.getReservedWordsMappings()) &&
Objects.equals(getGitHost(), that.getGitHost()) &&
@ -1026,6 +1070,7 @@ public final class GeneratorSettings implements Serializable {
getAdditionalProperties(),
getImportMappings(),
getInlineSchemaNameMappings(),
getInlineSchemaNameDefaults(),
getLanguageSpecificPrimitives(),
getReservedWordsMappings(),
getGitHost(),

View File

@ -114,6 +114,7 @@ class OpenApiGeneratorPlugin : Plugin<Project> {
languageSpecificPrimitives.set(generate.languageSpecificPrimitives)
importMappings.set(generate.importMappings)
inlineSchemaNameMappings.set(generate.inlineSchemaNameMappings)
inlineSchemaNameDefaults.set(generate.inlineSchemaNameDefaults)
invokerPackage.set(generate.invokerPackage)
groupId.set(generate.groupId)
id.set(generate.id)

View File

@ -146,6 +146,11 @@ open class OpenApiGeneratorGenerateExtension(project: Project) {
*/
val inlineSchemaNameMappings = project.objects.mapProperty<String, String>()
/**
* Specifies default values for inline schema naming convention
*/
val inlineSchemaNameDefaults = project.objects.mapProperty<String, String>()
/**
* Root package for generated code.
*/

View File

@ -226,6 +226,13 @@ open class GenerateTask : DefaultTask() {
@Input
val inlineSchemaNameMappings = project.objects.mapProperty<String, String>()
/**
* Specifies default values for inline schema naming convention
*/
@Optional
@Input
val inlineSchemaNameDefaults = project.objects.mapProperty<String, String>()
/**
* Root package for generated code.
*/
@ -691,6 +698,12 @@ open class GenerateTask : DefaultTask() {
}
}
if (inlineSchemaNameDefaults.isPresent) {
inlineSchemaNameDefaults.get().forEach { entry ->
configurator.addInlineSchemaNameDefault(entry.key, entry.value)
}
}
if (typeMappings.isPresent) {
typeMappings.get().forEach { entry ->
configurator.addTypeMapping(entry.key, entry.value)

View File

@ -304,6 +304,12 @@ public class CodeGenMojo extends AbstractMojo {
@Parameter(name = "inlineSchemaNameMappings", property = "openapi.generator.maven.plugin.inlineSchemaNameMappings")
private List<String> inlineSchemaNameMappings;
/**
* A map of inline scheme naming convention and the value
*/
@Parameter(name = "inlineSchemaNameDefaults", property = "openapi.generator.maven.plugin.inlineSchemaNameDefaults")
private List<String> inlineSchemaNameDefaults;
/**
* A map of swagger spec types and the generated code types to use for them
*/
@ -666,11 +672,17 @@ public class CodeGenMojo extends AbstractMojo {
}
// Retained for backwards-compatibility with configOptions -> inline-schema-name-mappings
if (importMappings == null && configOptions.containsKey("inline-schema-name-mappings")) {
if (inlineSchemaNameMappings == null && configOptions.containsKey("inline-schema-name-mappings")) {
applyInlineSchemaNameMappingsKvp(configOptions.get("inline-schema-name-mappings").toString(),
configurator);
}
// Retained for backwards-compatibility with configOptions -> inline-schema-name-defaults
if (inlineSchemaNameDefaults == null && configOptions.containsKey("inline-schema-name-defaults")) {
applyInlineSchemaNameDefaultsKvp(configOptions.get("inline-schema-name-defaults").toString(),
configurator);
}
// Retained for backwards-compatibility with configOptions -> type-mappings
if (typeMappings == null && configOptions.containsKey("type-mappings")) {
applyTypeMappingsKvp(configOptions.get("type-mappings").toString(), configurator);
@ -714,6 +726,11 @@ public class CodeGenMojo extends AbstractMojo {
applyInlineSchemaNameMappingsKvpList(inlineSchemaNameMappings, configurator);
}
// Apply Inline Schema Name Defaults
if (inlineSchemaNameDefaults != null && (configOptions == null || !configOptions.containsKey("inline-schema-name-defaults"))) {
applyInlineSchemaNameDefaultsKvpList(inlineSchemaNameDefaults, configurator);
}
// Apply Type Mappings
if (typeMappings != null && (configOptions == null || !configOptions.containsKey("type-mappings"))) {
applyTypeMappingsKvpList(typeMappings, configurator);

View File

@ -143,6 +143,8 @@ public interface CodegenConfig {
Map<String, String> inlineSchemaNameMapping();
Map<String, String> inlineSchemaNameDefault();
Map<String, String> apiTemplateFiles();
Map<String, String> modelTemplateFiles();

View File

@ -155,6 +155,8 @@ public class DefaultCodegen implements CodegenConfig {
protected Map<String, String> importMapping = new HashMap<>();
// a map to store the mappping between inline schema and the name provided by the user
protected Map<String, String> inlineSchemaNameMapping = new HashMap<>();
// a map to store the inline schema naming conventions
protected Map<String, String> inlineSchemaNameDefault = new HashMap<>();
protected String modelPackage = "", apiPackage = "", fileSuffix;
protected String modelNamePrefix = "", modelNameSuffix = "";
protected String apiNamePrefix = "", apiNameSuffix = "Api";
@ -1063,6 +1065,11 @@ public class DefaultCodegen implements CodegenConfig {
return inlineSchemaNameMapping;
}
@Override
public Map<String, String> inlineSchemaNameDefault() {
return inlineSchemaNameDefault;
}
@Override
public String testPackage() {
return testPackage;

View File

@ -875,6 +875,7 @@ public class DefaultGenerator implements Generator {
if (config.getUseInlineModelResolver()) {
InlineModelResolver inlineModelResolver = new InlineModelResolver();
inlineModelResolver.setInlineSchemaNameMapping(config.inlineSchemaNameMapping());
inlineModelResolver.setInlineSchemaNameDefaults(config.inlineSchemaNameDefault());
inlineModelResolver.flatten(openAPI);
}

View File

@ -42,6 +42,7 @@ public class InlineModelResolver {
private Map<String, Schema> addedModels = new HashMap<>();
private Map<String, String> generatedSignature = new HashMap<>();
private Map<String, String> inlineSchemaNameMapping = new HashMap<>();
private Map<String, String> inlineSchemaNameDefaults = new HashMap<>();
private Set<String> inlineSchemaNameMappingValues = new HashSet<>();
public boolean resolveInlineEnums = false;
@ -60,11 +61,20 @@ public class InlineModelResolver {
final Logger LOGGER = LoggerFactory.getLogger(InlineModelResolver.class);
public InlineModelResolver() {
this.inlineSchemaNameDefaults.put("arrayItemSuffix", "_inner");
this.inlineSchemaNameDefaults.put("mapItemSuffix", "_value");
}
public void setInlineSchemaNameMapping(Map inlineSchemaNameMapping) {
this.inlineSchemaNameMapping = inlineSchemaNameMapping;
this.inlineSchemaNameMappingValues = new HashSet<>(inlineSchemaNameMapping.values());
}
public void setInlineSchemaNameDefaults(Map inlineSchemaNameDefaults) {
this.inlineSchemaNameDefaults.putAll(inlineSchemaNameDefaults);
}
void flatten(OpenAPI openAPI) {
this.openAPI = openAPI;
@ -230,7 +240,7 @@ public class InlineModelResolver {
if (schema.getAdditionalProperties() != null) {
if (schema.getAdditionalProperties() instanceof Schema) {
Schema inner = (Schema) schema.getAdditionalProperties();
String schemaName = resolveModelName(schema.getTitle(), modelPrefix + "_value");
String schemaName = resolveModelName(schema.getTitle(), modelPrefix + this.inlineSchemaNameDefaults.get("mapItemSuffix"));
// Recurse to create $refs for inner models
gatherInlineModels(inner, schemaName);
if (isModelNeeded(inner)) {
@ -265,7 +275,7 @@ public class InlineModelResolver {
" items must be defined for array schemas:\n " + schema.toString());
return;
}
String schemaName = resolveModelName(items.getTitle(), modelPrefix + "_inner");
String schemaName = resolveModelName(items.getTitle(), modelPrefix + this.inlineSchemaNameDefaults.get("arrayItemSuffix"));
// Recurse to create $refs for inner models
gatherInlineModels(items, schemaName);

View File

@ -69,6 +69,7 @@ public class CodegenConfigurator {
private Map<String, Object> additionalProperties = new HashMap<>();
private Map<String, String> importMappings = new HashMap<>();
private Map<String, String> inlineSchemaNameMappings = new HashMap<>();
private Map<String, String> inlineSchemaNameDefaults = new HashMap<>();
private Set<String> languageSpecificPrimitives = new HashSet<>();
private Map<String, String> reservedWordsMappings = new HashMap<>();
private Map<String, String> serverVariables = new HashMap<>();
@ -115,6 +116,9 @@ public class CodegenConfigurator {
if(generatorSettings.getInlineSchemaNameMappings() != null) {
configurator.inlineSchemaNameMappings.putAll(generatorSettings.getInlineSchemaNameMappings());
}
if(generatorSettings.getInlineSchemaNameDefaults() != null) {
configurator.inlineSchemaNameDefaults.putAll(generatorSettings.getInlineSchemaNameDefaults());
}
if(generatorSettings.getLanguageSpecificPrimitives() != null) {
configurator.languageSpecificPrimitives.addAll(generatorSettings.getLanguageSpecificPrimitives());
}
@ -190,6 +194,12 @@ public class CodegenConfigurator {
return this;
}
public CodegenConfigurator addInlineSchemaNameDefault(String key, String value) {
this.inlineSchemaNameDefaults.put(key, value);
generatorSettingsBuilder.withInlineSchemaNameDefault(key, value);
return this;
}
public CodegenConfigurator addInstantiationType(String key, String value) {
this.instantiationTypes.put(key, value);
generatorSettingsBuilder.withInstantiationType(key, value);
@ -350,6 +360,12 @@ public class CodegenConfigurator {
return this;
}
public CodegenConfigurator setInlineSchemaNameDefaults(Map<String, String> inlineSchemaNameDefaults) {
this.inlineSchemaNameDefaults = inlineSchemaNameDefaults;
generatorSettingsBuilder.withInlineSchemaNameDefaults(inlineSchemaNameDefaults);
return this;
}
public CodegenConfigurator setInputSpec(String inputSpec) {
this.inputSpec = inputSpec;
workflowSettingsBuilder.withInputSpec(inputSpec);
@ -627,6 +643,7 @@ public class CodegenConfigurator {
config.typeMapping().putAll(generatorSettings.getTypeMappings());
config.importMapping().putAll(generatorSettings.getImportMappings());
config.inlineSchemaNameMapping().putAll(generatorSettings.getInlineSchemaNameMappings());
config.inlineSchemaNameDefault().putAll(generatorSettings.getInlineSchemaNameDefaults());
config.languageSpecificPrimitives().addAll(generatorSettings.getLanguageSpecificPrimitives());
config.reservedWordsMappings().putAll(generatorSettings.getReservedWordsMappings());
config.additionalProperties().putAll(generatorSettings.getAdditionalProperties());

View File

@ -94,6 +94,19 @@ public final class CodegenConfiguratorUtils {
}
}
public static void applyInlineSchemaNameDefaultsKvpList(List<String> inlineSchemaNameDefaults, CodegenConfigurator configurator) {
for (String propString : inlineSchemaNameDefaults) {
applyInlineSchemaNameDefaultsKvp(propString, configurator);
}
}
public static void applyInlineSchemaNameDefaultsKvp(String inlineSchemaNameDefaults, CodegenConfigurator configurator) {
final Map<String, String> map = createMapFromKeyValuePairs(inlineSchemaNameDefaults);
for (Map.Entry<String, String> entry : map.entrySet()) {
configurator.addInlineSchemaNameDefault(entry.getKey().trim(), entry.getValue().trim());
}
}
public static void applyTypeMappingsKvpList(List<String> typeMappings, CodegenConfigurator configurator) {
for (String propString : typeMappings) {
applyTypeMappingsKvp(propString, configurator);

View File

@ -1020,6 +1020,23 @@ public class InlineModelResolverTest {
assertTrue(nothingNew.getProperties().get("arbitrary_request_body_array_property") instanceof ObjectSchema);
}
@Test
public void testInlineSchemaNameDefault() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/inline_model_resolver.yaml");
InlineModelResolver resolver = new InlineModelResolver();
Map<String, String> inlineSchemaNameDefaults = new HashMap<>();
inlineSchemaNameDefaults.put("arrayItemSuffix", "_something");
resolver.setInlineSchemaNameDefaults(inlineSchemaNameDefaults);
resolver.flatten(openAPI);
Schema schema = openAPI.getComponents().getSchemas().get("resolveInlineArrayRequestBody_request_something");
assertTrue(schema.getProperties().get("street") instanceof StringSchema);
assertTrue(schema.getProperties().get("city") instanceof StringSchema);
Schema nothingNew = openAPI.getComponents().getSchemas().get("arbitraryRequestBodyArrayProperty_request_something");
assertTrue(nothingNew.getProperties().get("arbitrary_request_body_array_property") instanceof ObjectSchema);
}
@Test
public void resolveInlineRequestBodyAllOf() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/inline_model_resolver.yaml");
@ -1037,4 +1054,4 @@ public class InlineModelResolverTest {
//RequestBody referencedRequestBody = ModelUtils.getReferencedRequestBody(openAPI, requestBodyReference);
//assertTrue(referencedRequestBody.getRequired());
}
}
}