forked from loafle/openapi-generator-original
fix some inheritance/composition issues and add allOf unit tests
Fix #3629 #3544 #3474 #3636
This commit is contained in:
parent
54fe7a731c
commit
194c389a06
@ -100,6 +100,7 @@ public class DefaultCodegen {
|
||||
protected List<CliOption> cliOptions = new ArrayList<CliOption>();
|
||||
protected boolean skipOverwrite;
|
||||
protected boolean supportsInheritance;
|
||||
protected boolean supportsMixins;
|
||||
protected Map<String, String> supportedLibraries = new LinkedHashMap<String, String>();
|
||||
protected String library;
|
||||
protected Boolean sortParamsByRequiredFlag = true;
|
||||
@ -1233,7 +1234,7 @@ public class DefaultCodegen {
|
||||
List<String> required = new ArrayList<String>();
|
||||
Map<String, Property> allProperties;
|
||||
List<String> allRequired;
|
||||
if (supportsInheritance) {
|
||||
if (supportsInheritance || supportsMixins) {
|
||||
allProperties = new LinkedHashMap<String, Property>();
|
||||
allRequired = new ArrayList<String>();
|
||||
m.allVars = new ArrayList<CodegenProperty>();
|
||||
@ -1254,17 +1255,20 @@ public class DefaultCodegen {
|
||||
interfaceModel = allDefinitions.get(_interface.getSimpleRef());
|
||||
}
|
||||
// set first interface with discriminator found as parent
|
||||
if (parent == null && interfaceModel instanceof ModelImpl && ((ModelImpl) interfaceModel).getDiscriminator() != null) {
|
||||
if (parent == null
|
||||
&& ((interfaceModel instanceof ModelImpl && ((ModelImpl) interfaceModel).getDiscriminator() != null)
|
||||
|| (interfaceModel instanceof ComposedModel && isDiscriminatorInInterfaceTree((ComposedModel) interfaceModel, allDefinitions)))) {
|
||||
parent = _interface;
|
||||
} else {
|
||||
final String interfaceRef = toModelName(_interface.getSimpleRef());
|
||||
m.interfaces.add(interfaceRef);
|
||||
addImport(m, interfaceRef);
|
||||
if (allDefinitions != null) {
|
||||
if (!supportsMixins) {
|
||||
addProperties(properties, required, interfaceModel, allDefinitions);
|
||||
}
|
||||
if (supportsInheritance) {
|
||||
addProperties(allProperties, allRequired, interfaceModel, allDefinitions);
|
||||
} else {
|
||||
addProperties(properties, required, interfaceModel, allDefinitions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1323,6 +1327,30 @@ public class DefaultCodegen {
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively look for a discriminator in the interface tree
|
||||
*/
|
||||
private boolean isDiscriminatorInInterfaceTree(ComposedModel model, Map<String, Model> allDefinitions) {
|
||||
if (model == null || allDefinitions == null)
|
||||
return false;
|
||||
|
||||
Model child = ((ComposedModel) model).getChild();
|
||||
if (child instanceof ModelImpl && ((ModelImpl) child).getDiscriminator() != null) {
|
||||
return true;
|
||||
}
|
||||
for (RefModel _interface : model.getInterfaces()) {
|
||||
Model interfaceModel = allDefinitions.get(_interface.getSimpleRef());
|
||||
if (interfaceModel instanceof ModelImpl && ((ModelImpl) interfaceModel).getDiscriminator() != null) {
|
||||
return true;
|
||||
}
|
||||
if (interfaceModel instanceof ComposedModel) {
|
||||
|
||||
return isDiscriminatorInInterfaceTree((ComposedModel) interfaceModel, allDefinitions);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, ModelImpl swaggerModel) {
|
||||
MapProperty mapProperty = new MapProperty(swaggerModel.getAdditionalProperties());
|
||||
addParentContainer(codegenModel, codegenModel.name, mapProperty);
|
||||
|
@ -223,6 +223,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
|
||||
setUseInheritance(Boolean.parseBoolean((String)additionalProperties.get(USE_INHERITANCE)));
|
||||
} else {
|
||||
supportsInheritance = true;
|
||||
supportsMixins = true;
|
||||
}
|
||||
if (additionalProperties.containsKey(EMIT_MODEL_METHODS)) {
|
||||
setEmitModelMethods(Boolean.parseBoolean((String)additionalProperties.get(EMIT_MODEL_METHODS)));
|
||||
@ -386,6 +387,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
|
||||
|
||||
public void setUseInheritance(boolean useInheritance) {
|
||||
this.supportsInheritance = useInheritance;
|
||||
this.supportsMixins = useInheritance;
|
||||
}
|
||||
|
||||
public void setEmitModelMethods(boolean emitModelMethods) {
|
||||
@ -889,7 +891,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
|
||||
// NOTE: can't use 'mandatory' as it is built from ModelImpl.getRequired(), which sorts names
|
||||
// alphabetically and in any case the document order of 'required' and 'properties' can differ.
|
||||
List<CodegenProperty> required = new ArrayList<>();
|
||||
List<CodegenProperty> allRequired = supportsInheritance ? new ArrayList<CodegenProperty>() : required;
|
||||
List<CodegenProperty> allRequired = supportsInheritance || supportsMixins ? new ArrayList<CodegenProperty>() : required;
|
||||
cm.vendorExtensions.put("x-required", required);
|
||||
cm.vendorExtensions.put("x-all-required", allRequired);
|
||||
|
||||
@ -903,7 +905,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsInheritance) {
|
||||
if (supportsInheritance || supportsMixins) {
|
||||
for (CodegenProperty var : cm.allVars) {
|
||||
if (Boolean.TRUE.equals(var.required)) {
|
||||
allRequired.add(var);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.swagger.codegen;
|
||||
|
||||
import io.swagger.models.Model;
|
||||
import io.swagger.models.Operation;
|
||||
import io.swagger.models.Swagger;
|
||||
import io.swagger.models.properties.Property;
|
||||
@ -187,6 +188,129 @@ public class CodegenTest {
|
||||
Assert.assertEquals(op.discriminator, "className");
|
||||
}
|
||||
|
||||
@Test(description = "handle simple composition")
|
||||
public void simpleCompositionTest() {
|
||||
final Swagger swagger = parseAndPrepareSwagger("src/test/resources/2_0/allOfTest.yaml");
|
||||
final DefaultCodegen codegen = new DefaultCodegen();
|
||||
codegen.supportsInheritance = true;
|
||||
final Model model = swagger.getDefinitions().get("SimpleComposition");
|
||||
CodegenModel composed = codegen.fromModel("SimpleComposition", model, swagger.getDefinitions());
|
||||
|
||||
Assert.assertEquals(composed.vars.size(), 3);
|
||||
Assert.assertEquals(composed.vars.get(0).baseName, "modelOneProp");
|
||||
Assert.assertEquals(composed.vars.get(1).baseName, "modelTwoProp");
|
||||
Assert.assertEquals(composed.vars.get(2).baseName, "simpleCompositionProp");
|
||||
Assert.assertNull(composed.parent);
|
||||
}
|
||||
|
||||
@Test(description = "handle multi level composition")
|
||||
public void multiCompositionTest() {
|
||||
final Swagger swagger = parseAndPrepareSwagger("src/test/resources/2_0/allOfTest.yaml");
|
||||
final DefaultCodegen codegen = new DefaultCodegen();
|
||||
codegen.supportsInheritance = true;
|
||||
final Model model = swagger.getDefinitions().get("CompositionOfSimpleComposition");
|
||||
CodegenModel composed = codegen.fromModel("CompositionOfSimpleComposition", model, swagger.getDefinitions());
|
||||
|
||||
Assert.assertEquals(composed.vars.size(), 5);
|
||||
Assert.assertEquals(composed.vars.get(0).baseName, "modelOneProp");
|
||||
Assert.assertEquals(composed.vars.get(1).baseName, "modelTwoProp");
|
||||
Assert.assertEquals(composed.vars.get(2).baseName, "simpleCompositionProp");
|
||||
Assert.assertEquals(composed.vars.get(3).baseName, "modelThreeProp");
|
||||
Assert.assertEquals(composed.vars.get(4).baseName, "compositionOfSimpleCompositionProp");
|
||||
Assert.assertNull(composed.parent);
|
||||
}
|
||||
|
||||
@Test(description = "handle simple inheritance")
|
||||
public void simpleInheritanceTest() {
|
||||
final Swagger swagger = parseAndPrepareSwagger("src/test/resources/2_0/allOfTest.yaml");
|
||||
final DefaultCodegen codegen = new DefaultCodegen();
|
||||
codegen.supportsInheritance = true;
|
||||
final Model model = swagger.getDefinitions().get("ChildOfSimpleParent");
|
||||
CodegenModel child = codegen.fromModel("ChildOfSimpleParent", model, swagger.getDefinitions());
|
||||
|
||||
Assert.assertEquals(child.vars.size(), 2);
|
||||
Assert.assertEquals(child.vars.get(0).baseName, "modelOneProp");
|
||||
Assert.assertEquals(child.vars.get(1).baseName, "childOfSimpleParentProp");
|
||||
Assert.assertEquals(child.parent, "SimpleParent");
|
||||
}
|
||||
|
||||
@Test(description = "handle multi level inheritance")
|
||||
public void multiInheritanceTest() {
|
||||
final Swagger swagger = parseAndPrepareSwagger("src/test/resources/2_0/allOfTest.yaml");
|
||||
final DefaultCodegen codegen = new DefaultCodegen();
|
||||
codegen.supportsInheritance = true;
|
||||
final Model model = swagger.getDefinitions().get("ChildOfChildOfSimpleParent");
|
||||
CodegenModel child = codegen.fromModel("ChildOfChildOfSimpleParent", model, swagger.getDefinitions());
|
||||
|
||||
Assert.assertEquals(child.vars.size(), 1);
|
||||
Assert.assertEquals(child.vars.get(0).baseName, "childOfChildOfSimpleParentProp");
|
||||
Assert.assertEquals(child.parent, "ChildOfSimpleParent");
|
||||
}
|
||||
|
||||
@Test(description = "copy properties in multi level inheritance if supportsInheritance is false")
|
||||
public void noSupportsInheritanceTest() {
|
||||
final Swagger swagger = parseAndPrepareSwagger("src/test/resources/2_0/allOfTest.yaml");
|
||||
final DefaultCodegen codegen = new DefaultCodegen();
|
||||
final Model model = swagger.getDefinitions().get("ChildOfChildOfSimpleParent");
|
||||
CodegenModel child = codegen.fromModel("ChildOfChildOfSimpleParent", model, swagger.getDefinitions());
|
||||
|
||||
Assert.assertEquals(child.vars.size(), 5);
|
||||
Assert.assertEquals(child.vars.get(0).baseName, "modelOneProp");
|
||||
Assert.assertEquals(child.vars.get(1).baseName, "disc");
|
||||
Assert.assertEquals(child.vars.get(2).baseName, "simpleParentProp");
|
||||
Assert.assertEquals(child.vars.get(3).baseName, "childOfSimpleParentProp");
|
||||
Assert.assertEquals(child.vars.get(4).baseName, "childOfChildOfSimpleParentProp");
|
||||
Assert.assertEquals(child.parent, "ChildOfSimpleParent");
|
||||
}
|
||||
|
||||
@Test(description = "don't copy interfaces properties if supportsMixins is true")
|
||||
public void supportsMixinsTest() {
|
||||
final Swagger swagger = parseAndPrepareSwagger("src/test/resources/2_0/allOfTest.yaml");
|
||||
final DefaultCodegen codegen = new DefaultCodegen();
|
||||
codegen.supportsInheritance = true;
|
||||
codegen.supportsMixins = true;
|
||||
final Model model = swagger.getDefinitions().get("ChildOfChildOfSimpleParent");
|
||||
CodegenModel child = codegen.fromModel("ChildOfChildOfSimpleParent", model, swagger.getDefinitions());
|
||||
|
||||
Assert.assertEquals(child.vars.size(), 1);
|
||||
Assert.assertEquals(child.vars.get(0).baseName, "childOfChildOfSimpleParentProp");
|
||||
Assert.assertEquals(child.allVars.size(), 5);
|
||||
Assert.assertEquals(child.allVars.get(0).baseName, "modelOneProp");
|
||||
Assert.assertEquals(child.allVars.get(1).baseName, "disc");
|
||||
Assert.assertEquals(child.allVars.get(2).baseName, "simpleParentProp");
|
||||
Assert.assertEquals(child.allVars.get(3).baseName, "childOfSimpleParentProp");
|
||||
Assert.assertEquals(child.allVars.get(4).baseName, "childOfChildOfSimpleParentProp");
|
||||
|
||||
Assert.assertEquals(child.parent, "ChildOfSimpleParent");
|
||||
}
|
||||
|
||||
@Test(description = "handle inheritance from composed model")
|
||||
public void inheritanceOfComposedModelTest() {
|
||||
final Swagger swagger = parseAndPrepareSwagger("src/test/resources/2_0/allOfTest.yaml");
|
||||
final DefaultCodegen codegen = new DefaultCodegen();
|
||||
codegen.supportsInheritance = true;
|
||||
final Model model = swagger.getDefinitions().get("ChildOfComposedParent");
|
||||
CodegenModel child = codegen.fromModel("ChildOfComposedParent", model, swagger.getDefinitions());
|
||||
|
||||
Assert.assertEquals(child.vars.size(), 1);
|
||||
Assert.assertEquals(child.vars.get(0).baseName, "childOfComposedParentProp");
|
||||
Assert.assertEquals(child.parent, "ComposedParent");
|
||||
}
|
||||
|
||||
@Test(description = "handle multi level inheritance from composed model")
|
||||
public void multiInheritanceOfComposedModelTest() {
|
||||
final Swagger swagger = parseAndPrepareSwagger("src/test/resources/2_0/allOfTest.yaml");
|
||||
final DefaultCodegen codegen = new DefaultCodegen();
|
||||
codegen.supportsInheritance = true;
|
||||
final Model model = swagger.getDefinitions().get("ChildOfChildOfComposedParent");
|
||||
CodegenModel child = codegen.fromModel("ChildOfChildOfComposedParent", model, swagger.getDefinitions());
|
||||
|
||||
Assert.assertEquals(child.vars.size(), 1);
|
||||
Assert.assertEquals(child.vars.get(0).baseName, "childOfChildOfComposedParentProp");
|
||||
Assert.assertEquals(child.parent, "ChildOfComposedParent");
|
||||
}
|
||||
|
||||
|
||||
@Test(description = "use operation consumes and produces")
|
||||
public void localConsumesAndProducesTest() {
|
||||
final Swagger model = parseAndPrepareSwagger("src/test/resources/2_0/globalConsumesAndProduces.json");
|
||||
|
104
modules/swagger-codegen/src/test/resources/2_0/allOfTest.yaml
Normal file
104
modules/swagger-codegen/src/test/resources/2_0/allOfTest.yaml
Normal file
@ -0,0 +1,104 @@
|
||||
swagger: '2.0'
|
||||
info:
|
||||
version: 0.0.0
|
||||
title: Simple API
|
||||
paths:
|
||||
/:
|
||||
get:
|
||||
responses:
|
||||
200:
|
||||
description: OK
|
||||
|
||||
definitions:
|
||||
|
||||
ModelOne:
|
||||
type: object
|
||||
properties:
|
||||
modelOneProp:
|
||||
type: string
|
||||
|
||||
ModelTwo:
|
||||
type: object
|
||||
properties:
|
||||
modelTwoProp:
|
||||
type: string
|
||||
|
||||
ModelThree:
|
||||
type: object
|
||||
properties:
|
||||
modelThreeProp:
|
||||
type: string
|
||||
|
||||
SimpleComposition:
|
||||
allOf:
|
||||
- $ref: '#/definitions/ModelOne'
|
||||
- $ref: '#/definitions/ModelTwo'
|
||||
- type: object
|
||||
properties:
|
||||
simpleCompositionProp:
|
||||
type: string
|
||||
|
||||
CompositionOfSimpleComposition:
|
||||
allOf:
|
||||
- $ref: '#/definitions/SimpleComposition'
|
||||
- $ref: '#/definitions/ModelThree'
|
||||
- type: object
|
||||
properties:
|
||||
compositionOfSimpleCompositionProp:
|
||||
type: string
|
||||
|
||||
SimpleParent:
|
||||
type: object
|
||||
discriminator: disc
|
||||
properties:
|
||||
disc:
|
||||
type: string
|
||||
simpleParentProp:
|
||||
type: string
|
||||
required: [disc]
|
||||
|
||||
ChildOfSimpleParent:
|
||||
allOf:
|
||||
- $ref: '#/definitions/ModelOne'
|
||||
- $ref: '#/definitions/SimpleParent'
|
||||
- type: object
|
||||
properties:
|
||||
childOfSimpleParentProp:
|
||||
type: string
|
||||
|
||||
ChildOfChildOfSimpleParent:
|
||||
allOf:
|
||||
- $ref: '#/definitions/ChildOfSimpleParent'
|
||||
- type: object
|
||||
properties:
|
||||
childOfChildOfSimpleParentProp:
|
||||
type: string
|
||||
|
||||
ComposedParent:
|
||||
allOf:
|
||||
- $ref: '#/definitions/ModelOne'
|
||||
- $ref: '#/definitions/ModelTwo'
|
||||
- type: object
|
||||
discriminator: disc
|
||||
properties:
|
||||
disc:
|
||||
type: string
|
||||
composedParentProp:
|
||||
type: string
|
||||
required: [disc]
|
||||
|
||||
ChildOfComposedParent:
|
||||
allOf:
|
||||
- $ref: '#/definitions/ComposedParent'
|
||||
- type: object
|
||||
properties:
|
||||
childOfComposedParentProp:
|
||||
type: string
|
||||
|
||||
ChildOfChildOfComposedParent:
|
||||
allOf:
|
||||
- $ref: '#/definitions/ChildOfComposedParent'
|
||||
- type: object
|
||||
properties:
|
||||
childOfChildOfComposedParentProp:
|
||||
type: string
|
Loading…
x
Reference in New Issue
Block a user