diff --git a/modules/swagger-core/src/main/java/io/swagger/util/PropertyDeserializer.java b/modules/swagger-core/src/main/java/io/swagger/util/PropertyDeserializer.java index 5faa5b1040..1e11a3d03a 100644 --- a/modules/swagger-core/src/main/java/io/swagger/util/PropertyDeserializer.java +++ b/modules/swagger-core/src/main/java/io/swagger/util/PropertyDeserializer.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.databind.node.TextNode; import io.swagger.models.Xml; import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.ComposedProperty; import io.swagger.models.properties.MapProperty; import io.swagger.models.properties.ObjectProperty; import io.swagger.models.properties.Property; @@ -219,7 +220,7 @@ Property propertyFromNode(JsonNode node) { return refProperty; } - if (ObjectProperty.isType(type) || node.get("properties") != null) { + if (ObjectProperty.isType(type) || node.get("properties") != null || node.get("allOf") != null) { JsonNode example = getDetailNode(node, PropertyBuilder.PropertyId.EXAMPLE); detailNode = node.get("additionalProperties"); if (detailNode != null && detailNode.getNodeType().equals(JsonNodeType.OBJECT)) { @@ -236,6 +237,7 @@ Property propertyFromNode(JsonNode node) { return mapProperty; } } else { + JsonNode allOfNode = node.get("allOf"); detailNode = node.get("properties"); String detailNodeType = null; Map properties = new LinkedHashMap(); @@ -255,6 +257,20 @@ Property propertyFromNode(JsonNode node) { } } } + } else if (allOfNode != null) { + ComposedProperty cp = new ComposedProperty().description(description).title(title); + cp.setExample(example); + cp.setDescription(description); + cp.setVendorExtensions(getVendorExtensions(node)); + + List allOf = new ArrayList(); + for (JsonNode innerNode : allOfNode) { + allOf.add(propertyFromNode(innerNode)); + } + + cp.setAllOf(allOf); + + return cp; } if("array".equals(detailNodeType)) { diff --git a/modules/swagger-core/src/test/java/io/swagger/ComposedPropertyTest.java b/modules/swagger-core/src/test/java/io/swagger/ComposedPropertyTest.java new file mode 100644 index 0000000000..d3b7d0898a --- /dev/null +++ b/modules/swagger-core/src/test/java/io/swagger/ComposedPropertyTest.java @@ -0,0 +1,75 @@ +package io.swagger; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.io.IOException; + +import org.testng.annotations.Test; + +import io.swagger.models.ModelImpl; +import io.swagger.models.properties.AbstractNumericProperty; +import io.swagger.models.properties.ComposedProperty; +import io.swagger.models.properties.ObjectProperty; +import io.swagger.models.properties.Property; +import io.swagger.models.properties.StringProperty; +import io.swagger.util.Json; + +public class ComposedPropertyTest { + + @Test(description = "convert a model with object properties") + public void readModelWithObjectProperty() throws IOException { + String json = "{\n" + + " \"properties\":{\n" + + " \"id\":{\n" + + " \"type\":\"string\"\n" + + " },\n" + + " \"someObject\":{\n" + + " \"type\":\"object\",\n" + + " \"x-foo\": \"vendor x\",\n" + + " \"allOf\":[\n" + + " {\n" + + " \"type\":\"object\",\n" + + " \"properties\":{\n" + + " \"innerId\":{\n" + + " \"type\":\"string\"\n" + + " }\n" + + " }\n" + + " },{\n" + + " \"type\":\"object\",\n" + + " \"properties\":{\n" + + " \"innerLength\":{\n" + + " \"type\":\"number\"\n" + + " }\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + + ModelImpl model = Json.mapper().readValue(json, ModelImpl.class); + + Property p = model.getProperties().get("someObject"); + assertTrue(p instanceof ComposedProperty); + + ComposedProperty cp = (ComposedProperty) p; + + Property op0 = cp.getAllOf().get(0); + Property op1 = cp.getAllOf().get(1); + + assertTrue(op0 instanceof ObjectProperty); + assertTrue(op1 instanceof ObjectProperty); + + Property sp = ((ObjectProperty) op0).getProperties().get("innerId"); + Property np = ((ObjectProperty) op1).getProperties().get("innerLength"); + + assertTrue(sp instanceof StringProperty); + assertTrue(np instanceof AbstractNumericProperty); + + assertTrue(cp.getVendorExtensions() != null); + assertNotNull(cp.getVendorExtensions().get("x-foo")); + assertEquals(cp.getVendorExtensions().get("x-foo"), "vendor x"); + } +} diff --git a/modules/swagger-models/src/main/java/io/swagger/models/properties/ComposedProperty.java b/modules/swagger-models/src/main/java/io/swagger/models/properties/ComposedProperty.java new file mode 100644 index 0000000000..87b40f66b9 --- /dev/null +++ b/modules/swagger-models/src/main/java/io/swagger/models/properties/ComposedProperty.java @@ -0,0 +1,100 @@ +package io.swagger.models.properties; + +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +import io.swagger.models.Xml; + +public class ComposedProperty extends AbstractProperty implements Property { + + public static final String TYPE = "object"; + private List allOf = new LinkedList(); + + public ComposedProperty() { + super.type = TYPE; + } + + public ComposedProperty vendorExtension(String key, Object obj) { + this.setVendorExtension(key, obj); + return this; + } + + public ComposedProperty access(String access) { + this.setAccess(access); + return this; + } + + @Override + public ComposedProperty description(String description) { + this.setDescription(description); + return this; + } + + public ComposedProperty name(String name) { + this.setName(name); + return this; + } + + @Override + public ComposedProperty title(String title) { + this.setTitle(title); + return this; + } + + public ComposedProperty _default(String _default) { + this.setDefault(_default); + return this; + } + + public ComposedProperty readOnly(boolean readOnly) { + this.setReadOnly(readOnly); + return this; + } + + public ComposedProperty required(boolean required) { + this.setRequired(required); + return this; + } + + public List getAllOf() { + return allOf; + } + + public void setAllOf(List allOf) { + this.allOf = allOf; + } + + @Override + public ComposedProperty readOnly() { + this.setReadOnly(Boolean.TRUE); + return this; + } + + public ComposedProperty xml(Xml xml) { + this.setXml(xml); + return this; + } + + public ComposedProperty example(Object example) { + this.setExample(example); + return this; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ComposedProperty)) { + return false; + } + + return Objects.equals(allOf, ((ComposedProperty) o).allOf); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (allOf != null ? allOf.hashCode() : 0); + + return result; + } +}