Skip to content

Commit

Permalink
enhanced support for additionalProperties
Browse files Browse the repository at this point in the history
  • Loading branch information
frantuma committed Nov 14, 2022
1 parent b03684f commit 991abce
Show file tree
Hide file tree
Showing 14 changed files with 309 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.swagger.jackson;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ResolvableSerializer;
import io.swagger.models.Model;

import java.io.IOException;

public class ModelSerializer extends JsonSerializer<Model> implements ResolvableSerializer {

private JsonSerializer<Object> defaultSerializer;

public ModelSerializer(JsonSerializer<Object> serializer) {
defaultSerializer = serializer;
}

@Override
public void resolve(SerializerProvider serializerProvider) throws JsonMappingException {
if (defaultSerializer instanceof ResolvableSerializer) {
((ResolvableSerializer) defaultSerializer).resolve(serializerProvider);
}
}

@Override
public void serialize(
Model value, JsonGenerator jgen, SerializerProvider provider)
throws IOException {

if (value.getBooleanValue() != null) {
jgen.writeBoolean(value.getBooleanValue());
} else {
defaultSerializer.serialize(value, jgen, provider);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.swagger.jackson;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ResolvableSerializer;
import io.swagger.models.properties.Property;

import java.io.IOException;

public class PropertySerializer extends JsonSerializer<Property> implements ResolvableSerializer {

private JsonSerializer<Object> defaultSerializer;

public PropertySerializer(JsonSerializer<Object> serializer) {
defaultSerializer = serializer;
}

@Override
public void resolve(SerializerProvider serializerProvider) throws JsonMappingException {
if (defaultSerializer instanceof ResolvableSerializer) {
((ResolvableSerializer) defaultSerializer).resolve(serializerProvider);
}
}

@Override
public void serialize(
Property value, JsonGenerator jgen, SerializerProvider provider)
throws IOException {

if (value.getBooleanValue() != null) {
jgen.writeBoolean(value.getBooleanValue());
} else {
defaultSerializer.serialize(value, jgen, provider);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.TextNode;
import io.swagger.models.ArrayModel;
import io.swagger.models.BooleanValueModel;
import io.swagger.models.ComposedModel;
import io.swagger.models.Model;
import io.swagger.models.ModelImpl;
Expand All @@ -21,6 +22,9 @@ public class ModelDeserializer extends JsonDeserializer<Model> {
public Model deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
if (node.isBoolean()) {
return new BooleanValueModel(node.asBoolean());
}
JsonNode sub = node.get("$ref");
JsonNode allOf = node.get("allOf");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.swagger.jackson.ModelSerializer;
import io.swagger.jackson.PropertySerializer;
import io.swagger.jackson.mixin.OperationResponseMixin;
import io.swagger.jackson.mixin.ResponseSchemaMixin;
import io.swagger.models.Model;
import io.swagger.models.Operation;
import io.swagger.models.Response;
import io.swagger.models.properties.Property;

public class ObjectMapperFactory {

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

mapper.registerModule(new SimpleModule() {
@Override
public void setupModule(SetupContext context) {
super.setupModule(context);
context.addBeanSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(
SerializationConfig config, BeanDescription desc, JsonSerializer<?> serializer) {
if (Property.class.isAssignableFrom(desc.getBeanClass())) {
return new PropertySerializer((JsonSerializer<Object>) serializer);
} else if (Model.class.isAssignableFrom(desc.getBeanClass())) {
return new ModelSerializer((JsonSerializer<Object>) serializer);
}
return serializer;
}
});
}
});

Module deserializerModule = new DeserializationModule(includePathDeserializer, includeResponseDeserializer);
mapper.registerModule(deserializerModule);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.BooleanValueProperty;
import io.swagger.models.properties.ComposedProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.ObjectProperty;
Expand Down Expand Up @@ -201,6 +202,10 @@ private Map<PropertyBuilder.PropertyId, Object> argsFromNode(JsonNode node) {
}

Property propertyFromNode(JsonNode node) {

if (node.isBoolean()) {
return new BooleanValueProperty(node.asBoolean());
}
final String type = getString(node, PropertyBuilder.PropertyId.TYPE);
final String title = getString(node, PropertyBuilder.PropertyId.TITLE);
final String format = getString(node, PropertyBuilder.PropertyId.FORMAT);
Expand Down Expand Up @@ -237,6 +242,18 @@ Property propertyFromNode(JsonNode node) {
mapProperty.setReadOnly(readOnly);
return mapProperty;
}
} else if (detailNode != null && detailNode.getNodeType().equals(JsonNodeType.BOOLEAN)) {
Property items = new BooleanValueProperty(detailNode.asBoolean());
MapProperty mapProperty = new MapProperty(items)
.description(description)
.title(title)
.xml(xml);
mapProperty.setExample(example);
mapProperty.setMinProperties(getInteger(node, PropertyBuilder.PropertyId.MIN_PROPERTIES));
mapProperty.setMaxProperties(getInteger(node, PropertyBuilder.PropertyId.MAX_PROPERTIES));
mapProperty.setVendorExtensionMap(getVendorExtensions(node));
mapProperty.setReadOnly(readOnly);
return mapProperty;
} else {
JsonNode allOfNode = node.get("allOf");
detailNode = node.get("properties");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package io.swagger;

import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.matchers.SerializationMatchers;
import io.swagger.models.ModelImpl;
import io.swagger.models.Swagger;
import io.swagger.util.Yaml;
import org.testng.annotations.Test;

import static org.testng.Assert.assertEquals;

public class BooleanModelTest {
@Test
public void testBooleanProperty() throws JsonProcessingException {
String yaml = "swagger: '2.0'\n" +
"info:\n" +
" title: Some API\n" +
" description: >-\n" +
" This is the Some Api\n" +
" version: 2.0.0\n" +
"basePath: /somepath\n" +
"schemes:\n" +
" - https\n" +
"consumes:\n" +
" - application/json\n" +
"produces:\n" +
" - application/json\n" +
"paths:\n" +
" /somepath:\n" +
" get:\n" +
" description: >\n" +
" my description\n" +
" operationId: MyGet\n" +
" responses:\n" +
" '200':\n" +
" $ref: '#/responses/Response'\n" +
"responses:\n" +
" Response:\n" +
" description: Response\n" +
" schema:\n" +
" type: object\n" +
" required:\n" +
" - Report\n" +
" properties:\n" +
" Report:\n" +
" type: string\n" +
" additionalProperties: false";

Swagger swagger = Yaml.mapper().readValue(yaml, Swagger.class);
assertEquals(((ModelImpl)swagger.getResponses().get("Response").getResponseSchema()).getAdditionalProperties().getBooleanValue().booleanValue(), false);
SerializationMatchers.assertEqualsToYaml(swagger, "swagger: \"2.0\"\n" +
"info:\n" +
" description: \"This is the Some Api\"\n" +
" version: \"2.0.0\"\n" +
" title: \"Some API\"\n" +
"basePath: \"/somepath\"\n" +
"schemes:\n" +
"- \"https\"\n" +
"consumes:\n" +
"- \"application/json\"\n" +
"produces:\n" +
"- \"application/json\"\n" +
"paths:\n" +
" /somepath:\n" +
" get:\n" +
" description: \"my description\\n\"\n" +
" operationId: \"MyGet\"\n" +
" parameters: []\n" +
" responses:\n" +
" \"200\":\n" +
" $ref: \"#/responses/Response\"\n" +
"responses:\n" +
" Response:\n" +
" description: \"Response\"\n" +
" schema:\n" +
" type: \"object\"\n" +
" required:\n" +
" - \"Report\"\n" +
" properties:\n" +
" Report:\n" +
" type: \"string\"\n" +
" additionalProperties: false");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ public abstract class AbstractModel implements Model {
protected Map<String, Property> properties;
protected List<String> required;

protected Boolean booleanValue;

@JsonIgnore
public Boolean getBooleanValue() {
return booleanValue;
}

public void setBooleanValue(Boolean booleanValue) {
this.booleanValue = booleanValue;
}

@Override
public ExternalDocs getExternalDocs() {
return externalDocs;
Expand Down Expand Up @@ -128,7 +139,7 @@ public void setPattern(String pattern) {
public void setVendorExtensions(Map<String, Object> vendorExtensions) {
this.vendorExtensions = vendorExtensions;
}

public Map<String, Property> getProperties() {
return properties;
}
Expand All @@ -140,7 +151,7 @@ public void setProperties(Map<String, Property> properties) {
}
}
}

public void addProperty(String key, Property property) {
if (property == null) {
return;
Expand All @@ -157,7 +168,7 @@ public void addProperty(String key, Property property) {
}
properties.put(key, property);
}

public List<String> getRequired() {
List<String> output = new ArrayList<String>();
if (properties != null) {
Expand Down Expand Up @@ -216,6 +227,7 @@ public void cloneTo(Object clone) {
} else {
cloned.xml = (Xml) xml.clone();
}
cloned.booleanValue = booleanValue;
}

public Object clone() {
Expand All @@ -242,6 +254,7 @@ public int hashCode() {
result = prime * result + (pattern != null ? pattern.hashCode() : 0);
result = prime * result + (properties != null ? properties.hashCode() : 0);
result = prime * result + (required != null ? required.hashCode() : 0);
result = prime * result + (booleanValue != null ? booleanValue.hashCode() : 0);
return result;
}

Expand Down Expand Up @@ -315,15 +328,20 @@ public boolean equals(Object obj) {
}
if (pattern != null ? !pattern.equals(other.pattern) : other.pattern != null) {
return false;
}
}
if (required != null ? !required.equals(other.required) : other.required != null) {
return false;
}
if (properties != null ? !properties.equals(other.properties) : other.properties != null) {
return false;
}

if (booleanValue != null ? !booleanValue.equals(other.booleanValue) : other.booleanValue != null) {
return false;
}

return maximum != null ? maximum.equals(other.maximum) : other.maximum == null;

}

@JsonIgnore
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.swagger.models;

public class BooleanValueModel extends AbstractModel {

public BooleanValueModel() {}
public BooleanValueModel(Boolean booleanValue) {
this.setBooleanValue(booleanValue);
}
@Override
public String getDescription() {
return null;
}

@Override
public void setDescription(String description) {

}

@Override
public Object getExample() {
return null;
}

@Override
public void setExample(Object example) {

}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.swagger.models;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.models.properties.Property;

import java.util.Map;
Expand Down Expand Up @@ -30,4 +31,9 @@ public interface Model {
Object clone();

Map<String, Object> getVendorExtensions();

@JsonIgnore
Boolean getBooleanValue();

void setBooleanValue(Boolean booleanValue);
}
Loading

0 comments on commit 991abce

Please sign in to comment.