Skip to content

Commit 991abce

Browse files
committed
enhanced support for additionalProperties
1 parent b03684f commit 991abce

File tree

14 files changed

+309
-6
lines changed

14 files changed

+309
-6
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package io.swagger.jackson;
2+
3+
import com.fasterxml.jackson.core.JsonGenerator;
4+
import com.fasterxml.jackson.databind.JsonMappingException;
5+
import com.fasterxml.jackson.databind.JsonSerializer;
6+
import com.fasterxml.jackson.databind.SerializerProvider;
7+
import com.fasterxml.jackson.databind.ser.ResolvableSerializer;
8+
import io.swagger.models.Model;
9+
10+
import java.io.IOException;
11+
12+
public class ModelSerializer extends JsonSerializer<Model> implements ResolvableSerializer {
13+
14+
private JsonSerializer<Object> defaultSerializer;
15+
16+
public ModelSerializer(JsonSerializer<Object> serializer) {
17+
defaultSerializer = serializer;
18+
}
19+
20+
@Override
21+
public void resolve(SerializerProvider serializerProvider) throws JsonMappingException {
22+
if (defaultSerializer instanceof ResolvableSerializer) {
23+
((ResolvableSerializer) defaultSerializer).resolve(serializerProvider);
24+
}
25+
}
26+
27+
@Override
28+
public void serialize(
29+
Model value, JsonGenerator jgen, SerializerProvider provider)
30+
throws IOException {
31+
32+
if (value.getBooleanValue() != null) {
33+
jgen.writeBoolean(value.getBooleanValue());
34+
} else {
35+
defaultSerializer.serialize(value, jgen, provider);
36+
}
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package io.swagger.jackson;
2+
3+
import com.fasterxml.jackson.core.JsonGenerator;
4+
import com.fasterxml.jackson.databind.JsonMappingException;
5+
import com.fasterxml.jackson.databind.JsonSerializer;
6+
import com.fasterxml.jackson.databind.SerializerProvider;
7+
import com.fasterxml.jackson.databind.ser.ResolvableSerializer;
8+
import io.swagger.models.properties.Property;
9+
10+
import java.io.IOException;
11+
12+
public class PropertySerializer extends JsonSerializer<Property> implements ResolvableSerializer {
13+
14+
private JsonSerializer<Object> defaultSerializer;
15+
16+
public PropertySerializer(JsonSerializer<Object> serializer) {
17+
defaultSerializer = serializer;
18+
}
19+
20+
@Override
21+
public void resolve(SerializerProvider serializerProvider) throws JsonMappingException {
22+
if (defaultSerializer instanceof ResolvableSerializer) {
23+
((ResolvableSerializer) defaultSerializer).resolve(serializerProvider);
24+
}
25+
}
26+
27+
@Override
28+
public void serialize(
29+
Property value, JsonGenerator jgen, SerializerProvider provider)
30+
throws IOException {
31+
32+
if (value.getBooleanValue() != null) {
33+
jgen.writeBoolean(value.getBooleanValue());
34+
} else {
35+
defaultSerializer.serialize(value, jgen, provider);
36+
}
37+
}
38+
}

modules/swagger-core/src/main/java/io/swagger/util/ModelDeserializer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.fasterxml.jackson.databind.JsonNode;
88
import com.fasterxml.jackson.databind.node.TextNode;
99
import io.swagger.models.ArrayModel;
10+
import io.swagger.models.BooleanValueModel;
1011
import io.swagger.models.ComposedModel;
1112
import io.swagger.models.Model;
1213
import io.swagger.models.ModelImpl;
@@ -21,6 +22,9 @@ public class ModelDeserializer extends JsonDeserializer<Model> {
2122
public Model deserialize(JsonParser jp, DeserializationContext ctxt)
2223
throws IOException, JsonProcessingException {
2324
JsonNode node = jp.getCodec().readTree(jp);
25+
if (node.isBoolean()) {
26+
return new BooleanValueModel(node.asBoolean());
27+
}
2428
JsonNode sub = node.get("$ref");
2529
JsonNode allOf = node.get("allOf");
2630

modules/swagger-core/src/main/java/io/swagger/util/ObjectMapperFactory.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,24 @@
22

33
import com.fasterxml.jackson.annotation.JsonInclude;
44
import com.fasterxml.jackson.core.JsonFactory;
5+
import com.fasterxml.jackson.databind.BeanDescription;
56
import com.fasterxml.jackson.databind.DeserializationFeature;
7+
import com.fasterxml.jackson.databind.JsonSerializer;
68
import com.fasterxml.jackson.databind.Module;
79
import com.fasterxml.jackson.databind.ObjectMapper;
10+
import com.fasterxml.jackson.databind.SerializationConfig;
811
import com.fasterxml.jackson.databind.SerializationFeature;
12+
import com.fasterxml.jackson.databind.module.SimpleModule;
13+
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
914
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
15+
import io.swagger.jackson.ModelSerializer;
16+
import io.swagger.jackson.PropertySerializer;
1017
import io.swagger.jackson.mixin.OperationResponseMixin;
1118
import io.swagger.jackson.mixin.ResponseSchemaMixin;
19+
import io.swagger.models.Model;
1220
import io.swagger.models.Operation;
1321
import io.swagger.models.Response;
22+
import io.swagger.models.properties.Property;
1423

1524
public class ObjectMapperFactory {
1625

@@ -33,6 +42,25 @@ protected static ObjectMapper createYaml(boolean includePathDeserializer, boolea
3342
private static ObjectMapper create(JsonFactory jsonFactory, boolean includePathDeserializer, boolean includeResponseDeserializer) {
3443
ObjectMapper mapper = jsonFactory == null ? new ObjectMapper() : new ObjectMapper(jsonFactory);
3544

45+
mapper.registerModule(new SimpleModule() {
46+
@Override
47+
public void setupModule(SetupContext context) {
48+
super.setupModule(context);
49+
context.addBeanSerializerModifier(new BeanSerializerModifier() {
50+
@Override
51+
public JsonSerializer<?> modifySerializer(
52+
SerializationConfig config, BeanDescription desc, JsonSerializer<?> serializer) {
53+
if (Property.class.isAssignableFrom(desc.getBeanClass())) {
54+
return new PropertySerializer((JsonSerializer<Object>) serializer);
55+
} else if (Model.class.isAssignableFrom(desc.getBeanClass())) {
56+
return new ModelSerializer((JsonSerializer<Object>) serializer);
57+
}
58+
return serializer;
59+
}
60+
});
61+
}
62+
});
63+
3664
Module deserializerModule = new DeserializationModule(includePathDeserializer, includeResponseDeserializer);
3765
mapper.registerModule(deserializerModule);
3866
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

modules/swagger-core/src/main/java/io/swagger/util/PropertyDeserializer.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.fasterxml.jackson.databind.node.TextNode;
1818
import io.swagger.models.Xml;
1919
import io.swagger.models.properties.ArrayProperty;
20+
import io.swagger.models.properties.BooleanValueProperty;
2021
import io.swagger.models.properties.ComposedProperty;
2122
import io.swagger.models.properties.MapProperty;
2223
import io.swagger.models.properties.ObjectProperty;
@@ -201,6 +202,10 @@ private Map<PropertyBuilder.PropertyId, Object> argsFromNode(JsonNode node) {
201202
}
202203

203204
Property propertyFromNode(JsonNode node) {
205+
206+
if (node.isBoolean()) {
207+
return new BooleanValueProperty(node.asBoolean());
208+
}
204209
final String type = getString(node, PropertyBuilder.PropertyId.TYPE);
205210
final String title = getString(node, PropertyBuilder.PropertyId.TITLE);
206211
final String format = getString(node, PropertyBuilder.PropertyId.FORMAT);
@@ -237,6 +242,18 @@ Property propertyFromNode(JsonNode node) {
237242
mapProperty.setReadOnly(readOnly);
238243
return mapProperty;
239244
}
245+
} else if (detailNode != null && detailNode.getNodeType().equals(JsonNodeType.BOOLEAN)) {
246+
Property items = new BooleanValueProperty(detailNode.asBoolean());
247+
MapProperty mapProperty = new MapProperty(items)
248+
.description(description)
249+
.title(title)
250+
.xml(xml);
251+
mapProperty.setExample(example);
252+
mapProperty.setMinProperties(getInteger(node, PropertyBuilder.PropertyId.MIN_PROPERTIES));
253+
mapProperty.setMaxProperties(getInteger(node, PropertyBuilder.PropertyId.MAX_PROPERTIES));
254+
mapProperty.setVendorExtensionMap(getVendorExtensions(node));
255+
mapProperty.setReadOnly(readOnly);
256+
return mapProperty;
240257
} else {
241258
JsonNode allOfNode = node.get("allOf");
242259
detailNode = node.get("properties");
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package io.swagger;
2+
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import io.swagger.matchers.SerializationMatchers;
5+
import io.swagger.models.ModelImpl;
6+
import io.swagger.models.Swagger;
7+
import io.swagger.util.Yaml;
8+
import org.testng.annotations.Test;
9+
10+
import static org.testng.Assert.assertEquals;
11+
12+
public class BooleanModelTest {
13+
@Test
14+
public void testBooleanProperty() throws JsonProcessingException {
15+
String yaml = "swagger: '2.0'\n" +
16+
"info:\n" +
17+
" title: Some API\n" +
18+
" description: >-\n" +
19+
" This is the Some Api\n" +
20+
" version: 2.0.0\n" +
21+
"basePath: /somepath\n" +
22+
"schemes:\n" +
23+
" - https\n" +
24+
"consumes:\n" +
25+
" - application/json\n" +
26+
"produces:\n" +
27+
" - application/json\n" +
28+
"paths:\n" +
29+
" /somepath:\n" +
30+
" get:\n" +
31+
" description: >\n" +
32+
" my description\n" +
33+
" operationId: MyGet\n" +
34+
" responses:\n" +
35+
" '200':\n" +
36+
" $ref: '#/responses/Response'\n" +
37+
"responses:\n" +
38+
" Response:\n" +
39+
" description: Response\n" +
40+
" schema:\n" +
41+
" type: object\n" +
42+
" required:\n" +
43+
" - Report\n" +
44+
" properties:\n" +
45+
" Report:\n" +
46+
" type: string\n" +
47+
" additionalProperties: false";
48+
49+
Swagger swagger = Yaml.mapper().readValue(yaml, Swagger.class);
50+
assertEquals(((ModelImpl)swagger.getResponses().get("Response").getResponseSchema()).getAdditionalProperties().getBooleanValue().booleanValue(), false);
51+
SerializationMatchers.assertEqualsToYaml(swagger, "swagger: \"2.0\"\n" +
52+
"info:\n" +
53+
" description: \"This is the Some Api\"\n" +
54+
" version: \"2.0.0\"\n" +
55+
" title: \"Some API\"\n" +
56+
"basePath: \"/somepath\"\n" +
57+
"schemes:\n" +
58+
"- \"https\"\n" +
59+
"consumes:\n" +
60+
"- \"application/json\"\n" +
61+
"produces:\n" +
62+
"- \"application/json\"\n" +
63+
"paths:\n" +
64+
" /somepath:\n" +
65+
" get:\n" +
66+
" description: \"my description\\n\"\n" +
67+
" operationId: \"MyGet\"\n" +
68+
" parameters: []\n" +
69+
" responses:\n" +
70+
" \"200\":\n" +
71+
" $ref: \"#/responses/Response\"\n" +
72+
"responses:\n" +
73+
" Response:\n" +
74+
" description: \"Response\"\n" +
75+
" schema:\n" +
76+
" type: \"object\"\n" +
77+
" required:\n" +
78+
" - \"Report\"\n" +
79+
" properties:\n" +
80+
" Report:\n" +
81+
" type: \"string\"\n" +
82+
" additionalProperties: false");
83+
}
84+
}

modules/swagger-models/src/main/java/io/swagger/models/AbstractModel.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ public abstract class AbstractModel implements Model {
3030
protected Map<String, Property> properties;
3131
protected List<String> required;
3232

33+
protected Boolean booleanValue;
34+
35+
@JsonIgnore
36+
public Boolean getBooleanValue() {
37+
return booleanValue;
38+
}
39+
40+
public void setBooleanValue(Boolean booleanValue) {
41+
this.booleanValue = booleanValue;
42+
}
43+
3344
@Override
3445
public ExternalDocs getExternalDocs() {
3546
return externalDocs;
@@ -128,7 +139,7 @@ public void setPattern(String pattern) {
128139
public void setVendorExtensions(Map<String, Object> vendorExtensions) {
129140
this.vendorExtensions = vendorExtensions;
130141
}
131-
142+
132143
public Map<String, Property> getProperties() {
133144
return properties;
134145
}
@@ -140,7 +151,7 @@ public void setProperties(Map<String, Property> properties) {
140151
}
141152
}
142153
}
143-
154+
144155
public void addProperty(String key, Property property) {
145156
if (property == null) {
146157
return;
@@ -157,7 +168,7 @@ public void addProperty(String key, Property property) {
157168
}
158169
properties.put(key, property);
159170
}
160-
171+
161172
public List<String> getRequired() {
162173
List<String> output = new ArrayList<String>();
163174
if (properties != null) {
@@ -216,6 +227,7 @@ public void cloneTo(Object clone) {
216227
} else {
217228
cloned.xml = (Xml) xml.clone();
218229
}
230+
cloned.booleanValue = booleanValue;
219231
}
220232

221233
public Object clone() {
@@ -242,6 +254,7 @@ public int hashCode() {
242254
result = prime * result + (pattern != null ? pattern.hashCode() : 0);
243255
result = prime * result + (properties != null ? properties.hashCode() : 0);
244256
result = prime * result + (required != null ? required.hashCode() : 0);
257+
result = prime * result + (booleanValue != null ? booleanValue.hashCode() : 0);
245258
return result;
246259
}
247260

@@ -315,15 +328,20 @@ public boolean equals(Object obj) {
315328
}
316329
if (pattern != null ? !pattern.equals(other.pattern) : other.pattern != null) {
317330
return false;
318-
}
331+
}
319332
if (required != null ? !required.equals(other.required) : other.required != null) {
320333
return false;
321334
}
322335
if (properties != null ? !properties.equals(other.properties) : other.properties != null) {
323336
return false;
324337
}
325338

339+
if (booleanValue != null ? !booleanValue.equals(other.booleanValue) : other.booleanValue != null) {
340+
return false;
341+
}
342+
326343
return maximum != null ? maximum.equals(other.maximum) : other.maximum == null;
344+
327345
}
328346

329347
@JsonIgnore
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.swagger.models;
2+
3+
public class BooleanValueModel extends AbstractModel {
4+
5+
public BooleanValueModel() {}
6+
public BooleanValueModel(Boolean booleanValue) {
7+
this.setBooleanValue(booleanValue);
8+
}
9+
@Override
10+
public String getDescription() {
11+
return null;
12+
}
13+
14+
@Override
15+
public void setDescription(String description) {
16+
17+
}
18+
19+
@Override
20+
public Object getExample() {
21+
return null;
22+
}
23+
24+
@Override
25+
public void setExample(Object example) {
26+
27+
}
28+
}

modules/swagger-models/src/main/java/io/swagger/models/Model.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.swagger.models;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnore;
34
import io.swagger.models.properties.Property;
45

56
import java.util.Map;
@@ -30,4 +31,9 @@ public interface Model {
3031
Object clone();
3132

3233
Map<String, Object> getVendorExtensions();
34+
35+
@JsonIgnore
36+
Boolean getBooleanValue();
37+
38+
void setBooleanValue(Boolean booleanValue);
3339
}

0 commit comments

Comments
 (0)