All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.swagger.util.PropertyDeserializer Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc2
Show newest version
package io.swagger.util;


import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.DoubleNode;
import com.fasterxml.jackson.databind.node.FloatNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.NumericNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import io.swagger.models.Xml;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.ObjectProperty;
import io.swagger.models.properties.Property;
import io.swagger.models.properties.PropertyBuilder;
import io.swagger.models.properties.RefProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class PropertyDeserializer extends JsonDeserializer {
    Logger LOGGER = LoggerFactory.getLogger(PropertyDeserializer.class);

    private static String getString(JsonNode node, PropertyBuilder.PropertyId type) {
        final JsonNode detailNode = getDetailNode(node, type);
        return detailNode == null ? null : detailNode.asText();
    }

    private static Integer getInteger(JsonNode node, PropertyBuilder.PropertyId type) {
        final JsonNode detailNode = getDetailNode(node, type);
        return detailNode == null ? null : detailNode.intValue();
    }

    private static Double getDouble(JsonNode node, PropertyBuilder.PropertyId type) {
        final JsonNode detailNode = getDetailNode(node, type);
        return detailNode == null ? null : detailNode.doubleValue();
    }

    private static BigDecimal getBigDecimal(JsonNode node, PropertyBuilder.PropertyId type) {
        final JsonNode detailNode = getDetailNode(node, type);
        return detailNode == null ? null : new BigDecimal(detailNode.toString());
    }

    private static Boolean getBoolean(JsonNode node, PropertyBuilder.PropertyId type) {
        final JsonNode detailNode = getDetailNode(node, type);
        return detailNode == null ? null : detailNode.booleanValue();
    }

    private static List getEnum(JsonNode node, PropertyBuilder.PropertyId type) {
        final List result = new ArrayList();
        JsonNode detailNode = getDetailNode(node, type);
        if (detailNode != null) {
            ArrayNode an = (ArrayNode) detailNode;
            for (JsonNode child : an) {
                if (child instanceof TextNode ||
                    child instanceof NumericNode ||
                    child instanceof IntNode ||
                    child instanceof LongNode ||
                    child instanceof DoubleNode ||
                    child instanceof FloatNode) {
                    result.add(child.asText());
                }
            }
        }

        return result.isEmpty() ? null : result;
    }

    //because of the complexity of deserializing properties we must handle vendor extensions by hand
    private static Map getVendorExtensions(JsonNode node) {
        Map result = new HashMap();

        Iterator fieldNameIter = node.fieldNames();
        while (fieldNameIter.hasNext()) {
            String fieldName = fieldNameIter.next();

            if(fieldName.startsWith("x-")) {
                JsonNode extensionField = node.get(fieldName);

                Object extensionObject = Json.mapper().convertValue(extensionField, Object.class);
                result.put(fieldName, extensionObject);
            }
        }
        return result;
    }

    private static List getRequired(JsonNode node, PropertyBuilder.PropertyId type) {
        List result = new ArrayList();

        final JsonNode detailNode = getDetailNode(node, type);

        if (detailNode == null) {
            return result;
        }

        if (detailNode.isArray()) {
            ArrayNode arrayNode = (ArrayNode) detailNode;
            Iterator fieldNameIter = arrayNode.iterator();

            while (fieldNameIter.hasNext()) {
                JsonNode item = fieldNameIter.next();
                result.add(item.asText());
            }
            return result;
        } else {
            throw new RuntimeException("Required property should be a list");
        }

    }

    private static JsonNode getDetailNode(JsonNode node, PropertyBuilder.PropertyId type) {
        return node.get(type.getPropertyName());
    }

    @Override
    public Property deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        Property property = propertyFromNode(node);
        if(property != null) {
            property.setXml(getXml(node));
        }
        return property;
    }

    public Xml getXml(JsonNode node) {
        Xml xml = null;

        if (node instanceof ObjectNode) {
            ObjectNode obj = (ObjectNode) ((ObjectNode) node).get("xml");
            if (obj != null) {
                xml = new Xml();
                JsonNode n = obj.get("name");
                if (n != null) {
                    xml.name(n.asText());
                }
                n = obj.get("namespace");
                if (n != null) {
                    xml.namespace(n.asText());
                }
                n = obj.get("prefix");
                if (n != null) {
                    xml.prefix(n.asText());
                }
                n = obj.get("attribute");
                if (n != null) {
                    xml.attribute(n.asBoolean());
                }
                n = obj.get("wrapped");
                if (n != null) {
                    xml.wrapped(n.asBoolean());
                }
            }
        }
        return xml;
    }

    private Map argsFromNode(JsonNode node) {
        if (node == null) return Collections.emptyMap();
        final Map args = new EnumMap(PropertyBuilder.PropertyId.class);
        args.put(PropertyBuilder.PropertyId.TYPE, getString(node, PropertyBuilder.PropertyId.TYPE));
        args.put(PropertyBuilder.PropertyId.FORMAT, getString(node, PropertyBuilder.PropertyId.FORMAT));
        args.put(PropertyBuilder.PropertyId.DESCRIPTION, getString(node, PropertyBuilder.PropertyId.DESCRIPTION));
        args.put(PropertyBuilder.PropertyId.EXAMPLE, getString(node, PropertyBuilder.PropertyId.EXAMPLE));
        args.put(PropertyBuilder.PropertyId.ENUM, getEnum(node, PropertyBuilder.PropertyId.ENUM));
        args.put(PropertyBuilder.PropertyId.TITLE, getString(node, PropertyBuilder.PropertyId.TITLE));
        args.put(PropertyBuilder.PropertyId.DEFAULT, getString(node, PropertyBuilder.PropertyId.DEFAULT));
        args.put(PropertyBuilder.PropertyId.PATTERN, getString(node, PropertyBuilder.PropertyId.PATTERN));
        args.put(PropertyBuilder.PropertyId.DESCRIMINATOR, getString(node, PropertyBuilder.PropertyId.DESCRIMINATOR));
        args.put(PropertyBuilder.PropertyId.MIN_ITEMS, getInteger(node, PropertyBuilder.PropertyId.MIN_ITEMS));
        args.put(PropertyBuilder.PropertyId.MAX_ITEMS, getInteger(node, PropertyBuilder.PropertyId.MAX_ITEMS));
        args.put(PropertyBuilder.PropertyId.MIN_PROPERTIES, getInteger(node, PropertyBuilder.PropertyId.MIN_PROPERTIES));
        args.put(PropertyBuilder.PropertyId.MAX_PROPERTIES, getInteger(node, PropertyBuilder.PropertyId.MAX_PROPERTIES));
        args.put(PropertyBuilder.PropertyId.MIN_LENGTH, getInteger(node, PropertyBuilder.PropertyId.MIN_LENGTH));
        args.put(PropertyBuilder.PropertyId.MAX_LENGTH, getInteger(node, PropertyBuilder.PropertyId.MAX_LENGTH));
        args.put(PropertyBuilder.PropertyId.MINIMUM, getBigDecimal(node, PropertyBuilder.PropertyId.MINIMUM));
        args.put(PropertyBuilder.PropertyId.MAXIMUM, getBigDecimal(node, PropertyBuilder.PropertyId.MAXIMUM));
        args.put(PropertyBuilder.PropertyId.MULTIPLE_OF, getBigDecimal(node, PropertyBuilder.PropertyId.MULTIPLE_OF));
        args.put(PropertyBuilder.PropertyId.EXCLUSIVE_MINIMUM, getBoolean(node, PropertyBuilder.PropertyId.EXCLUSIVE_MINIMUM));
        args.put(PropertyBuilder.PropertyId.EXCLUSIVE_MAXIMUM, getBoolean(node, PropertyBuilder.PropertyId.EXCLUSIVE_MAXIMUM));
        args.put(PropertyBuilder.PropertyId.UNIQUE_ITEMS, getBoolean(node, PropertyBuilder.PropertyId.UNIQUE_ITEMS));
        args.put(PropertyBuilder.PropertyId.READ_ONLY, getBoolean(node, PropertyBuilder.PropertyId.READ_ONLY));
        args.put(PropertyBuilder.PropertyId.VENDOR_EXTENSIONS, getVendorExtensions(node));
        return args;
    }

    Property propertyFromNode(JsonNode node) {
        final String type = getString(node, PropertyBuilder.PropertyId.TYPE);
        final String title = getString(node, PropertyBuilder.PropertyId.TITLE);
        final String format = getString(node, PropertyBuilder.PropertyId.FORMAT);

        String description = getString(node, PropertyBuilder.PropertyId.DESCRIPTION);

        JsonNode detailNode = node.get("$ref");
        if (detailNode != null) {
            return new RefProperty(detailNode.asText())
                    .description(description)
                    .title(title);
        }

        if (ObjectProperty.isType(type) || node.get("properties") != null) {
            JsonNode example = getDetailNode(node, PropertyBuilder.PropertyId.EXAMPLE);
            detailNode = node.get("additionalProperties");
            if (detailNode != null && detailNode.getNodeType().equals(JsonNodeType.OBJECT)) {
                Property items = propertyFromNode(detailNode);
                if (items != null) {
                    MapProperty mapProperty = new MapProperty(items)
                            .description(description)
                            .title(title);
                    mapProperty.setExample(example);
                    mapProperty.setMinProperties(getInteger(node, PropertyBuilder.PropertyId.MIN_PROPERTIES));
                    mapProperty.setMaxProperties(getInteger(node, PropertyBuilder.PropertyId.MAX_PROPERTIES));
                    mapProperty.setVendorExtensionMap(getVendorExtensions(node));
                    return mapProperty;
                }
            } else {
                detailNode = node.get("properties");
                String detailNodeType = null;
                Map properties = new LinkedHashMap();
                if(detailNode != null){
                    for(Iterator> iter = detailNode.fields(); iter.hasNext();){
                        Map.Entry field = iter.next();
                        Property property = propertyFromNode(field.getValue());
                        if(property != null) {
                            properties.put(field.getKey(), property);
                        }
                        else {
                            if("type".equals(field.getKey()) && field.getValue() != null && "array".equals(field.getValue().asText())) {
                                detailNodeType = "array";
                            }
                            if(("description").equals(field.getKey()) && field.getValue().getNodeType().equals(JsonNodeType.STRING)) {
                                description = field.getValue().asText();
                            }
                        }
                    }
                }

                if("array".equals(detailNodeType)) {
                    ArrayProperty ap = new ArrayProperty()
                            .description(description)
                            .title(title);
                    ap.setExample(example);
                    PropertyBuilder.merge(ap, argsFromNode(detailNode));
                    ap.setDescription(description);

                    if(properties.keySet().size() == 1) {
                        String key = properties.keySet().iterator().next();
                        ap.setItems(properties.get(key));
                    }
                    ap.setVendorExtensionMap(getVendorExtensions(node));
                    return ap;
                }
                ObjectProperty objectProperty = new ObjectProperty(properties)
                        .description(description)
                        .title(title);
                objectProperty.setExample(example);
                objectProperty.setVendorExtensionMap(getVendorExtensions(node));

                List required = getRequired(node, PropertyBuilder.PropertyId.REQUIRED);
                objectProperty.setRequiredProperties(required);

                return objectProperty;
            }
        }
        if (ArrayProperty.isType(type)) {
            detailNode = node.get("items");
            if (detailNode != null) {
                Property subProperty = propertyFromNode(detailNode);
                ArrayProperty arrayProperty = new ArrayProperty()
                        .items(subProperty)
                        .description(description)
                        .title(title);
                arrayProperty.setMinItems(getInteger(node, PropertyBuilder.PropertyId.MIN_ITEMS));
                arrayProperty.setMaxItems(getInteger(node, PropertyBuilder.PropertyId.MAX_ITEMS));
                arrayProperty.setUniqueItems(getBoolean(node, PropertyBuilder.PropertyId.UNIQUE_ITEMS));

                JsonNode example = getDetailNode( node, PropertyBuilder.PropertyId.EXAMPLE);
                arrayProperty.setExample(example);

                arrayProperty.setVendorExtensionMap(getVendorExtensions(node));
                return arrayProperty;
            }
        }


        Map args = argsFromNode(node);
        Property output = PropertyBuilder.build(type, format, args);
        if (output == null) {
            LOGGER.warn("no property from " + type + ", " + format + ", " + args);
            return null;
        }
        output.setDescription(description);

        return output;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy