JSON-Schema Data Transfer Objects

##### Table of Contents

## 1 - Overview

Juneau supports serializing and parsing of JSON-Schema documents through the use of beans defined in the `org.apache.juneau.dto.jsonschema` package.
These beans are used with the existing {@link org.apache.juneau.json.JsonSerializer} and {@link org.apache.juneau.json.JsonParser} classes to produce and consume JSON-Schema documents.

NOTE: JSON-Schema is currently in draft form. This API may change as the JSON-Schema specification changes.

### 1.1 - JSON-Schema schema definition

The draft JSON-Schema specification that the JSON-Schema beans are modeled after is as follows:

{ "id": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#", "description": "Core schema meta-schema", "definitions": { "schemaArray": { "type": "array", "minItems": 1, "items": { "$ref": "#" } }, "positiveInteger": { "type": "integer", "minimum": 0 }, "positiveIntegerDefault0": { "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] }, "simpleTypes": { "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] }, "stringArray": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true } }, "type": "object", "properties": { "id": { "type": "string", "format": "uri" }, "$schema": { "type": "string", "format": "uri" }, "title": { "type": "string" }, "description": { "type": "string" }, "default": {}, "multipleOf": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "maximum": { "type": "number" }, "exclusiveMaximum": { "type": "boolean", "default": false }, "minimum": { "type": "number" }, "exclusiveMinimum": { "type": "boolean", "default": false }, "maxLength": { "$ref": "#/definitions/positiveInteger" }, "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, "pattern": { "type": "string", "format": "regex" }, "additionalItems": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, "items": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/schemaArray" } ], "default": {} }, "maxItems": { "$ref": "#/definitions/positiveInteger" }, "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "type": "boolean", "default": false }, "maxProperties": { "$ref": "#/definitions/positiveInteger" }, "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, "required": { "$ref": "#/definitions/stringArray" }, "additionalProperties": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "properties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "patternProperties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "dependencies": { "type": "object", "additionalProperties": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/stringArray" } ] } }, "enum": { "type": "array", "minItems": 1, "uniqueItems": true }, "type": { "anyOf": [ { "$ref": "#/definitions/simpleTypes" }, { "type": "array", "items": { "$ref": "#/definitions/simpleTypes" }, "minItems": 1, "uniqueItems": true } ] }, "allOf": { "$ref": "#/definitions/schemaArray" }, "anyOf": { "$ref": "#/definitions/schemaArray" }, "oneOf": { "$ref": "#/definitions/schemaArray" }, "not": { "$ref": "#" } }, "dependencies": { "exclusiveMaximum": [ "maximum" ], "exclusiveMinimum": [ "minimum" ] }, "default": {} }

The bean classes that make up the model are as follows:

- {@link org.apache.juneau.dto.jsonschema.Schema} - Top level schema object.
- {@link org.apache.juneau.dto.jsonschema.SchemaProperty} - A subclass of `Schema` for representing properties.
- {@link org.apache.juneau.dto.jsonschema.SchemaPropertySimpleArray} - A convenience subclass of `SchemaProperty` for representing properties of simple array types.
- {@link org.apache.juneau.dto.jsonschema.SchemaRef} - Represents a URI reference to another schema.
- {@link org.apache.juneau.dto.jsonschema.SchemaArray} - An array of `Schema` objects.
- {@link org.apache.juneau.dto.jsonschema.JsonType} - An enum of possible JSON data types.
- {@link org.apache.juneau.dto.jsonschema.JsonTypeArray} - An array of `JsonType` objects.

### 1.2 - Creating JSON-Schema documents

JSON-Schema documents can be constructed using the Juneau JSON-Schema beans as a document model object. These beans are defined with fluent-style setters to make constructing documents as easy as possible.

The following is an example JSON-Schema document:

{ "title": "Example Schema", "type": "object", "properties": { "firstName": { "type": "string" }, "lastName": { "type": "string" }, "age": { "description": "Age in years", "type": "integer", "minimum": 0 } }, "required": ["firstName", "lastName"] }

This document can be constructing using the following code:

// Create the document object model Schema s = new Schema() .setTitle("Example Schema") .setType(JsonType.OBJECT) .addProperties( new SchemaProperty("firstName", JsonType.STRING), new SchemaProperty("lastName", JsonType.STRING), new SchemaProperty("age", JsonType.INTEGER) .setDescription("Age in years") .setMinimum(0) ) .addRequired("firstName", "lastName"); // Serialize to JSON String json = JsonSerializer.DEFAULT_READABLE.serialize(s);

The following is a more-complex example showing various kinds of constraints.

{ "id": "http://some.site.somewhere/entry-schema#", "$schema": "http://json-schema.org/draft-04/schema#", "description": "schema for an fstab entry", "type": "object", "required": [ "storage" ], "properties": { "storage": { "type": "object", "oneOf": [ { "$ref": "#/definitions/diskDevice" }, { "$ref": "#/definitions/diskUUID" }, { "$ref": "#/definitions/nfs" }, { "$ref": "#/definitions/tmpfs" } ] }, "fstype": { "enum": [ "ext3", "ext4", "btrfs" ] }, "options": { "type": "array", "minItems": 1, "items": { "type": "string" }, "uniqueItems": true }, "readonly": { "type": "boolean" } }, "definitions": { "diskDevice": {}, "diskUUID": {}, "nfs": {}, "tmpfs": {} } }

This document can be constructing using the following code:

Schema s = new Schema() .setId("http://some.site.somewhere/entry-schema#") .setSchemaVersionId("http://json-schema.org/draft-04/schema#") .setDescription("schema for an fstab entry") .setType(JsonType.OBJECT) .addRequired("storage") .addProperties( new SchemaProperty("storage") .setType(JsonType.OBJECT) .addOneOf( new SchemaRef("#/definitions/diskDevice"), new SchemaRef("#/definitions/diskUUID"), new SchemaRef("#/definitions/nsf"), new SchemaRef("#/definitions/tmpfs") ), new SchemaProperty("fstype") .addEnum("ext3", "ext4", "btrfs"), new SchemaPropertySimpleArray("options", JsonType.STRING) .setMinItems(1) .setUniqueItems(true), new SchemaProperty("readonly") .setType(JsonType.BOOLEAN) ) .addDefinition("diskDevice", new Schema() ) .addDefinition("diskUUID", new Schema() ) .addDefinition("nfs", new Schema() ) .addDefinition("tmpfs", new Schema() ); // Serialize to JSON String json = JsonSerializer.DEFAULT_READABLE.serialize(s);

#### 1.2.1 - Serializing to other data types

Since the JSON-Schema DTOs are simple beans, they can be used to serialize to a variety of other language types as well as JSON. This also allows JSON-Schema documents to be easily served up using the Juneau REST API.

The sample web application includes a REST resource that generates a JSON-Schema document. We'll use this resource to show what the JSON-Schema document looks like in other languages.

/** * Sample resource that shows how to serialize JSON-Schema documents. */ @RestResource( path="/jsonSchema", messages="nls/JsonSchemaResource", title="Sample JSON-Schema document", htmldoc=@HtmlDoc( navlinks={ "options: ?method=OPTIONS" } ) ) public class JsonSchemaResource extends RestServletJenaDefault { private Schema schema; // The schema document /** Servlet initialization */ @Override public void init() { try { schema = new Schema() .setId("http://example.com/sample-schema#") .setSchemaVersionUri("http://json-schema.org/draft-04/schema#") .setTitle("Example Schema") .setType(JsonType.OBJECT) .addProperties( new SchemaProperty("firstName", JsonType.STRING), new SchemaProperty("lastName", JsonType.STRING), new SchemaProperty("age", JsonType.INTEGER) .setDescription("Age in years") .setMinimum(0) ) .addRequired("firstName", "lastName"); } catch (Exception e) { throw new RuntimeException(e); } } /** GET request handler */ @RestMethod(name=GET, path="/") public Schema getSchema() throws Exception { return schema; } /** * PUT request handler. * Replaces the schema document with the specified content, and then mirrors it as the response. */ @RestMethod(name=PUT, path="/") public Schema setSchema(@Body Schema schema) throws Exception { this.schema = schema; return this.schema; } /** OPTIONS request handler */ @RestMethod(name=OPTIONS, path="/*") public ResourceOptions doOptions(RestRequest req) { return new ResourceOptions(this, req); } }

When you point your browser to this resource, the default content type is HTML (since that's what the browser asks for by default).

###### HTML

The REST API allows you to specify the `Accept` header as a GET parameter, and the `plainText=true` parameter forces the returned `Content-Type` to be `text/plain`. We'll use this to view the JSON-Schema document in other languages.

###### Normal JSON

###### XML

###### URL-Encoded

###### Abbreviated RDF/XML

###### Turtle

The full list of options for this resource can be accessed by the `options` link on the HTML page.

###### Resource Options

### 1.3 - Parsing JSON-Schema documents

Use the {@link org.apache.juneau.json.JsonParser} to parse JSON-Schema documents into DTOs:

// Use parser to load JSON-Schema document into JSON-Schema DTOs Schema schema = JsonParser.DEFAULT.parse(json, Schema.class);

Schema objects can also be constructed from the other media types using the appropriate parsers.

*** fín ***