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

org.everit.json.schema.Schema Maven / Gradle / Ivy

Go to download

Implementation of the JSON Schema Core Draft v4 specification built with the org.json API

There is a newer version: 1.14.4
Show newest version
package org.everit.json.schema;

import static java.util.Collections.unmodifiableMap;

import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.everit.json.schema.internal.JSONPrinter;
import org.json.JSONWriter;

/**
 * Superclass of all other schema validator classes of this package.
 */
public abstract class Schema {

    /**
     * Abstract builder class for the builder classes of {@code Schema} subclasses. This builder is
     * used to load the generic properties of all types of schemas like {@code title} or
     * {@code description}.
     *
     * @param 
     *         the type of the schema being built by the builder subclass.
     */
    public abstract static class Builder {

        private String title;

        private String description;

        private String id;

        private SchemaLocation schemaLocation;

        private Object defaultValue;

        private Boolean nullable = null;

        private Boolean readOnly = null;

        private Boolean writeOnly = null;

        public Map unprocessedProperties = new HashMap<>(0);

        public Builder title(String title) {
            this.title = title;
            return this;
        }

        public Builder description(String description) {
            this.description = description;
            return this;
        }

        public Builder id(String id) {
            this.id = id;
            return this;
        }

        /**
         * @deprecated Use {@link #schemaLocation(SchemaLocation)} instead.
         */
        @Deprecated
        public Builder schemaLocation(String schemaLocation) {
            return schemaLocation(SchemaLocation.parseURI(schemaLocation));
        }

        public Builder schemaLocation(SchemaLocation location) {
            this.schemaLocation = location;
            return this;
        }

        public Builder defaultValue(Object defaultValue) {
            this.defaultValue = defaultValue;
            return this;
        }

        public Builder nullable(Boolean nullable) {
            this.nullable = nullable;
            return this;
        }

        public Builder readOnly(Boolean readOnly) {
            this.readOnly = readOnly;
            return this;
        }

        public Builder writeOnly(Boolean writeOnly) {
            this.writeOnly = writeOnly;
            return this;
        }

        public Builder unprocessedProperties(Map unprocessedProperties) {
            this.unprocessedProperties = unprocessedProperties;
            return this;
        }

        public abstract S build();

    }

    private final String title;

    private final String description;

    private final String id;

    @Deprecated
    protected final String schemaLocation;

    private final SchemaLocation location;

    private final Object defaultValue;

    private final Boolean nullable;

    private final Boolean readOnly;

    private final Boolean writeOnly;

    private final Map unprocessedProperties;

    /**
     * Constructor.
     *
     * @param builder
     *         the builder containing the optional title, description and id attributes of the schema
     */
    protected Schema(Builder builder) {
        this.title = builder.title;
        this.description = builder.description;
        this.id = builder.id;
        this.schemaLocation = builder.schemaLocation == null ? null : builder.schemaLocation.toString();
        this.location = builder.schemaLocation;
        this.defaultValue = builder.defaultValue;
        this.nullable = builder.nullable;
        this.readOnly = builder.readOnly;
        this.writeOnly = builder.writeOnly;
        this.unprocessedProperties = new HashMap<>(builder.unprocessedProperties);
    }

    /**
     * Performs the schema validation.
     *
     * @param subject
     *         the object to be validated
     * @throws ValidationException
     *         if the {@code subject} is invalid against this schema.
     */
    public void validate(Object subject) {
        Validator.builder().build().performValidation(this, subject);
    }

