Skip to content

Commit eecd8c0

Browse files
pe-stbkoziakwing328
authored
Java importmapping 3589 (#4350)
* type aliasing issue * Add example OpenAPI document from issue 3589 #3589 * Add test to reproduce the issue - type of TypeAlias changed from 'string' to 'object' (not sure if importMapping is supposed also for 'string' types...) - there might be better ways to write the test, it's kind of a brute force test (generate a file and parse it with a regexp) * Remove duplicate test file * Add new method override handleMethodResponse Fixes broken unit test after merge from master Co-authored-by: bkoziak <[email protected]> Co-authored-by: William Cheng <[email protected]>
1 parent f526585 commit eecd8c0

File tree

10 files changed

+220
-62
lines changed

10 files changed

+220
-62
lines changed

modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ public void execute() throws MojoExecutionException {
641641
configurator);
642642
}
643643

644-
// Retained for backwards-compataibility with configOptions -> import-mappings
644+
// Retained for backwards-compatibility with configOptions -> import-mappings
645645
if (importMappings == null && configOptions.containsKey("import-mappings")) {
646646
applyImportMappingsKvp(configOptions.get("import-mappings").toString(),
647647
configurator);
@@ -869,6 +869,7 @@ private void addCompileSourceRootIfConfigured() {
869869
}
870870
}
871871
}
872+
872873
/**
873874
* This method enables conversion of true/false strings in
874875
* config.additionalProperties (configuration/configOptions) to proper booleans.

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

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,12 +1798,15 @@ public String toOneOfName(List<String> names, ComposedSchema composedSchema) {
17981798
* @return the string representation of the schema type.
17991799
*/
18001800
private String getSingleSchemaType(Schema schema) {
1801-
Schema unaliasSchema = ModelUtils.unaliasSchema(this.openAPI, schema);
1801+
Schema unaliasSchema = ModelUtils.unaliasSchema(this.openAPI, schema, importMapping);
18021802

18031803
if (StringUtils.isNotBlank(unaliasSchema.get$ref())) { // reference to another definition/schema
18041804
// get the schema/model name from $ref
18051805
String schemaName = ModelUtils.getSimpleRef(unaliasSchema.get$ref());
18061806
if (StringUtils.isNotEmpty(schemaName)) {
1807+
if (importMapping.containsKey(schemaName)) {
1808+
return schemaName;
1809+
}
18071810
return getAlias(schemaName);
18081811
} else {
18091812
LOGGER.warn("Error obtaining the datatype from ref:" + unaliasSchema.get$ref() + ". Default to 'object'");
@@ -1903,7 +1906,6 @@ public String lowerCamelCase(String name) {
19031906
return (name.length() > 0) ? (Character.toLowerCase(name.charAt(0)) + name.substring(1)) : "";
19041907
}
19051908

1906-
19071909
/**
19081910
* Output the type declaration of a given name
19091911
*
@@ -2021,7 +2023,7 @@ public CodegenModel fromModel(String name, Schema schema) {
20212023
}
20222024

20232025
// unalias schema
2024-
schema = ModelUtils.unaliasSchema(this.openAPI, schema);
2026+
schema = ModelUtils.unaliasSchema(this.openAPI, schema, importMapping);
20252027
if (schema == null) {
20262028
LOGGER.warn("Schema {} not found", name);
20272029
return null;
@@ -2372,7 +2374,7 @@ public CodegenProperty fromProperty(String name, Schema p) {
23722374
LOGGER.debug("debugging fromProperty for " + name + " : " + p);
23732375

23742376
// unalias schema
2375-
p = ModelUtils.unaliasSchema(this.openAPI, p);
2377+
p = ModelUtils.unaliasSchema(this.openAPI, p, importMapping);
23762378

23772379
CodegenProperty property = CodegenModelFactory.newInstance(CodegenModelType.PROPERTY);
23782380

@@ -2526,12 +2528,13 @@ public CodegenProperty fromProperty(String name, Schema p) {
25262528
} else if (ModelUtils.isArraySchema(p)) {
25272529
// default to string if inner item is undefined
25282530
ArraySchema arraySchema = (ArraySchema) p;
2529-
Schema innerSchema = ModelUtils.unaliasSchema(this.openAPI, getSchemaItems(arraySchema));
2531+
Schema innerSchema = ModelUtils.unaliasSchema(this.openAPI, getSchemaItems(arraySchema), importMapping);
25302532
if (arraySchema.getItems() == null) {
25312533
arraySchema.setItems(innerSchema);
25322534
}
25332535
} else if (ModelUtils.isMapSchema(p)) {
2534-
Schema innerSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getAdditionalProperties(p));
2536+
Schema innerSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getAdditionalProperties(p),
2537+
importMapping);
25352538
if (innerSchema == null) {
25362539
LOGGER.error("Undefined map inner type for `{}`. Default to String.", p.getName());
25372540
innerSchema = new StringSchema().description("//TODO automatically added by openapi-generator due to undefined type");
@@ -2607,7 +2610,7 @@ public CodegenProperty fromProperty(String name, Schema p) {
26072610
itemName = property.name;
26082611
}
26092612
ArraySchema arraySchema = (ArraySchema) p;
2610-
Schema innerSchema = ModelUtils.unaliasSchema(this.openAPI, getSchemaItems(arraySchema));
2613+
Schema innerSchema = ModelUtils.unaliasSchema(this.openAPI, getSchemaItems(arraySchema), importMapping);
26112614
if (arraySchema.getItems() == null) {
26122615
arraySchema.setItems(innerSchema);
26132616
}
@@ -2622,7 +2625,8 @@ public CodegenProperty fromProperty(String name, Schema p) {
26222625
property.maxItems = p.getMaxProperties();
26232626

26242627
// handle inner property
2625-
Schema innerSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getAdditionalProperties(p));
2628+
Schema innerSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getAdditionalProperties(p),
2629+
importMapping);
26262630
if (innerSchema == null) {
26272631
LOGGER.error("Undefined map inner type for `{}`. Default to String.", p.getName());
26282632
innerSchema = new StringSchema().description("//TODO automatically added by openapi-generator due to undefined type");
@@ -2841,7 +2845,24 @@ protected void handleMethodResponse(Operation operation,
28412845
Map<String, Schema> schemas,
28422846
CodegenOperation op,
28432847
ApiResponse methodResponse) {
2844-
Schema responseSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getSchemaFromResponse(methodResponse));
2848+
handleMethodResponse(operation, schemas, op, methodResponse, Collections.<String, String>emptyMap());
2849+
}
2850+
2851+
/**
2852+
* Set op's returnBaseType, returnType, examples etc.
2853+
*
2854+
* @param operation endpoint Operation
2855+
* @param schemas a map of the schemas in the openapi spec
2856+
* @param op endpoint CodegenOperation
2857+
* @param methodResponse the default ApiResponse for the endpoint
2858+
* @param importMappings mappings of external types to be omitted by unaliasing
2859+
*/
2860+
protected void handleMethodResponse(Operation operation,
2861+
Map<String, Schema> schemas,
2862+
CodegenOperation op,
2863+
ApiResponse methodResponse,
2864+
Map<String, String> importMappings) {
2865+
Schema responseSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getSchemaFromResponse(methodResponse), importMappings);
28452866

28462867
if (responseSchema != null) {
28472868
CodegenProperty cm = fromProperty("response", responseSchema);
@@ -2996,7 +3017,7 @@ public CodegenOperation fromOperation(String path,
29963017
op.responses.get(op.responses.size() - 1).hasMore = false;
29973018

29983019
if (methodResponse != null) {
2999-
handleMethodResponse(operation, schemas, op, methodResponse);
3020+
handleMethodResponse(operation, schemas, op, methodResponse, importMapping);
30003021
}
30013022
}
30023023

@@ -3130,9 +3151,12 @@ public CodegenOperation fromOperation(String path,
31303151
Collections.sort(allParams, new Comparator<CodegenParameter>() {
31313152
@Override
31323153
public int compare(CodegenParameter one, CodegenParameter another) {
3133-
if (one.required == another.required) return 0;
3134-
else if (one.required) return -1;
3135-
else return 1;
3154+
if (one.required == another.required)
3155+
return 0;
3156+
else if (one.required)
3157+
return -1;
3158+
else
3159+
return 1;
31363160
}
31373161
});
31383162
}
@@ -3211,7 +3235,8 @@ public CodegenResponse fromResponse(String responseCode, ApiResponse response) {
32113235
}
32123236
Schema responseSchema;
32133237
if (this.openAPI != null && this.openAPI.getComponents() != null) {
3214-
responseSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getSchemaFromResponse(response));
3238+
responseSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getSchemaFromResponse(response),
3239+
importMapping);
32153240
} else { // no model/alias defined
32163241
responseSchema = ModelUtils.getSchemaFromResponse(response);
32173242
}
@@ -3443,7 +3468,7 @@ public CodegenParameter fromParameter(Parameter parameter, Set<String> imports)
34433468
}
34443469

34453470
if (s != null) {
3446-
Schema parameterSchema = ModelUtils.unaliasSchema(this.openAPI, s);
3471+
Schema parameterSchema = ModelUtils.unaliasSchema(this.openAPI, s, importMapping);
34473472
if (parameterSchema == null) {
34483473
LOGGER.warn("warning! Schema not found for parameter \"" + parameter.getName() + "\", using String");
34493474
parameterSchema = new StringSchema().description("//TODO automatically added by openapi-generator due to missing type definition.");
@@ -4047,7 +4072,7 @@ protected void addImport(CodegenModel m, String type) {
40474072
private Map<String, Schema> unaliasPropertySchema(Map<String, Schema> properties) {
40484073
if (properties != null) {
40494074
for (String key : properties.keySet()) {
4050-
properties.put(key, ModelUtils.unaliasSchema(this.openAPI, properties.get(key)));
4075+
properties.put(key, ModelUtils.unaliasSchema(this.openAPI, properties.get(key), importMapping()));
40514076

40524077
}
40534078
}
@@ -5422,7 +5447,6 @@ public CodegenParameter fromRequestBody(RequestBody body, Set<String> imports, S
54225447
codegenParameter.maxLength = codegenProperty.maxLength;
54235448
codegenParameter.pattern = codegenProperty.pattern;
54245449

5425-
54265450
if (codegenProperty.complexType != null) {
54275451
imports.add(codegenProperty.complexType);
54285452
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
261261

262262
if (methodResponse != null) {
263263
Schema response = ModelUtils.getSchemaFromResponse(methodResponse);
264-
response = ModelUtils.unaliasSchema(this.openAPI, response);
264+
response = ModelUtils.unaliasSchema(this.openAPI, response, importMapping);
265265
if (response != null) {
266266
CodegenProperty cm = fromProperty("response", response);
267267
op.vendorExtensions.put("x-codegen-response", cm);

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ public CodegenResponse fromResponse(String responseCode, ApiResponse response) {
529529
// When we serialize/deserialize ModelSimple models, validations and enums will be checked.
530530
Schema responseSchema;
531531
if (this.openAPI != null && this.openAPI.getComponents() != null) {
532-
responseSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getSchemaFromResponse(response));
532+
responseSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getSchemaFromResponse(response), importMapping);
533533
} else { // no model/alias defined
534534
responseSchema = ModelUtils.getSchemaFromResponse(response);
535535
}
@@ -582,12 +582,30 @@ public void handleMethodResponse(Operation operation,
582582
Map<String, Schema> schemas,
583583
CodegenOperation op,
584584
ApiResponse methodResponse) {
585+
handleMethodResponse(operation, schemas, op, methodResponse, Collections.<String, String>emptyMap());
586+
}
587+
588+
/**
589+
* Set op's returnBaseType, returnType, examples etc.
590+
*
591+
* @param operation endpoint Operation
592+
* @param schemas a map of the schemas in the openapi spec
593+
* @param op endpoint CodegenOperation
594+
* @param methodResponse the default ApiResponse for the endpoint
595+
* @param importMappings mappings of external types to be omitted by unaliasing
596+
*/
597+
@Override
598+
protected void handleMethodResponse(Operation operation,
599+
Map<String, Schema> schemas,
600+
CodegenOperation op,
601+
ApiResponse methodResponse,
602+
Map<String, String> importMappings) {
585603
// we have a custom version of this method to handle endpoints that return models where
586604
// type != object the model has validations and/or enums
587605
// we do this by invoking our custom fromResponse method to create defaultResponse
588606
// which we then use to set op.returnType and op.returnBaseType
589607
CodegenResponse defaultResponse = fromResponse("defaultResponse", methodResponse);
590-
Schema responseSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getSchemaFromResponse(methodResponse));
608+
Schema responseSchema = ModelUtils.unaliasSchema(this.openAPI, ModelUtils.getSchemaFromResponse(methodResponse), importMappings);
591609

592610
if (responseSchema != null) {
593611
op.returnBaseType = defaultResponse.baseType;

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,16 @@ public String getTypeDeclaration(Schema p) {
101101
@Override
102102
protected void handleMethodResponse(Operation operation, Map<String, Schema> schemas, CodegenOperation op,
103103
ApiResponse methodResponse) {
104-
super.handleMethodResponse(operation, schemas, op, methodResponse);
104+
handleMethodResponse(operation, schemas, op, methodResponse, Collections.<String, String>emptyMap());
105+
}
106+
107+
@Override
108+
protected void handleMethodResponse(Operation operation,
109+
Map<String, Schema> schemas,
110+
CodegenOperation op,
111+
ApiResponse methodResponse,
112+
Map<String, String> importMappings) {
113+
super.handleMethodResponse(operation, schemas, op, methodResponse, importMappings);
105114

106115
// see comment in getTypeDeclaration
107116
if (op.isResponseFile) {

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

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class ModelUtils {
4747
private static final String URI_FORMAT = "uri";
4848

4949
private static final String generateAliasAsModelKey = "generateAliasAsModel";
50+
5051
public static void setGenerateAliasAsModel(boolean value) {
5152
GlobalSettings.setProperty(generateAliasAsModelKey, Boolean.toString(value));
5253
}
@@ -240,7 +241,7 @@ private static void visitPathItem(PathItem pathItem, OpenAPI openAPI, OpenAPISch
240241
}
241242

242243
private static void visitParameters(OpenAPI openAPI, List<Parameter> parameters, OpenAPISchemaVisitor visitor,
243-
List<String> visitedSchemas) {
244+
List<String> visitedSchemas) {
244245
if (parameters != null) {
245246
for (Parameter p : parameters) {
246247
Parameter parameter = getReferencedParameter(openAPI, p);
@@ -870,7 +871,22 @@ private static Schema getSchemaFromContent(Content content) {
870871
* @param schema schema (alias or direct reference)
871872
* @return actual schema
872873
*/
873-
public static Schema unaliasSchema(OpenAPI openAPI, Schema schema) {
874+
public static Schema unaliasSchema(OpenAPI openAPI,
875+
Schema schema) {
876+
return unaliasSchema(openAPI, schema, Collections.<String, String>emptyMap());
877+
}
878+
879+
/**
880+
* Get the actual schema from aliases. If the provided schema is not an alias, the schema itself will be returned.
881+
*
882+
* @param openAPI specification being checked
883+
* @param schema schema (alias or direct reference)
884+
* @param importMappings mappings of external types to be omitted by unaliasing
885+
* @return actual schema
886+
*/
887+
public static Schema unaliasSchema(OpenAPI openAPI,
888+
Schema schema,
889+
Map<String, String> importMappings) {
874890
Map<String, Schema> allSchemas = getSchemas(openAPI);
875891
if (allSchemas == null || allSchemas.isEmpty()) {
876892
// skip the warning as the spec can have no model defined
@@ -879,7 +895,12 @@ public static Schema unaliasSchema(OpenAPI openAPI, Schema schema) {
879895
}
880896

881897
if (schema != null && StringUtils.isNotEmpty(schema.get$ref())) {
882-
Schema ref = allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref()));
898+
String simpleRef = ModelUtils.getSimpleRef(schema.get$ref());
899+
if (importMappings.containsKey(simpleRef)) {
900+
LOGGER.info("Schema unaliasing of {} omitted because aliased class is to be mapped to {}", simpleRef, importMappings.get(simpleRef));
901+
return schema;
902+
}
903+
Schema ref = allSchemas.get(simpleRef);
883904
if (ref == null) {
884905
once(LOGGER).warn("{} is not defined", schema.get$ref());
885906
return schema;
@@ -890,7 +911,8 @@ public static Schema unaliasSchema(OpenAPI openAPI, Schema schema) {
890911
if (isGenerateAliasAsModel()) {
891912
return schema; // generate a model extending array
892913
} else {
893-
return unaliasSchema(openAPI, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())));
914+
return unaliasSchema(openAPI, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())),
915+
importMappings);
894916
}
895917
} else if (isComposedSchema(ref)) {
896918
return schema;
@@ -902,17 +924,19 @@ public static Schema unaliasSchema(OpenAPI openAPI, Schema schema) {
902924
return schema; // generate a model extending map
903925
} else {
904926
// treat it as a typical map
905-
return unaliasSchema(openAPI, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())));
927+
return unaliasSchema(openAPI, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())),
928+
importMappings);
906929
}
907930
}
908931
} else if (isObjectSchema(ref)) { // model
909932
if (ref.getProperties() != null && !ref.getProperties().isEmpty()) { // has at least one property
910933
return schema;
911934
} else { // free form object (type: object)
912-
return unaliasSchema(openAPI, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())));
935+
return unaliasSchema(openAPI, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())),
936+
importMappings);
913937
}
914938
} else {
915-
return unaliasSchema(openAPI, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())));
939+
return unaliasSchema(openAPI, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())), importMappings);
916940
}
917941
}
918942
return schema;

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,21 @@ public void modelDoNotContainInheritedVars() {
10731073
Assert.assertEquals(codegenModel.vars.size(), 1);
10741074
}
10751075

1076+
@Test
1077+
public void importMapping() {
1078+
DefaultCodegen codegen = new DefaultCodegen();
1079+
codegen.importMapping.put("TypeAlias", "foo.bar.TypeAlias");
1080+
1081+
OpenAPI openAPI = new OpenAPIParser()
1082+
.readLocation("src/test/resources/3_0/type-alias.yaml", null, new ParseOptions()).getOpenAPI();
1083+
codegen.setOpenAPI(openAPI);
1084+
1085+
CodegenModel codegenModel = codegen.fromModel("ParentType", openAPI.getComponents().getSchemas().get("ParentType"));
1086+
1087+
Assert.assertEquals(codegenModel.vars.size(), 1);
1088+
Assert.assertEquals(codegenModel.vars.get(0).getBaseType(), "TypeAlias");
1089+
}
1090+
10761091
@Test
10771092
public void modelWithPrefixDoNotContainInheritedVars() {
10781093
DefaultCodegen codegen = new DefaultCodegen();

0 commit comments

Comments
 (0)