New option to map inline schema names (#12237)

* add option to specify inline schema nam mapping

* update samples

* update samples

* add new option to plugins

* better code format

* better code format

* better log info

* better docstring

* add tests
This commit is contained in:
William Cheng 2022-04-27 01:13:45 +08:00 committed by GitHub
parent 356732d1bd
commit 53eebc953f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 634 additions and 121 deletions

View File

@ -71,6 +71,9 @@ public class ConfigHelp extends OpenApiGeneratorCommand {
@Option(name = {"--import-mappings"}, title = "import mappings", description = "displays the default import mappings (types and aliases, and what imports they will pull into the template)")
private Boolean importMappings;
@Option(name = {"--inline-schema-name-mappings"}, title = "inline schema name mappings", description = "displays the inline schema name mappings (none)")
private Boolean inlineSchemaNameMappings;
@Option(name = {"--metadata"}, title = "metadata", description = "displays the generator metadata like the help txt for the generator and generator type etc")
private Boolean metadata;
@ -449,6 +452,18 @@ public class ConfigHelp extends OpenApiGeneratorCommand {
sb.append(newline);
}
if (Boolean.TRUE.equals(inlineSchemaNameMappings)) {
sb.append(newline).append("INLINE SCHEMA NAME MAPPING").append(newline).append(newline);
Map<String, String> map = config.inlineSchemaNameMapping()
.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 name", "Mapped 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

@ -159,6 +159,13 @@ public class Generate extends OpenApiGeneratorCommand {
+ " You can also have multiple occurrences of this option.")
private List<String> importMappings = new ArrayList<>();
@Option(
name = {"--inline-schema-name-mappings"},
title = "inline schema name mappings",
description = "specifies mappings between the inline schema name and the new name in the format of inline_object_2=Cat,inline_object_5=Bird."
+ " You can also have multiple occurrences of this option.")
private List<String> inlineSchemaNameMappings = new ArrayList<>();
@Option(
name = {"--server-variables"},
title = "server variables",
@ -423,6 +430,7 @@ public class Generate extends OpenApiGeneratorCommand {
}
applyInstantiationTypesKvpList(instantiationTypes, configurator);
applyImportMappingsKvpList(importMappings, configurator);
applyInlineSchemaNameMappingsKvpList(inlineSchemaNameMappings, configurator);
applyTypeMappingsKvpList(typeMappings, configurator);
applyAdditionalPropertiesKvpList(additionalProperties, configurator);
applyLanguageSpecificPrimitivesCsvList(languageSpecificPrimitives, configurator);

View File

@ -50,6 +50,7 @@ public final class GeneratorSettings implements Serializable {
private final Map<String, String> typeMappings;
private final Map<String, Object> additionalProperties;
private final Map<String, String> importMappings;
private final Map<String, String> inlineSchemaNameMappings;
private final Set<String> languageSpecificPrimitives;
private final Map<String, String> reservedWordMappings;
private final Map<String, String> serverVariables;
@ -234,6 +235,15 @@ public final class GeneratorSettings implements Serializable {
return importMappings;
}
/**
* Gets inline schema name mappings between an inline schema name and the new name.
*
* @return the inline schema name mappings
*/
public Map<String, String> getInlineSchemaNameMappings() {
return inlineSchemaNameMappings;
}
/**
* Gets language specific primitives. These are in addition to the "base" primitives defined in a generator.
* <p>
@ -349,6 +359,7 @@ public final class GeneratorSettings implements Serializable {
instantiationTypes = Collections.unmodifiableMap(builder.instantiationTypes);
typeMappings = Collections.unmodifiableMap(builder.typeMappings);
importMappings = Collections.unmodifiableMap(builder.importMappings);
inlineSchemaNameMappings = Collections.unmodifiableMap(builder.inlineSchemaNameMappings);
languageSpecificPrimitives = Collections.unmodifiableSet(builder.languageSpecificPrimitives);
reservedWordMappings = Collections.unmodifiableMap(builder.reservedWordMappings);
serverVariables = Collections.unmodifiableMap(builder.serverVariables);
@ -419,6 +430,7 @@ public final class GeneratorSettings implements Serializable {
typeMappings = Collections.unmodifiableMap(new HashMap<>(0));
additionalProperties = Collections.unmodifiableMap(new HashMap<>(0));
importMappings = Collections.unmodifiableMap(new HashMap<>(0));
inlineSchemaNameMappings = Collections.unmodifiableMap(new HashMap<>(0));
languageSpecificPrimitives = Collections.unmodifiableSet(new HashSet<>(0));
reservedWordMappings = Collections.unmodifiableMap(new HashMap<>(0));
serverVariables = Collections.unmodifiableMap(new HashMap<>(0));
@ -470,6 +482,9 @@ public final class GeneratorSettings implements Serializable {
if (copy.getImportMappings() != null) {
builder.importMappings.putAll(copy.getImportMappings());
}
if (copy.getInlineSchemaNameMappings() != null) {
builder.inlineSchemaNameMappings.putAll(copy.getInlineSchemaNameMappings());
}
if (copy.getLanguageSpecificPrimitives() != null) {
builder.languageSpecificPrimitives.addAll(copy.getLanguageSpecificPrimitives());
}
@ -509,6 +524,7 @@ public final class GeneratorSettings implements Serializable {
private Map<String, String> typeMappings;
private Map<String, Object> additionalProperties;
private Map<String, String> importMappings;
private Map<String, String> inlineSchemaNameMappings;
private Set<String> languageSpecificPrimitives;
private Map<String, String> reservedWordMappings;
private Map<String, String> serverVariables;
@ -526,6 +542,7 @@ public final class GeneratorSettings implements Serializable {
typeMappings = new HashMap<>();
additionalProperties = new HashMap<>();
importMappings = new HashMap<>();
inlineSchemaNameMappings = new HashMap<>();
languageSpecificPrimitives = new HashSet<>();
reservedWordMappings = new HashMap<>();
serverVariables = new HashMap<>();
@ -768,6 +785,32 @@ public final class GeneratorSettings implements Serializable {
return this;
}
/**
* Sets the {@code inlineSchemaNameMappings} and returns a reference to this Builder so that the methods can be chained together.
*
* @param inlineSchemaNameMappings the {@code inlineSchemaNameMappings} to set
* @return a reference to this Builder
*/
public Builder withInlineSchemaNameMappings(Map<String, String> inlineSchemaNameMappings) {
this.inlineSchemaNameMappings = inlineSchemaNameMappings;
return this;
}
/**
* 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
* @return a reference to this Builder
*/
public Builder withInlineSchemaNameMapping(String key, String value) {
if (this.inlineSchemaNameMappings == null) {
this.inlineSchemaNameMappings = new HashMap<>();
}
this.inlineSchemaNameMappings.put(key, value);
return this;
}
/**
* Sets the {@code languageSpecificPrimitives} and returns a reference to this Builder so that the methods can be chained together.
*
@ -953,6 +996,7 @@ public final class GeneratorSettings implements Serializable {
Objects.equals(getTypeMappings(), that.getTypeMappings()) &&
Objects.equals(getAdditionalProperties(), that.getAdditionalProperties()) &&
Objects.equals(getImportMappings(), that.getImportMappings()) &&
Objects.equals(getInlineSchemaNameMappings(), that.getInlineSchemaNameMappings()) &&
Objects.equals(getLanguageSpecificPrimitives(), that.getLanguageSpecificPrimitives()) &&
Objects.equals(getReservedWordMappings(), that.getReservedWordMappings()) &&
Objects.equals(getGitHost(), that.getGitHost()) &&
@ -981,6 +1025,7 @@ public final class GeneratorSettings implements Serializable {
getTypeMappings(),
getAdditionalProperties(),
getImportMappings(),
getInlineSchemaNameMappings(),
getLanguageSpecificPrimitives(),
getReservedWordMappings(),
getGitHost(),

View File

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

View File

@ -141,6 +141,11 @@ open class OpenApiGeneratorGenerateExtension(project: Project) {
*/
val importMappings = project.objects.mapProperty<String, String>()
/**
* Specifies mappings between an inline schema name and the new name
*/
val inlineSchemaNameMappings = project.objects.mapProperty<String, String>()
/**
* Root package for generated code.
*/

View File

@ -219,6 +219,13 @@ open class GenerateTask : DefaultTask() {
@Input
val importMappings = project.objects.mapProperty<String, String>()
/**
* Specifies mappings between the inline scheme name and the new name
*/
@Optional
@Input
val inlineSchemaNameMappings = project.objects.mapProperty<String, String>()
/**
* Root package for generated code.
*/
@ -678,6 +685,12 @@ open class GenerateTask : DefaultTask() {
}
}
if (inlineSchemaNameMappings.isPresent) {
inlineSchemaNameMappings.get().forEach { entry ->
configurator.addInlineSchemaNameMapping(entry.key, entry.value)
}
}
if (typeMappings.isPresent) {
typeMappings.get().forEach { entry ->
configurator.addTypeMapping(entry.key, entry.value)

View File

@ -298,6 +298,12 @@ public class CodeGenMojo extends AbstractMojo {
@Parameter(name = "importMappings", property = "openapi.generator.maven.plugin.importMappings")
private List<String> importMappings;
/**
* A map of inline scheme names and the new names
*/
@Parameter(name = "inlineSchemaNameMappings", property = "openapi.generator.maven.plugin.inlineSchemaNameMappings")
private List<String> inlineSchemaNameMappings;
/**
* A map of swagger spec types and the generated code types to use for them
*/
@ -659,6 +665,12 @@ public class CodeGenMojo extends AbstractMojo {
configurator);
}
// Retained for backwards-compatibility with configOptions -> inline-schema-name-mappings
if (importMappings == null && configOptions.containsKey("inline-schema-name-mappings")) {
applyInlineSchemaNameMappingsKvp(configOptions.get("inline-schema-name-mappings").toString(),
configurator);
}
// Retained for backwards-compatibility with configOptions -> type-mappings
if (typeMappings == null && configOptions.containsKey("type-mappings")) {
applyTypeMappingsKvp(configOptions.get("type-mappings").toString(), configurator);
@ -697,6 +709,11 @@ public class CodeGenMojo extends AbstractMojo {
applyImportMappingsKvpList(importMappings, configurator);
}
// Apply Inline Schema Name Mappings
if (inlineSchemaNameMappings != null && (configOptions == null || !configOptions.containsKey("inline-schema-name-mappings"))) {
applyInlineSchemaNameMappingsKvpList(inlineSchemaNameMappings, configurator);
}
// Apply Type Mappings
if (typeMappings != null && (configOptions == null || !configOptions.containsKey("type-mappings"))) {
applyTypeMappingsKvpList(typeMappings, configurator);

View File

@ -141,6 +141,8 @@ public interface CodegenConfig {
Map<String, String> importMapping();
Map<String, String> inlineSchemaNameMapping();
Map<String, String> apiTemplateFiles();
Map<String, String> modelTemplateFiles();
@ -284,6 +286,7 @@ public interface CodegenConfig {
/**
* Set the OpenAPI instance. This method needs to be called right after the instantiation of the Codegen class.
*
* @param openAPI specification being generated
*/
void setOpenAPI(OpenAPI openAPI);

View File

@ -152,6 +152,8 @@ public class DefaultCodegen implements CodegenConfig {
protected Set<String> reservedWords;
protected Set<String> languageSpecificPrimitives = new HashSet<>();
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<>();
protected String modelPackage = "", apiPackage = "", fileSuffix;
protected String modelNamePrefix = "", modelNameSuffix = "";
protected String apiNamePrefix = "", apiNameSuffix = "Api";
@ -1055,6 +1057,11 @@ public class DefaultCodegen implements CodegenConfig {
return importMapping;
}
@Override
public Map<String, String> inlineSchemaNameMapping() {
return inlineSchemaNameMapping;
}
@Override
public String testPackage() {
return testPackage;

View File

@ -874,6 +874,7 @@ public class DefaultGenerator implements Generator {
// resolve inline models
if (config.getUseInlineModelResolver()) {
InlineModelResolver inlineModelResolver = new InlineModelResolver();
inlineModelResolver.setInlineSchemaNameMapping(config.inlineSchemaNameMapping());
inlineModelResolver.flatten(openAPI);
}

View File

@ -39,14 +39,19 @@ import java.util.stream.Collectors;
public class InlineModelResolver {
private OpenAPI openAPI;
private Map<String, Schema> addedModels = new HashMap<String, Schema>();
private Map<String, String> generatedSignature = new HashMap<String, String>();
private Map<String, Schema> addedModels = new HashMap<>();
private Map<String, String> generatedSignature = new HashMap<>();
private Map<String, String> inlineSchemaNameMapping = new HashMap<>();
private Set<String> inlineSchemaNameMappingValues = new HashSet<>();
public boolean resolveInlineEnums = false;
// structure mapper sorts properties alphabetically on write to ensure models are
// serialized consistently for lookup of existing models
private static ObjectMapper structureMapper;
// a set to keep track of names generated for inline schemas
private Set<String> uniqueNames = new HashSet<>();
static {
structureMapper = Json.mapper().copy();
structureMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
@ -55,6 +60,11 @@ public class InlineModelResolver {
final Logger LOGGER = LoggerFactory.getLogger(InlineModelResolver.class);
public void setInlineSchemaNameMapping(Map inlineSchemaNameMapping) {
this.inlineSchemaNameMapping = inlineSchemaNameMapping;
this.inlineSchemaNameMappingValues = new HashSet<>(inlineSchemaNameMapping.values());
}
void flatten(OpenAPI openAPI) {
this.openAPI = openAPI;
@ -326,9 +336,7 @@ public class InlineModelResolver {
flattenProperties(openAPI, obj.getProperties(), pathname);
// for model name, use "title" if defined, otherwise default to 'inline_object'
String modelName = resolveModelName(obj.getTitle(), "inline_object");
addGenerated(modelName, model);
openAPI.getComponents().addSchemas(modelName, model);
modelName = addSchemas(modelName, model);
// create request body
RequestBody rb = new RequestBody();
rb.setRequired(requestBody.getRequired());
@ -384,11 +392,10 @@ public class InlineModelResolver {
schema.setRequired(op.getRequired());
am.setItems(schema);
} else {
modelName = addSchemas(modelName, innerModel);
Schema schema = new Schema().$ref(modelName);
schema.setRequired(op.getRequired());
am.setItems(schema);
addGenerated(modelName, innerModel);
openAPI.getComponents().addSchemas(modelName, innerModel);
}
}
}
@ -419,10 +426,8 @@ public class InlineModelResolver {
if (obj.getProperties() != null && obj.getProperties().size() > 0) {
flattenProperties(openAPI, obj.getProperties(), pathname);
String modelName = resolveModelName(obj.getTitle(), parameter.getName());
modelName = addSchemas(modelName, model);
parameter.$ref(modelName);
addGenerated(modelName, model);
openAPI.getComponents().addSchemas(modelName, model);
}
}
} else if (model instanceof ArraySchema) {
@ -440,11 +445,10 @@ public class InlineModelResolver {
schema.setRequired(op.getRequired());
am.setItems(schema);
} else {
modelName = addSchemas(modelName, innerModel);
Schema schema = new Schema().$ref(modelName);
schema.setRequired(op.getRequired());
am.setItems(schema);
addGenerated(modelName, innerModel);
openAPI.getComponents().addSchemas(modelName, innerModel);
}
}
}
@ -485,11 +489,10 @@ public class InlineModelResolver {
schema.setRequired(op.getRequired());
mediaType.setSchema(schema);
} else {
modelName = addSchemas(modelName, model);
Schema schema = this.makeSchema(modelName, property);
schema.setRequired(op.getRequired());
mediaType.setSchema(schema);
addGenerated(modelName, model);
openAPI.getComponents().addSchemas(modelName, model);
}
}
}
@ -509,11 +512,10 @@ public class InlineModelResolver {
schema.setRequired(op.getRequired());
ap.setItems(schema);
} else {
modelName = addSchemas(modelName, innerModel);
Schema schema = this.makeSchema(modelName, op);
schema.setRequired(op.getRequired());
ap.setItems(schema);
addGenerated(modelName, innerModel);
openAPI.getComponents().addSchemas(modelName, innerModel);
}
}
}
@ -533,11 +535,10 @@ public class InlineModelResolver {
schema.setRequired(op.getRequired());
mp.setAdditionalProperties(schema);
} else {
modelName = addSchemas(modelName, innerModel);
Schema schema = new Schema().$ref(modelName);
schema.setRequired(op.getRequired());
mp.setAdditionalProperties(schema);
addGenerated(modelName, innerModel);
openAPI.getComponents().addSchemas(modelName, innerModel);
}
}
}
@ -596,8 +597,7 @@ public class InlineModelResolver {
Schema innerModel = modelFromProperty(openAPI, component, innerModelName);
String existing = matchGenerated(innerModel);
if (existing == null) {
openAPI.getComponents().addSchemas(innerModelName, innerModel);
addGenerated(innerModelName, innerModel);
innerModelName = addSchemas(innerModelName, innerModel);
Schema schema = new Schema().$ref(innerModelName);
schema.setRequired(component.getRequired());
listIterator.set(schema);
@ -697,8 +697,7 @@ public class InlineModelResolver {
private String resolveModelName(String title, String key) {
if (title == null) {
if (key == null) {
LOGGER.warn("Found an inline schema without the `title` attribute. Default the model name to InlineObject instead. To have better control of the model naming, define the model separately so that it can be reused throughout the spec.");
return uniqueName("InlineObject");
return uniqueName("inline_object");
}
return uniqueName(sanitizeName(key));
} else {
@ -740,19 +739,20 @@ public class InlineModelResolver {
}
private String uniqueName(final String name) {
if (openAPI.getComponents().getSchemas() == null) {
if (openAPI.getComponents().getSchemas() == null) { // no schema has been created
uniqueNames.add(name);
return name;
}
String uniqueName = name;
int count = 0;
while (true) {
if (!openAPI.getComponents().getSchemas().containsKey(uniqueName)) {
if (!openAPI.getComponents().getSchemas().containsKey(uniqueName) && !uniqueNames.contains(uniqueName)) {
uniqueNames.add(uniqueName);
return uniqueName;
}
uniqueName = name + "_" + ++count;
}
// TODO it would probably be a good idea to check against a list of used uniqueNames to make sure there are no collisions
}
private void flattenProperties(OpenAPI openAPI, Map<String, Schema> properties, String path) {
@ -775,12 +775,11 @@ public class InlineModelResolver {
schema.setRequired(op.getRequired());
propsToUpdate.put(key, schema);
} else {
modelName = addSchemas(modelName, model);
Schema schema = new Schema().$ref(modelName);
schema.setRequired(op.getRequired());
propsToUpdate.put(key, schema);
modelsToAdd.put(modelName, model);
addGenerated(modelName, model);
openAPI.getComponents().addSchemas(modelName, model);
}
} else if (property instanceof ArraySchema) {
ArraySchema ap = (ArraySchema) property;
@ -797,11 +796,10 @@ public class InlineModelResolver {
schema.setRequired(op.getRequired());
ap.setItems(schema);
} else {
modelName = addSchemas(modelName, innerModel);
Schema schema = new Schema().$ref(modelName);
schema.setRequired(op.getRequired());
ap.setItems(schema);
addGenerated(modelName, innerModel);
openAPI.getComponents().addSchemas(modelName, innerModel);
}
}
}
@ -820,11 +818,10 @@ public class InlineModelResolver {
schema.setRequired(op.getRequired());
property.setAdditionalProperties(schema);
} else {
modelName = addSchemas(modelName, innerModel);
Schema schema = new Schema().$ref(modelName);
schema.setRequired(op.getRequired());
property.setAdditionalProperties(schema);
addGenerated(modelName, innerModel);
openAPI.getComponents().addSchemas(modelName, innerModel);
}
}
}
@ -934,9 +931,8 @@ public class InlineModelResolver {
if (resolveInlineEnums && schema.getEnum() != null && schema.getEnum().size() > 0) {
LOGGER.warn("Model " + name + " promoted to its own schema due to resolveInlineEnums=true");
}
name = addSchemas(name, schema);
refSchema = new Schema().$ref(name);
addGenerated(name, schema);
openAPI.getComponents().addSchemas(name, schema);
}
this.copyVendorExtensions(schema, refSchema);
return refSchema;
@ -961,7 +957,6 @@ public class InlineModelResolver {
* @param source source property
* @param target target property
*/
private void copyVendorExtensions(Schema source, Schema target) {
Map<String, Object> vendorExtensions = source.getExtensions();
if (vendorExtensions == null) {
@ -971,4 +966,28 @@ public class InlineModelResolver {
target.addExtension(extName, vendorExtensions.get(extName));
}
}
/**
* Add the schemas to the components
*
* @param name name of the inline schema
* @param schema inilne schema
* @return the actual model name (based on inlineSchemaNameMapping if provied)
*/
private String addSchemas(String name, Schema schema) {
//check inlineSchemaNameMapping
if (inlineSchemaNameMapping.containsKey(name)) {
name = inlineSchemaNameMapping.get(name);
}
addGenerated(name, schema);
openAPI.getComponents().addSchemas(name, schema);
if (!name.equals(schema.getTitle()) && !inlineSchemaNameMappingValues.contains(name)) {
LOGGER.info("Inline schema created as {}. To have complete control of the model name, set the `title` field or use the inlineSchemaNameMapping option (--inline-schema-name-mapping in CLI).", name);
}
return name;
}
}

View File

@ -68,6 +68,7 @@ public class CodegenConfigurator {
private Map<String, String> typeMappings = new HashMap<>();
private Map<String, Object> additionalProperties = new HashMap<>();
private Map<String, String> importMappings = new HashMap<>();
private Map<String, String> inlineSchemaNameMappings = new HashMap<>();
private Set<String> languageSpecificPrimitives = new HashSet<>();
private Map<String, String> reservedWordMappings = new HashMap<>();
private Map<String, String> serverVariables = new HashMap<>();
@ -111,6 +112,9 @@ public class CodegenConfigurator {
if(generatorSettings.getImportMappings() != null) {
configurator.importMappings.putAll(generatorSettings.getImportMappings());
}
if(generatorSettings.getInlineSchemaNameMappings() != null) {
configurator.inlineSchemaNameMappings.putAll(generatorSettings.getInlineSchemaNameMappings());
}
if(generatorSettings.getLanguageSpecificPrimitives() != null) {
configurator.languageSpecificPrimitives.addAll(generatorSettings.getLanguageSpecificPrimitives());
}
@ -180,6 +184,12 @@ public class CodegenConfigurator {
return this;
}
public CodegenConfigurator addInlineSchemaNameMapping(String key, String value) {
this.inlineSchemaNameMappings.put(key, value);
generatorSettingsBuilder.withInlineSchemaNameMapping(key, value);
return this;
}
public CodegenConfigurator addInstantiationType(String key, String value) {
this.instantiationTypes.put(key, value);
generatorSettingsBuilder.withInstantiationType(key, value);
@ -334,6 +344,12 @@ public class CodegenConfigurator {
return this;
}
public CodegenConfigurator setInlineSchemaNameMappings(Map<String, String> inlineSchemaNameMappings) {
this.inlineSchemaNameMappings = inlineSchemaNameMappings;
generatorSettingsBuilder.withInlineSchemaNameMappings(inlineSchemaNameMappings);
return this;
}
public CodegenConfigurator setInputSpec(String inputSpec) {
this.inputSpec = inputSpec;
workflowSettingsBuilder.withInputSpec(inputSpec);
@ -610,6 +626,7 @@ public class CodegenConfigurator {
config.instantiationTypes().putAll(generatorSettings.getInstantiationTypes());
config.typeMapping().putAll(generatorSettings.getTypeMappings());
config.importMapping().putAll(generatorSettings.getImportMappings());
config.inlineSchemaNameMapping().putAll(generatorSettings.getInlineSchemaNameMappings());
config.languageSpecificPrimitives().addAll(generatorSettings.getLanguageSpecificPrimitives());
config.reservedWordsMappings().putAll(generatorSettings.getReservedWordMappings());
config.additionalProperties().putAll(generatorSettings.getAdditionalProperties());

View File

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

View File

@ -429,7 +429,7 @@ public class InlineModelResolverTest {
ArraySchema requestBody = (ArraySchema) mediaType.getSchema();
assertNotNull(requestBody.getItems().get$ref());
assertEquals("#/components/schemas/InlineObject", requestBody.getItems().get$ref());
assertEquals("#/components/schemas/inline_object_2", requestBody.getItems().get$ref());
Schema items = ModelUtils.getReferencedSchema(openAPI, ((ArraySchema) mediaType.getSchema()).getItems());
assertTrue(items.getProperties().get("street") instanceof StringSchema);
@ -995,7 +995,20 @@ public class InlineModelResolverTest {
}
@Test
public void regression_6905() {
public void testInlineSchemaNameMapping() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/inline_model_resolver.yaml");
InlineModelResolver resolver = new InlineModelResolver();
Map<String, String> inlineSchemaNames = new HashMap<>();
inlineSchemaNames.put("inline_object_2", "SomethingMapped");
inlineSchemaNames.put("inline_object_4", "nothing_new");
resolver.setInlineSchemaNameMapping(inlineSchemaNames);
resolver.flatten(openAPI);
Schema schema = openAPI.getComponents().getSchemas().get("SomethingMapped");
assertTrue(schema.getProperties().get("street") instanceof StringSchema);
assertTrue(schema.getProperties().get("city") instanceof StringSchema);
Schema nothingNew = openAPI.getComponents().getSchemas().get("nothing_new");
assertTrue(nothingNew.getProperties().get("arbitrary_request_body_array_property") instanceof ObjectSchema);
}
}

View File

@ -12,7 +12,7 @@ docs/Apple.md
docs/AppleReq.md
docs/ArrayOfArrayOfNumberOnly.md
docs/ArrayOfInlineAllOf.md
docs/ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf.md
docs/ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.md
docs/ArrayOfNumberOnly.md
docs/ArrayTest.md
docs/Banana.md
@ -133,7 +133,7 @@ src/main/java/org/openapitools/client/model/Apple.java
src/main/java/org/openapitools/client/model/AppleReq.java
src/main/java/org/openapitools/client/model/ArrayOfArrayOfNumberOnly.java
src/main/java/org/openapitools/client/model/ArrayOfInlineAllOf.java
src/main/java/org/openapitools/client/model/ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf.java
src/main/java/org/openapitools/client/model/ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.java
src/main/java/org/openapitools/client/model/ArrayOfNumberOnly.java
src/main/java/org/openapitools/client/model/ArrayTest.java
src/main/java/org/openapitools/client/model/Banana.java

View File

@ -162,7 +162,7 @@ Class | Method | HTTP request | Description
- [AppleReq](docs/AppleReq.md)
- [ArrayOfArrayOfNumberOnly](docs/ArrayOfArrayOfNumberOnly.md)
- [ArrayOfInlineAllOf](docs/ArrayOfInlineAllOf.md)
- [ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf](docs/ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf.md)
- [ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1](docs/ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.md)
- [ArrayOfNumberOnly](docs/ArrayOfNumberOnly.md)
- [ArrayTest](docs/ArrayTest.md)
- [Banana](docs/Banana.md)

View File

@ -2344,7 +2344,7 @@ components:
items:
allOf:
- $ref: '#/components/schemas/Dog_allOf'
- $ref: '#/components/schemas/ArrayOfInlineAllOf_array_allof_dog_propertyItems_allOf'
- $ref: '#/components/schemas/ArrayOfInlineAllOf_array_allof_dog_propertyItems_allOf_1'
type: array
required:
- name
@ -2504,7 +2504,7 @@ components:
declawed:
type: boolean
type: object
ArrayOfInlineAllOf_array_allof_dog_propertyItems_allOf:
ArrayOfInlineAllOf_array_allof_dog_propertyItems_allOf_1:
properties:
color:
type: string

View File

@ -0,0 +1,13 @@
# ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1
## Properties
| Name | Type | Description | Notes |
|------------ | ------------- | ------------- | -------------|
|**color** | **String** | | [optional] |

View File

@ -225,7 +225,7 @@ public class JSON {
.registerTypeAdapterFactory(new org.openapitools.client.model.AppleReq.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.ArrayOfArrayOfNumberOnly.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.ArrayOfInlineAllOf.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.ArrayOfNumberOnly.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.ArrayTest.CustomTypeAdapterFactory())
.registerTypeAdapterFactory(new org.openapitools.client.model.Banana.CustomTypeAdapterFactory())

View File

@ -25,7 +25,7 @@ import io.swagger.annotations.ApiModelProperty;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.openapitools.client.model.ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf;
import org.openapitools.client.model.ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1;
import org.openapitools.client.model.DogAllOf;
import com.google.gson.Gson;

View File

@ -0,0 +1,273 @@
/*
* OpenAPI Petstore
* This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.model;
import java.util.Objects;
import java.util.Arrays;
import com.google.gson.TypeAdapter;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.IOException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.openapitools.client.JSON;
/**
* ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1
*/
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public class ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 {
public static final String SERIALIZED_NAME_COLOR = "color";
@SerializedName(SERIALIZED_NAME_COLOR)
private String color;
public ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1() {
}
public ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 color(String color) {
this.color = color;
return this;
}
/**
* Get color
* @return color
**/
@javax.annotation.Nullable
@ApiModelProperty(value = "")
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
/**
* A container for additional, undeclared properties.
* This is a holder for any undeclared properties as specified with
* the 'additionalProperties' keyword in the OAS document.
*/
private Map<String, Object> additionalProperties;
/**
* Set the additional (undeclared) property with the specified name and value.
* If the property does not already exist, create it otherwise replace it.
*/
public ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 putAdditionalProperty(String key, Object value) {
if (this.additionalProperties == null) {
this.additionalProperties = new HashMap<String, Object>();
}
this.additionalProperties.put(key, value);
return this;
}
/**
* Return the additional (undeclared) property.
*/
public Map<String, Object> getAdditionalProperties() {
return additionalProperties;
}
/**
* Return the additional (undeclared) property with the specified name.
*/
public Object getAdditionalProperty(String key) {
if (this.additionalProperties == null) {
return null;
}
return this.additionalProperties.get(key);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 arrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 = (ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1) o;
return Objects.equals(this.color, arrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.color)&&
Objects.equals(this.additionalProperties, arrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.additionalProperties);
}
@Override
public int hashCode() {
return Objects.hash(color, additionalProperties);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 {\n");
sb.append(" color: ").append(toIndentedString(color)).append("\n");
sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n");
sb.append("}");
return sb.toString();
}
/**
* Convert the given object to string with each line indented by 4 spaces
* (except the first line).
*/
private String toIndentedString(Object o) {
if (o == null) {
return "null";
}
return o.toString().replace("\n", "\n ");
}
public static HashSet<String> openapiFields;
public static HashSet<String> openapiRequiredFields;
static {
// a set of all properties/fields (JSON key names)
openapiFields = new HashSet<String>();
openapiFields.add("color");
// a set of required properties/fields (JSON key names)
openapiRequiredFields = new HashSet<String>();
}
/**
* Validates the JSON Object and throws an exception if issues found
*
* @param jsonObj JSON Object
* @throws IOException if the JSON Object is invalid with respect to ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1
*/
public static void validateJsonObject(JsonObject jsonObj) throws IOException {
if (jsonObj == null) {
if (ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.openapiRequiredFields.isEmpty()) {
return;
} else { // has required fields
throw new IllegalArgumentException(String.format("The required field(s) %s in ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 is not found in the empty JSON string", ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.openapiRequiredFields.toString()));
}
}
if (jsonObj.get("color") != null && !jsonObj.get("color").isJsonPrimitive()) {
throw new IllegalArgumentException(String.format("Expected the field `color` to be a primitive type in the JSON string but got `%s`", jsonObj.get("color").toString()));
}
}
public static class CustomTypeAdapterFactory implements TypeAdapterFactory {
@SuppressWarnings("unchecked")
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (!ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.class.isAssignableFrom(type.getRawType())) {
return null; // this class only serializes 'ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1' and its subtypes
}
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
final TypeAdapter<ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1> thisAdapter
= gson.getDelegateAdapter(this, TypeToken.get(ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.class));
return (TypeAdapter<T>) new TypeAdapter<ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1>() {
@Override
public void write(JsonWriter out, ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 value) throws IOException {
JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject();
obj.remove("additionalProperties");
// serialize additonal properties
if (value.getAdditionalProperties() != null) {
for (Map.Entry<String, Object> entry : value.getAdditionalProperties().entrySet()) {
if (entry.getValue() instanceof String)
obj.addProperty(entry.getKey(), (String) entry.getValue());
else if (entry.getValue() instanceof Number)
obj.addProperty(entry.getKey(), (Number) entry.getValue());
else if (entry.getValue() instanceof Boolean)
obj.addProperty(entry.getKey(), (Boolean) entry.getValue());
else if (entry.getValue() instanceof Character)
obj.addProperty(entry.getKey(), (Character) entry.getValue());
else {
obj.add(entry.getKey(), gson.toJsonTree(entry.getValue()).getAsJsonObject());
}
}
}
elementAdapter.write(out, obj);
}
@Override
public ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 read(JsonReader in) throws IOException {
JsonObject jsonObj = elementAdapter.read(in).getAsJsonObject();
validateJsonObject(jsonObj);
// store additional fields in the deserialized instance
ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 instance = thisAdapter.fromJsonTree(jsonObj);
for (Map.Entry<String, JsonElement> entry : jsonObj.entrySet()) {
if (!openapiFields.contains(entry.getKey())) {
if (entry.getValue().isJsonPrimitive()) { // primitive type
if (entry.getValue().getAsJsonPrimitive().isString())
instance.putAdditionalProperty(entry.getKey(), entry.getValue().getAsString());
else if (entry.getValue().getAsJsonPrimitive().isNumber())
instance.putAdditionalProperty(entry.getKey(), entry.getValue().getAsNumber());
else if (entry.getValue().getAsJsonPrimitive().isBoolean())
instance.putAdditionalProperty(entry.getKey(), entry.getValue().getAsBoolean());
else
throw new IllegalArgumentException(String.format("The field `%s` has unknown primitive type. Value: %s", entry.getKey(), entry.getValue().toString()));
} else { // non-primitive type
instance.putAdditionalProperty(entry.getKey(), gson.fromJson(entry.getValue(), HashMap.class));
}
}
}
return instance;
}
}.nullSafe();
}
}
/**
* Create an instance of ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 given an JSON string
*
* @param jsonString JSON string
* @return An instance of ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1
* @throws IOException if the JSON string is invalid with respect to ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1
*/
public static ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 fromJson(String jsonString) throws IOException {
return JSON.getGson().fromJson(jsonString, ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1.class);
}
/**
* Convert an instance of ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 to an JSON string
*
* @return JSON string
*/
public String toJson() {
return JSON.getGson().toJson(this);
}
}

View File

@ -0,0 +1,50 @@
/*
* OpenAPI Petstore
* This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.model;
import com.google.gson.TypeAdapter;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.IOException;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
/**
* Model tests for ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1
*/
public class ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1Test {
private final ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1 model = new ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1();
/**
* Model tests for ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1
*/
@Test
public void testArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1() {
// TODO: test ArrayOfInlineAllOfArrayAllofDogPropertyItemsAllOf1
}
/**
* Test the property 'color'
*/
@Test
public void colorTest() {
// TODO: test color
}
}