JSON Schema for the enterprise
Submodule | Summary |
---|---|
binding | API to bind Java classes to JSON objects whose structure is expressed in the JSON Schema Definition Language. |
generator | Utility to generate Java binding classes from a JSD(x) schema. |
jsonx-maven-plugin | Maven plugin to generate and convert JSONx and JSD(x) bindings. |
jaxrs | JAX-RS @Provider to read and write JSON documents with the JSONx Binding API. |
jsonxml | Utility to convert and validate JSON and JSONx documents. |
sample | Sample applications. |
The JSONx Framework for Java provides a reference implementation processor, validator, and binding API for the JSON Schema Definition Language (JSD), which is a schema language for JSON designed in close resemblance to the XMLSchema❐ specification. The framework also provides a collection of structural and functional patterns intended to help developers work with JSON documents.
This document introduces the JSONx Framework for Java, and presents a directory of links to its constituent parts and related resources.
1 Introduction
1.1 Conventions Used in This Document
2 Use-Cases
2.1 Consumer Driven Contracts
3 JSON Schema Definition Language
3.1 Purpose
3.2 Requirements
3.3 Getting Started
3.4 JSD vs JSDx
3.5 Specification
4 JSONx Binding API
4.1 Purpose
4.2 Requirements
4.3 Getting Started
4.4 Specification
5 JSONx Binding Generator
5.1 Purpose
5.2 Requirements
5.3 Getting Started
5.3.1 Generator
5.3.2 Converter
5.4 Specification
6 JSONx Integration for JAX-RS
6.1 Purpose
6.2 Requirements
6.3 Getting Started
6.4 Specification
7 JSONx Maven Plugin
7.1 Purpose
7.2 Requirements
7.3 Getting Started
7.4 Specification
8 JsonXml
8.1 Purpose
8.2 Requirements
8.3 Getting Started
8.3.1 JSON-to-XML
8.3.2 XML-to-JSON
8.4 Specification
9 Contributing
10 License
The JSONx Framework for Java was created to help developers address common problems and use-cases when working with JSON documents. The JSONx Framework for Java offers structural and functional patterns that systematically reduce errors and pain-points commonly encountered when developing software that interfaces with JSON. The structural patterns are defined in the JSON Schema Definition Language, which is a programming-language-agnostic schema language used to describe constraints and document the meaning, usage and relationships of the constituent parts of JSON documents. The functional patterns are reference implementations of the specification of the schema language, providing utilities that address common use-cases for applications that use JSON in one way or another. Common use-cases include:
- Definition of a normative contract between a producer and consumer of JSON documents.
- Validation of JSON documents conforming to a respective schema document.
- Java class binding API for JSON documents conforming to a respective schema document.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC2119.
The following sections lists common use-cases where JSONx Framework for Java can be used.
The JSONx Framework for Java was created specifically with Consumer Driven Contracts❐ in mind. With the JSON Schema Definition Language (JSD), one can create a Consumer Driven Contract (CDC) with a model that includes the capacity to evolve based on schema versioning. Additionally, the JSD can be used by producers and consumers to validate documents in a communication protocol.
The following example illustrates a simple protocol that uses the CDC approach, and consists of the actors:
- Producer: Representing the provider of the ProductSearch service.
- Consumer1: The first consumer of the ProductSearch service.
- Consumer2: The second consumer of the ProductSearch service.
Consider a simple ProductSearch service, which allows consumer applications to search a product catalogue.
Version v1 of the protocol defines the contract:
-
Request
GET /ProductSearch?name=<name>
-
Response
{ "Version": "v1", "CatalogueID": <number>, "Name": <string>, "Price": <string>, "Manufacturer": <string>, "InStock": <boolean> }
The schema that describes the Response contract is:
{
"jx:ns": "http://www.jsonx.org/schema-0.3.jsd",
"jx:schemaLocation": "http://www.jsonx.org/schema-0.3.jsd http://www.jsonx.org/schema.jsd",
"product": { "jx:type": "object", "abstract": true, "properties": {
"CatalogueID": { "jx:type": "number", "range": "[1,]", "scale": 0, "nullable": false},
"Name": { "jx:type": "string", "pattern": "\\S|\\S.*\\S", "nullable": false },
"Price": { "jx:type": "string", "pattern": "\\$\\d+\\.\\d{2}", "nullable": false },
"Manufacturer": { "jx:type": "string", "pattern": "\\S|\\S.*\\S", "nullable": false },
"InStock": { "jx:type": "boolean", "nullable": false} } },
"product1": { "jx:type": "object", "extends": "product", "properties": {
"Version": { "jx:type": "string", "pattern": "v1", "nullable": false } } }
}
<schema
xmlns="http://www.jsonx.org/schema-0.3.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jsonx.org/schema-0.3.xsd http://www.jsonx.org/schema.xsd">
<object name="product" abstract="true">
<property name="CatalogueID" xsi:type="number" range="[1,]" scale="0" nullable="false"/>
<property name="Name" xsi:type="string" pattern="\S|\S.*\S" nullable="false"/>
<property name="Price" xsi:type="string" pattern="\$\d+\.\d{2}" nullable="false"/>
<property name="Manufacturer" xsi:type="string" pattern="\S|\S.*\S" nullable="false"/>
<property name="InStock" xsi:type="boolean" nullable="false"/>
</object>
<object name="product1" extends="product">
<property name="Version" xsi:type="string" pattern="v1" nullable="false"/>
</object>
</schema>
Note: The Converter utility automatically converts between JSD and JSDx.
All actors -- Producer, Consumer1, and Consumer2 -- agree on the contract, and implement and integrate the protocol into their systems. To assert receipt of contract-compliant documents, all actors use the contract definition to automatically validate received and sent messages.
After many months of running in production, Consumer2 issues a request to the Producer to provide additional information in the response. Specifically, Consumer2 requests for the addition of another field in the JSON response:
{
- "Version": "v1.0",
+ "Version": "v2.0",
"CatalogueID": <number>,
"Name": <string>,
"Price": <string>,
"Manufacturer": <string>,
"InStock": <boolean>,
+ "Description": <string>
}
To satisfy Consumer2's request, the contract is updated to support version v2 of the Response:
{
"jx:ns": "http://www.jsonx.org/schema-0.3.jsd",
"jx:schemaLocation": "http://www.jsonx.org/schema-0.3.jsd http://www.jsonx.org/schema.jsd",
"product": { "jx:type": "object", "abstract": true, "properties": {
"CatalogueID": { "jx:type": "number", "range": "[1,]", "scale": 0, "nullable": false},
"Name": { "jx:type": "string", "pattern": "\\S|\\S.*\\S", "nullable": false },
"Price": { "jx:type": "string", "pattern": "\\$\\d+\\.\\d{2}", "nullable": false },
"Manufacturer": { "jx:type": "string", "pattern": "\\S|\\S.*\\S", "nullable": false },
"InStock": { "jx:type": "boolean", "nullable": false} } },
"product1": { "jx:type": "object", "extends": "product", "properties": {
"Version": { "jx:type": "string", "pattern": "v1", "nullable": false } } }
+ "product2": { "jx:type": "object", "extends": "product", "properties": {
+ "Version": { "jx:type": "string", "pattern": "v2", "nullable": false },
+ "Description": { "jx:type": "string", "pattern": "\\S|\\S.*\\S", "nullable": false } } }
}
<schema
xmlns="http://www.jsonx.org/schema-0.3.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jsonx.org/schema-0.3.xsd http://www.jsonx.org/schema.xsd">
<object name="product" abstract="true">
<property name="CatalogueID" xsi:type="number" range="[1,]" scale="0" nullable="false"/>
<property name="Name" xsi:type="string" pattern="\S|\S.*\S" nullable="false"/>
<property name="Price" xsi:type="string" pattern="\$\d+\.\d{2}" nullable="false"/>
<property name="Manufacturer" xsi:type="string" pattern="\S|\S.*\S" nullable="false"/>
<property name="InStock" xsi:type="boolean" nullable="false"/>
</object>
<object name="product1" extends="product">
<property name="Version" xsi:type="string" pattern="v1" nullable="false"/>
</object>
+ <object name="product2" extends="product">
+ <property name="Version" xsi:type="string" pattern="v2" nullable="false"/>
+ <property name="Description" xsi:type="string" pattern="\S|\S.*\S" nullable="false"/>
+ </object>
</schema>
Note: The Converter utility automatically converts between JSD and JSDx.
With this approach, the v2 evolution of the contract satisfies Customer2. And, since the contract also retains support for v1, integration with Customer1 is unaffected.
For the application code, see Sample: Consumer Driven Contracts.
Describes JSON documents using schema components to constrain and document the meaning, usage and relationships of their constituent parts: value types and their content.
Provide a schema language to describe normative contracts between producer and consumer ends of a protocol exchanging JSON documents.
-
The schema language MUST constrain and document the meaning, usage, constraints and relationships of the constituent parts of a JSON document.
-
The schema language MUST provide meaningful and useful constraint rules for the 5 JSON value types:
boolean
,number
,string
,object
,array
. -
The schema language MUST support schema descriptions for any and all legal JSON documents, as specified by RFC2119.
-
The schema language MUST be free-of and agnostic-to patterns specific to any particular programming language.
-
The schema language MUST be able to describe itself.
The JSON Schema Definition Language can be expressed in 2 forms: JSD (Json Schema Document), and JSDx (JSD in XML semantics).
Create schema.jsd
or schema.jsdx
with the following content:
{
"jx:ns": "http://www.jsonx.org/schema-0.3.jsd",
"jx:schemaLocation": "http://www.jsonx.org/schema-0.3.jsd http://www.jsonx.org/schema.jsd",
"myNumber": { "jx:type": "number", "range": "[-1,1)" },
"myString": { "jx:type": "string", "pattern": "[a-z]+" },
"myObject": {
"jx:type": "object", "properties": {
"myArray": {
"jx:type": "array", "elements": [
{ "jx:type": "boolean" },
{ "jx:type": "reference", "type": "myNumber" },
{ "jx:type": "reference", "type": "myString" },
{ "jx:type": "array", "elements": [
{ "jx:type": "boolean" },
{ "jx:type": "number", "range": "[0,100]", "scale": 0 },
{ "jx:type": "string", "pattern": "[0-9]+" },
{ "jx:type": "any", "types": "myNumber myString" } ]},
{ "jx:type": "reference", "type": "myObject" },
{ "jx:type": "any", "types": "myString myObject" }]
}
}
}
}
<schema
xmlns="http://www.jsonx.org/schema-0.3.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jsonx.org/schema-0.3.xsd http://www.jsonx.org/schema.xsd">
<number name="myNumber" range="[-1,1)"/>
<string name="myString" pattern="[a-z]+"/>
<object name="myObject">
<property name="myArray" xsi:type="array">
<boolean/>
<reference type="myNumber"/>
<reference type="myString"/>
<array>
<boolean/>
<number range="[0,100]" scale="0"/>
<string pattern="[0-9]+"/>
<any types="myNumber myString"/>
</array>
<reference type="myObject"/>
<any types="myString myObject"/>
</property>
</object>
</schema>
Note: You can use the Converter utility to automatically convert between JSD and JSDx.
This example defines a schema with 3 types that express the following structure:
- Type
myNumber
: Anumber
between the range -1 (inclusive) and 1 (exclusive). - Type
myString
: Astring
with the regex patter "[a-z]+". - Type
myObject
: Anobject
that has one property:- "myArray": An
array
that defines a sequence of elements:boolean
myNumber
myString
- An
array
with the following elements:boolean
- An integer
number
between 0 and 100. - A
string
of pattern "[0-9]+" - Either
myNumber
ormyString
.
myObject
- Either
myString
ormyObject
.
- "myArray": An
The JSDx format offers XML validation, and using an XML IDE like oXygen XML Editor❐ offers edit-time XML validation, such as:
When using the JSDx format with the oXygen XML Editor❐, the auto-completion features of the editor will guide you in writing the schema. With the JSDx format, the XML editor will also validate keys and keyrefs to ensure that declared types are referenced correctly.
For a detailed specification of the schema language, see JSON Schema Definition Language.
Provides a way for JSON objects whose structure is expressed in the JSON Schema Definition Language to be validated, parsed and marshaled, to and from Java objects of strongly-typed classes.
Provide a binding API for parsing and marshaling JSON documents to and from strongly-typed Java classes.
-
The binding API MUST be able to model the full scope of normative meaning, usage, constraints and relationships of the constituent parts of a JSON document as specifiable with the schema language.
-
The binding API MUST enforce (via validation) the full scope of normative meaning, usage, constraints and relationships of the constituent parts of a JSON document as specifiable in the schema language.
-
The binding API MUST produce clear and useful error messages when exception of schema document constraints are encountered during validation of JSON documents.
-
The binding API MUST constrain the constituent parts of a schema document to Java type bindings that are as lightweight as necessary to retain the full normative scope of specification of the schema language.
-
The binding API MUST use light coupling, not imposing requirements for exclusionary patterns onto a class model of binding classes.
-
The binding API MUST offer easy patterns for manual description of bindings.
-
The binding API MUST be straightforward, intuitive, and resilient to human error.
The JSONx Binding API uses annotations to bind class definitions to usage, constraints and relationships specifiable in the schema language.
The following illustrates usage of the binding API with an example of an invoice.
1. Create invoice.jsd
or invoice.jsdx
in src/main/resources/
:
{
"jx:ns": "http://www.jsonx.org/schema-0.3.jsd",
"jx:schemaLocation": "http://www.jsonx.org/schema-0.3.jsd http://www.jsonx.org/schema.jsd",
"money": { "jx:type": "number", "range": "[0,]", "scale": 2},
"positiveInteger": { "jx:type": "number", "range": "[1,]", "scale": 0},
"date": { "jx:type": "string", "pattern": "-?\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(02-(0[1-9]|1\\d|2\\d))|((0[469]|11)-(0[1-9]|[12]\\d|30)))" },
"nonEmptyString": { "jx:type": "string", "pattern": "\\S|\\S.*\\S" },
"address": { "jx:type": "object", "properties": {
"name": { "jx:type": "reference", "nullable": false, "type": "nonEmptyString" },
"address": { "jx:type": "reference", "nullable": false, "type": "nonEmptyString" },
"city": { "jx:type": "reference", "nullable": false, "type": "nonEmptyString" },
"postalCode": { "jx:type": "reference", "nullable": false, "type": "nonEmptyString", "use": "optional" },
"country": { "jx:type": "reference", "type": "nonEmptyString" } }
},
"invoice": { "jx:type": "object", "properties": {
"number": { "jx:type": "reference", "type": "positiveInteger" },
"date": { "jx:type": "reference", "type": "date" },
"billingAddress": { "jx:type": "reference", "type": "address" },
"shippingAddress": { "jx:type": "reference", "type": "address" },
"billedItems": { "jx:type": "array", "nullable": false, "elements": [
{ "jx:type": "reference", "type": "item" } ] } }
},
"item": { "jx:type": "object", "properties": {
"description": { "jx:type": "reference", "nullable": false, "type": "nonEmptyString" },
"code": { "jx:type": "reference", "nullable": false, "type": "positiveInteger" },
"quantity": { "jx:type": "reference", "nullable": false, "type": "positiveInteger" },
"price": { "jx:type": "reference", "nullable": false, "type": "money" } }
}
}
<schema
xmlns="http://www.jsonx.org/schema-0.3.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jsonx.org/schema-0.3.xsd http://www.jsonx.org/schema.xsd">
<number name="money" range="[0,]" scale="2"/>
<number name="positiveInteger" range="[1,]" scale="0"/>
<string name="date" pattern="-?\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\d|3[01])|(02-(0[1-9]|1\d|2\d))|((0[469]|11)-(0[1-9]|[12]\d|30)))"/>
<string name="nonEmptyString" pattern="\S|\S.*\S"/>
<object name="address">
<property name="name" xsi:type="reference" type="nonEmptyString" nullable="false"/>
<property name="address" xsi:type="reference" type="nonEmptyString" nullable="false"/>
<property name="city" xsi:type="reference" type="nonEmptyString" nullable="false"/>
<property name="postalCode" xsi:type="reference" type="nonEmptyString" nullable="false" use="optional"/>
<property name="country" xsi:type="reference" type="nonEmptyString"/>
</object>
<object name="invoice">
<property name="number" xsi:type="reference" type="positiveInteger"/>
<property name="date" xsi:type="reference" type="date"/>
<property name="billingAddress" xsi:type="reference" type="address"/>
<property name="shippingAddress" xsi:type="reference" type="address"/>
<property name="billedItems" xsi:type="array" nullable="false">
<reference type="item"/>
</property>
</object>
<object name="item">
<property name="description" xsi:type="reference" type="nonEmptyString" nullable="false"/>
<property name="code" xsi:type="reference" type="positiveInteger" nullable="false"/>
<property name="quantity" xsi:type="reference" type="positiveInteger" nullable="false"/>
<property name="price" xsi:type="reference" type="money" nullable="false"/>
</object>
</schema>
Note: You can use the Converter utility to automatically convert between JSD and JSDx.
2. With the invoice.jsd
or invoice.jsdx
, you can use the jsonx-maven-plugin
to automatically generate the Java class files. In your POM, add:
<plugin>
<groupId>org.jsonx</groupId>
<artifactId>jsonx-maven-plugin</artifactId>
<version>0.3.2</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<destDir>${project.build.directory}/generated-sources/jsonx</destDir>
<prefix>com.example.invoice.</prefix>
<schemas>
<schema>src/main/resources/invoice.jsd</schema> <!-- or invoice.jsdx -->
</schemas>
</configuration>
</execution>
</executions>
</plugin>
3. (Alternatively) Create the Java class files by hand:
Note: Set-ters and get-ters have been replaced with public fields for conciseness.
import org.jsonx.*;
public class Address implements JxObject {
@StringProperty(pattern="\\S|\\S.*\\S", nullable=false)
public String name;
@StringProperty(pattern="\\S|\\S.*\\S", nullable=false)
public String address;
@StringProperty(pattern="\\S|\\S.*\\S", nullable=false)
public String city;
@StringProperty(pattern="\\S|\\S.*\\S", use=Use.OPTIONAL, nullable=false)
public String postalCode;
@StringProperty(pattern="\\S|\\S.*\\S")
public String country;
}
import org.jsonx.*;
public class Item implements JxObject {
@StringProperty(pattern="\\S|\\S.*\\S", nullable=false)
public String description;
@NumberProperty(range="[1,]", scale=0, nullable=false)
public java.math.BigInteger code;
@NumberProperty(range="[1,]", scale=0, nullable=false)
public java.math.BigInteger quantity;
@NumberProperty(range="[1,]", scale=2, nullable=false)
public java.math.BigDecimal price;
}
import org.jsonx.*;
public class Invoice implements JxObject {
@NumberProperty(range="[1,]", scale=0)
public java.math.BigInteger number;
@StringProperty(pattern="-?\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(02-(0[1-9]|1\\d|2\\d))|((0[469]|11)-(0[1-9]|[12]\\d|30)))")
public String date;
@ObjectProperty
public Address billingAddress;
@ObjectProperty
public Address shippingAddress;
@ObjectElement(id=0, type=Item.class)
@ArrayProperty(elementIds={0}, nullable=false)
public java.util.List<Item> billedItems;
}
4. You can use these classes to represent Address
es, Item
s, and Invoice
s.
Address address = new Address();
address.name = "John Doe";
address.address = "111 Wall St.";
address.city = "New York";
address.postalCode = "10043";
address.country = "USA";
Item item = new Item();
item.code = BigInteger.valueOf(123);
item.description = "Pocket Protector";
item.price = new BigDecimal("14.99");
item.quantity = BigInteger.valueOf(5);
Invoice invoice = new Invoice();
invoice.number = BigInteger.valueOf(14738);
invoice.date = "2019-05-13";
invoice.billingAddress = address;
invoice.shippingAddress = address;
invoice.billedItems = Collections.singletonList(item);
5. You can now marshal the Java objects to JSON:
String json = JxEncoder._2.marshal(invoice);
System.out.println(json);
... will produce:
{
"number": 14738,
"date": "2019-05-13",
"billingAddress": {
"name": "John Doe",
"address": "111 Wall St.",
"city": "New York",
"postalCode": "10043",
"country": "USA"
},
"shippingAddress": {
"name": "John Doe",
"address": "111 Wall St.",
"city": "New York",
"postalCode": "10043",
"country": "USA"
},
"billedItems": [{
"description": "Pocket Protector",
"code": 123,
"quantity": 5,
"price": 14.99
}]
}
6. You can also parse the JSON into Java objects:
Invoice invoice2 = JxDecoder.parseObject(Invoice.class, new JsonReader(new StringReader(json)));
assertEquals(invoice, invoice2);
For the application code, see Sample: Invoice.
For a detailed specification of the binding API, see JSONx Binding API.
Consumes a JSD schema, and generates classes that use the JSONx Binding API to achieve binding between JSON documents conforming to a JSD schema, and Java object represetations of these documents.
Provide a binding generator utility for automatic generation of binding classes from a schema document.
-
The binding generator MUST be able to consume a schema document, and produce Java class definitions (
.java
files) that use the binding API. -
The binding generator MUST be able to consume Java class definitions (
.class
files) utilizing the binding API, and produce a schema document. -
The binding generator MUST create Java classes (
.java
files) that encode the full normative scope of the schema document. -
The binding generator MUST represent the constituent parts of a schema document with Java type bindings that are as strongly-typed as possible, but not limiting in any way with regard to the definition of the respective constituent part.
-
The binding generator MUST be able to validate a schema document.
The JSONx Binding Generator provides convenience utilities for generating bindings and converting schema documents. The following illustrates example usage of the Generator
and Converter
executable classes.
The following example generates binding classes (.java
files) in target/generated-sources/jsonx
for the schema document at src/main/resources/example.jsd
, with prefix org.example$
.
java -cp ... org.jsonx.Generator --prefix org.example$ -d target/generated-sources/jsonx src/main/resources/example.jsd
The following example converts the JSD file at src/main/resources/example.jsd
to a JSDx file in target/generated-resources
.
java -cp ... org.jsonx.Converter src/main/resources/example.jsd target/generated-resources/example.jsdx
For a detailed specification of the binding generator, see JSONx Binding Generator.
Implements the MessageBodyReader
and MessageBodyWriter
interfaces in the JAX-RS API to integrate with JAX-RS server runtimes.
Provide JSONx Integration for JAX-RS for parsing and marshaling Java object instances of binding classes in a JAX-RS runtime.
-
The JSONx Integration for JAX-RS MUST support validation of JSON upon the consumption and production of documents in a JAX-RS runtime.
-
The JSONx Integration for JAX-RS MUST support any JAX-RS application that implements the facets relevant to parsing and marshaling of entity object, as defined in the JAX-RS 2.0 Specification.
-
The JSONx Integration for JAX-RS MUST be automatic and free of any configuration that would couple an application to the JSONx Framework for Java.
The JSONx Integration for JAX-RS sub-project provides a Provider
implementing the MessageBodyReader
and MessageBodyWriter
interfaces that can be registered with a JAX-RS runtime.
The following illustrates example usage.
1. Create account.jsd
or account.jsdx
in src/main/resources/
.
{
"jx:ns": "http://www.jsonx.org/schema-0.3.jsd",
"jx:schemaLocation": "http://www.jsonx.org/schema-0.3.jsd http://www.jsonx.org/schema.jsd",
"uuid": { "jx:type": "string", "pattern": "[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}" },
"id": { "jx:type": "object", "abstract": true, "properties": {
"id": { "jx:type": "reference", "nullable": false, "type": "uuid" } } },
"credentials": { "jx:type": "object", "properties": {
"email": { "jx:type": "string", "nullable": false, "pattern": "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}" },
"password": { "jx:type": "string", "nullable": false, "pattern": "[0-9a-f]{64}", "use": "optional" } } },
"account": { "jx:type": "object", "extends": "credentials", "properties": {
"id": { "jx:type": "reference", "nullable": false, "type": "uuid", "use": "optional" },
"firstName": { "jx:type": "string", "nullable": false },
"lastName": { "jx:type": "string", "nullable": false } } }
}
<schema
xmlns="http://www.jsonx.org/schema-0.3.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jsonx.org/schema-0.3.xsd http://www.jsonx.org/schema.xsd">
<string name="uuid" pattern="[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}"/>
<object name="id" abstract="true">
<property name="id" xsi:type="reference" type="uuid" nullable="false"/>
</object>
<object name="credentials">
<property xsi:type="string" name="email" pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}" nullable="false"/>
<property xsi:type="string" name="password" pattern="[0-9a-f]{64}" use="optional" nullable="false"/>
</object>
<object name="account" extends="credentials">
<property name="id" xsi:type="reference" type="uuid" nullable="false" use="optional"/>
<property name="firstName" xsi:type="string" nullable="false"/>
<property name="lastName" xsi:type="string" nullable="false"/>
</object>
</schema>
Note: You can use the Converter utility to automatically convert between JSD and JSDx.
2. Add the org.jsonx:jsonx-maven-plugin
to the POM.
<plugin>
<groupId>org.jsonx</groupId>
<artifactId>jsonx-maven-plugin</artifactId>
<version>0.3.2</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<destDir>${project.build.directory}/generated-sources/jsonx</destDir>
<prefix>com.example.jsonx.</prefix>
<schemas>
<schema>src/main/resources/account.jsonx</schema>
</schemas>
</configuration>
</execution>
</executions>
</plugin>
3. Upon successful execution of the jsonx-maven-plugin
plugin, Java class files will be generated in generated-sources/jsonx
. Add this path to your Build Paths in your IDE to integrate into your project.
The generated classes can be instantiated as any other Java objects. They are strongly typed, and will guide you in proper construction of a JSON message. The following APIs can be used for parsing and marshalling JSONx to and from JSON:
To parse JSON to JSONx Bindings:
String json = "{\"email\":\"john@doe\",\"password\":\"066b91577bc547e21aa329c74d74b0e53e29534d4cc0ad455abba050121a9557\"}";
Credentials credentials = JxDecoder.parseObject(Credentials.class, new JsonReader(new StringReader(json)));
To marshal JSONx Bindings to JSON:
String json2 = JxEncoder.get().marshal(credentials);
assertEquals(json, json2);
4. Next, register the JxObjectProvider
provider in the JAX-RS appilcation singletons, and implement the AccountService
:
public class MyApplication extends javax.ws.rs.core.Application {
@Override
public Set<Object> getSingletons() {
return Collections.singleton(new JxObjectProvider(JxEncoder._2));
}
}
@Path("/account")
@RolesAllowed("registered")
public class AccountService {
@GET
@Produces("application/vnd.example.v1+json")
public Account get(@Context SecurityContext securityContext) {
Account account = new Account();
...
return account;
}
@POST
@Consumes("application/vnd.example.v1+json")
public void post(@Context SecurityContext securityContext, Account account) {
...
}
}
For a detailed specification of JSONx Integration for JAX-RS, see JSONx Integration for JAX-RS.
A Maven plugin for generating JSONx and JSD bindings.
Provide schema validation, schema conversion, and Java binding source generation in a Maven plugin.
-
The JSONx Maven plugin MUST offer utilities for the generation of Java binding sources from a specified schema document.
-
The JSONx Maven plugin MUST offer utilities for validation of schema documents.
-
The JSONx Maven plugin MUST offer utilities for conversion of schema documents from JSD to JSDx, and vice versa.
-
The JSONx Maven plugin MUST present clear and informative errors and warnings that arise during parsing and validation of schema documents and JSON documents with an associated schema.
The JSONx Maven Plugin implements a Maven MOJO that can be used in a pom.xml
. The following illustrates an example usage.
<plugin>
<groupId>org.jsonx</groupId>
<artifactId>jsonx-maven-plugin</artifactId>
<version>0.3.2</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<destDir>${project.build.directory}/generated-sources/jsonx</destDir>
<prefix>com.example.json.</prefix>
<schemas>
<schema>src/main/resources/schema.jsd</schema> <!-- or schema.jsdx -->
</schemas>
</configuration>
</execution>
</executions>
</plugin>
For a detailed specification of the Maven plugin, see JSONx Maven Plugin.
Offers facilities for converting JSON documents to XML, and vice-versa.
Provide an encoding of JSON documents in an analogous form that uses XML semantics, referred to as JsonXml documents.
-
The JsonXml documents MUST be able to represent any and all legal JSON documents, as specified by RFC2119.
-
The JsonXml documents MUST be translatable to JSON documents, and vice versa, preserving all normative and non-normative features of the original document.
-
The JsonXml documents MUST provide meaningful and useful validation features via XSD validation.
The JsonXml sub-project provides convenience utilities for converting JSON documents to XML. The following illustrates example usage of the JxConverter
class.
String xml = JxConverter.jsonToXml(new JsonReader(new FileReader("example.json")));
String json = JxConverter.xmlToJson(new FileInputStream("example.xml"));
For a detailed specification of JsonXml, see JsonXml.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.
This project is licensed under the MIT License - see the LICENSE.txt file for details.