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

com.github.bjansen.ssv.SwaggerValidator Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
package com.github.bjansen.ssv;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.fge.jsonschema.SchemaVersion;
import com.github.fge.jsonschema.cfg.ValidationConfiguration;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.ref.JsonRef;
import com.github.fge.jsonschema.core.report.LogLevel;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.format.FormatAttribute;
import com.github.fge.jsonschema.format.draftv3.DateAttribute;
import com.github.fge.jsonschema.library.DraftV4Library;
import com.github.fge.jsonschema.library.Library;
import com.github.fge.jsonschema.library.LibraryBuilder;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import com.github.fge.msgsimple.load.MessageBundles;
import com.google.common.collect.ImmutableMap;
import io.swagger.util.Json;
import io.swagger.util.Yaml;
import org.apache.commons.lang3.tuple.Pair;

import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;

public class SwaggerValidator {

    private static final Map, JsonSchema> SCHEMA_CACHE = new HashMap<>();

    private static final Map TRANSFORMATIONS =
        ImmutableMap.builder()
            .put("x-additionalItems", "additionalItems")
            .put("x-contains", "contains")
            .put("x-patternProperties", "patternProperties")
            .put("x-dependencies", "dependencies")
            .put("x-propertyNames", "propertyNames")
            .put("x-if", "if")
            .put("x-then", "then")
            .put("x-else", "else")
            .put("x-allOf", "allOf")
            .put("x-anyOf", "anyOf")
            .put("x-oneOf", "oneOf")
            .put("x-not", "not")
            .build();

    private final JsonNode schemaObject;

    private SwaggerValidator(JsonNode schemaObject) {
        this.schemaObject = transform(schemaObject);
    }

    /**
     * Creates a Swagger schema validator based on the given JSON-based Swagger spec.
     *
     * @param swaggerSpec the Swagger spec (in JSON format)
     * @return a validator for that spec
     * @throws IOException if the Swagger spec is not a valid JSON object
     */
    public static SwaggerValidator forJsonSchema(Reader swaggerSpec) throws IOException {
        return new SwaggerValidator(Json.mapper().readTree(swaggerSpec));
    }

    /**
     * Creates a Swagger schema validator based on the given YAML-based Swagger spec.
     *
     * @param swaggerSpec the Swagger spec (in YAML format)
     * @return a validator for that spec
     * @throws IOException if the Swagger spec is not a valid YAML object
     */
    public static SwaggerValidator forYamlSchema(Reader swaggerSpec) throws IOException {
        return new SwaggerValidator(Yaml.mapper().readTree(swaggerSpec));
    }

    /**
     * Validates the given {@code jsonPayload} against the definition located at {@code definitionPointer}.
     *
     * @param jsonPayload       the JSON payload to validate
     * @param definitionPointer the path to the schema object the payload should be validated against,
     *                          for example {@code /definitions/User}
     * @return a validation report
     * @throws ProcessingException in case a processing error occurred during validation
     * @throws IOException         if the payload is not a valid JSON object
     */
    public ProcessingReport validate(String jsonPayload, String definitionPointer) throws ProcessingException, IOException {
        JsonNode jsonNode = Json.mapper().readTree(jsonPayload);

        if (jsonNode == null) {
            throw new IOException("The JSON payload could not be parsed correctly");
        }

        return getSchema(definitionPointer).validate(jsonNode);
    }

    /**
     * Applies all the {@link #TRANSFORMATIONS} on each property contained in each definition
     * of the given schema.
     *
     * @param schema the Swagger schema containing transformations to apply (x-oneOf, etc).
     * @return the patched schema
     */
    private JsonNode transform(JsonNode schema) {
        if (!(schema instanceof ObjectNode)) {
            return schema;
        }

        ObjectNode schemaNode = (ObjectNode) schema;

        if (schemaNode.has("definitions")) {
            for (JsonNode definition : schemaNode.get("definitions")) {
                TRANSFORMATIONS.forEach((from, to) -> {
                    if (definition instanceof ObjectNode && definition.has(from)) {
                        ((ObjectNode) definition).set(to, definition.get(from));
                        ((ObjectNode) definition).remove(from);
                    }
                });
            }
        }

        return schema;
    }

    private JsonSchema getSchema(String definitionPointer) throws ProcessingException {
        Pair key = Pair.of(schemaObject, definitionPointer);

        JsonSchemaFactory jsonSchemaFactory = SwaggerV20Library.schemaFactory(LogLevel.INFO, LogLevel.FATAL);

        if (!SCHEMA_CACHE.containsKey(key)) {
            SCHEMA_CACHE.put(key, jsonSchemaFactory.getJsonSchema(schemaObject, definitionPointer));
        }

        return SCHEMA_CACHE.get(key);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy