Pre-calculate type aliases before processing models (#6559)

A type alias in this context is where a model is simply another name for a
primitive type, such as `MyString` in the following model definitions:

    MyList:
      type: array
      items:
        $ref: '#/definitions/MyString'
    MyString:
      type: string

It is valid to use a type alias as a property in another object or array model,
even if the object/array is defined before the alias is, as in the example
above. However, the current alias logic only looks "back" in list of previously
defined models, meaning that `MyList` would not know that `MyString` is an
alias. This change fixes the incorrect behavior by pre-calculating the list of
aliases before any models are processed. It also changes the test endpoint to
verify the correct behavior even when an object is defined before an alias it
uses.
This commit is contained in:
Benjamin Douglas 2017-10-01 19:54:41 -07:00 committed by wing328
parent 8bd7d3912b
commit 6e7ad13e1b
3 changed files with 38 additions and 12 deletions

View File

@ -119,7 +119,7 @@ public class DefaultCodegen {
// Then translated back during JSON encoding and decoding // Then translated back during JSON encoding and decoding
protected Map<String, String> specialCharReplacements = new HashMap<String, String>(); protected Map<String, String> specialCharReplacements = new HashMap<String, String>();
// When a model is an alias for a simple type // When a model is an alias for a simple type
protected Map<String, String> typeAliases = new HashMap<>(); protected Map<String, String> typeAliases = null;
protected String ignoreFilePathOverride; protected String ignoreFilePathOverride;
@ -1312,6 +1312,10 @@ public class DefaultCodegen {
* @return Codegen Model object * @return Codegen Model object
*/ */
public CodegenModel fromModel(String name, Model model, Map<String, Model> allDefinitions) { public CodegenModel fromModel(String name, Model model, Map<String, Model> allDefinitions) {
if (typeAliases == null) {
// Only do this once during first call
typeAliases = getAllAliases(allDefinitions);
}
CodegenModel m = CodegenModelFactory.newInstance(CodegenModelType.MODEL); CodegenModel m = CodegenModelFactory.newInstance(CodegenModelType.MODEL);
if (reservedWords.contains(name)) { if (reservedWords.contains(name)) {
m.name = escapeReservedWord(name); m.name = escapeReservedWord(name);
@ -1327,6 +1331,7 @@ public class DefaultCodegen {
m.modelJson = Json.pretty(model); m.modelJson = Json.pretty(model);
m.externalDocs = model.getExternalDocs(); m.externalDocs = model.getExternalDocs();
m.vendorExtensions = model.getVendorExtensions(); m.vendorExtensions = model.getVendorExtensions();
m.isAlias = typeAliases.containsKey(name);
if (model instanceof ModelImpl) { if (model instanceof ModelImpl) {
ModelImpl modelImpl = (ModelImpl) model; ModelImpl modelImpl = (ModelImpl) model;
@ -1444,10 +1449,6 @@ public class DefaultCodegen {
ModelImpl impl = (ModelImpl) model; ModelImpl impl = (ModelImpl) model;
if (impl.getType() != null) { if (impl.getType() != null) {
Property p = PropertyBuilder.build(impl.getType(), impl.getFormat(), null); Property p = PropertyBuilder.build(impl.getType(), impl.getFormat(), null);
if (!impl.getType().equals("object") && impl.getEnum() == null) {
typeAliases.put(name, impl.getType());
m.isAlias = true;
}
m.dataType = getSwaggerType(p); m.dataType = getSwaggerType(p);
} }
if(impl.getEnum() != null && impl.getEnum().size() > 0) { if(impl.getEnum() != null && impl.getEnum().size() > 0) {
@ -3166,6 +3167,31 @@ public class DefaultCodegen {
} }
} }
/**
* Determine all of the types in the model definitions that are aliases of
* simple types.
* @param allDefinitions The complete set of model definitions.
* @return A mapping from model name to type alias
*/
private static Map<String, String> getAllAliases(Map<String, Model> allDefinitions) {
Map<String, String> aliases = new HashMap<>();
if (allDefinitions != null) {
for (Map.Entry<String, Model> entry : allDefinitions.entrySet()) {
String swaggerName = entry.getKey();
Model m = entry.getValue();
if (m instanceof ModelImpl) {
ModelImpl impl = (ModelImpl) m;
if (impl.getType() != null &&
!impl.getType().equals("object") &&
impl.getEnum() == null) {
aliases.put(swaggerName, impl.getType());
}
}
}
}
return aliases;
}
/** /**
* Remove characters not suitable for variable or method name from the input and camelize it * Remove characters not suitable for variable or method name from the input and camelize it
* *

View File

@ -619,7 +619,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
@Override @Override
public String getAlias(String name) { public String getAlias(String name) {
if (typeAliases.containsKey(name)) { if (typeAliases != null && typeAliases.containsKey(name)) {
return typeAliases.get(name); return typeAliases.get(name);
} }
return name; return name;

View File

@ -1402,12 +1402,6 @@ definitions:
- "placed" - "placed"
- "approved" - "approved"
- "delivered" - "delivered"
OuterNumber:
type: number
OuterString:
type: string
OuterBoolean:
type: boolean
OuterComposite: OuterComposite:
type: object type: object
properties: properties:
@ -1417,6 +1411,12 @@ definitions:
$ref: '#/definitions/OuterString' $ref: '#/definitions/OuterString'
my_boolean: my_boolean:
$ref: '#/definitions/OuterBoolean' $ref: '#/definitions/OuterBoolean'
OuterNumber:
type: number
OuterString:
type: string
OuterBoolean:
type: boolean
externalDocs: externalDocs:
description: Find out more about Swagger description: Find out more about Swagger
url: 'http://swagger.io' url: 'http://swagger.io'