    /**
     * Determines if this {@code Schema} instance defines any restrictions for the object property
     * denoted by {@code field}. The {@code field} should be a JSON pointer, denoting the property to
     * be queried.
     * 

* For example the field {@code "#/rectangle/a"} is defined by the following schema: *

*
     * 
     * objectWithSchemaRectangleDep" : {
     *   "type" : "object",
     *   "dependencies" : {
     *       "d" : {
     *           "type" : "object",
     *           "properties" : {
     *               "rectangle" : {"$ref" : "#/definitions/Rectangle" }
     *           }
     *       }
     *   },
     *   "definitions" : {
     *       "size" : {
     *           "type" : "number",
     *           "minimum" : 0
     *       },
     *       "Rectangle" : {
     *           "type" : "object",
     *           "properties" : {
     *               "a" : {"$ref" : "#/definitions/size"},
     *               "b" : {"$ref" : "#/definitions/size"}
     *           }
     *       }
     *    }
     * }
     * 
     * 
* The default implementation of this method always returns false. * * @param field * should be a JSON pointer in its string representation. * @return {@code true} if the propertty denoted by {@code field} is defined by this schema * instance */ public boolean definesProperty(String field) { return false; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o instanceof Schema) { Schema schema = (Schema) o; return schema.canEqual(this) && Objects.equals(title, schema.title) && Objects.equals(defaultValue, schema.defaultValue) && Objects.equals(description, schema.description) && Objects.equals(id, schema.id) && Objects.equals(nullable, schema.nullable) && Objects.equals(readOnly, schema.readOnly) && Objects.equals(writeOnly, schema.writeOnly) && Objects.equals(unprocessedProperties, schema.unprocessedProperties); } else { return false; } } @Override public int hashCode() { return Objects.hash(title, description, id, defaultValue, nullable, readOnly, writeOnly, unprocessedProperties); } public String getTitle() { return title; } public String getDescription() { return description; } public String getId() { return id; } public String getSchemaLocation() { return schemaLocation; } public SchemaLocation getLocation() { return location; } public Object getDefaultValue() { return this.defaultValue; } public boolean hasDefaultValue() { return this.defaultValue != null; } public Boolean isNullable() { return nullable; } public Boolean isReadOnly() { return readOnly; } public Boolean isWriteOnly() { return writeOnly; } /** * Returns the properties of the original schema JSON which aren't keywords of json schema * (therefore they weren't recognized during schema loading). */ public Map getUnprocessedProperties() { return unmodifiableMap(unprocessedProperties); } /** * Describes the instance as a JSONObject to {@code writer}. *

* First it adds the {@code "title} , {@code "description"} and {@code "id"} properties then calls * {@link #describePropertiesTo(JSONPrinter)}, which will add the subclass-specific properties. *

* It is used by {@link #toString()} to serialize the schema instance into its JSON representation. * * @param writer * it will receive the schema description */ public void describeTo(JSONPrinter writer) { accept(new ToStringVisitor(writer)); } /** * Subclasses are supposed to override this method to describe the subclass-specific attributes. * This method is called by {@link #describeTo(JSONPrinter)} after adding the generic properties if * they are present ({@code id}, {@code title} and {@code description}). As a side effect, * overriding subclasses don't have to open and close the object with {@link JSONWriter#object()} * and {@link JSONWriter#endObject()}. * * @param writer * it will receive the schema description */ void describePropertiesTo(JSONPrinter writer) { } abstract void accept(Visitor visitor); @Override public String toString() { StringWriter w = new StringWriter(); JSONPrinter writer = new JSONPrinter(w); new ToStringVisitor(writer).visit(this); return w.getBuffer().toString(); } @Deprecated protected ValidationException failure(String message, String keyword) { return new ValidationException(this, message, keyword, schemaLocation.toString()); } @Deprecated protected ValidationException failure(Class expectedType, Object actualValue) { return new ValidationException(this, expectedType, actualValue, "type", schemaLocation.toString()); } /** * Since we add state in subclasses, but want those subclasses to be non final, this allows us to * have equals methods that satisfy the equals contract. *

* http://www.artima.com/lejava/articles/equality.html * * @param other * the subject of comparison * @return {@code true } if {@code this} can be equal to {@code other} */ protected boolean canEqual(Object other) { return (other instanceof Schema); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy