MOXy’s @XmlVariableNode – JSON Schema Example
We are in the process of adding the ability to generate a JSON Schema from your domain model to EclipseLink MOXy. To accomplish this we have created a new Variable Node mapping. In this post I will demonstrate the new mapping by mapping a Java model to a JSON Schema.
You can try this out today using a nightly build of EclipseLink 2.6.0:
JSON Schema (input.json/Output)
Below is the “Basic Example” taken from http://json-schema.org/examples.html. Note how the type has many properties, but they don’t appear as a JSON array. Instead they appear as separate JSON objects keyed on the property name.
{
"title": "Example Schema",
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"age": {
"description": "Age in years",
"type": "integer",
"minimum": 0
}
},
"required": ["firstName", "lastName"]
}Java Model
Below is the Java model we will use for this example.
JsonSchema (Properties Stored in a List)
In this Java representation of the JSON Schema we have a class that has a collection of Property objects. Instead of the default representation of the collection (see: Binding to JSON & XML – Handling Collections), we want each Property to be keyed by its name. We can do this using the @XmlVariableNode annotation. With it we specify the field/property from the target object that should be used as the key.
package blog.variablenode.jsonschema;
import java.util.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlVariableNode;
@XmlAccessorType(XmlAccessType.FIELD)
public class JsonSchema {
private String title;
private String type;
@XmlElementWrapper
@XmlVariableNode("name")
public List<Property> properties;
private List<String> required;
}JsonSchema (Properties Stored in a Map)
In this version of the JsonSchema class we have changed the type of properties property from List<Property> property to Map<String, Property>. The annotation remains the same, the difference is that when @XmlVariableNode is used on a Map the variable node name is used as the map key.
package blog.variablenode.jsonschema;
import java.util.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlVariableNode;
@XmlAccessorType(XmlAccessType.FIELD)
public class JsonSchema {
private String title;
private String type;
@XmlElementWrapper
@XmlVariableNode("name")
public Map<String, Property> properties;
private List<String> required;
}Property
To prevent the name field from being marshalled we need to annotate it with @XmlTransient (see JAXB and Unmapped Properties).
package blog.variablenode.jsonschema;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class Property {
@XmlTransient
private String name;
private String description;
private String type;
private Integer minimum;
}Demo Code
Below is some sample code that you can use to prove that everything works.
package blog.variablenode.jsonschema;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jc = JAXBContext.newInstance(new Class[] {JsonSchema.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource json = new StreamSource("src/blog/variablenode/jsonschema/input.json");
JsonSchema jsonSchema = unmarshaller.unmarshal(json, JsonSchema.class).getValue();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(jsonSchema, System.out);
}
}External Metadata
MOXy also offers an external mapping document which allows you to provide metadata for third party objects or apply alternate mappings for your model (see: Mapping Object to Multiple XML Schemas – Weather Example). Below is the mapping document for this example.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="blog.variablenode.jsonschema"
xml-accessor-type="FIELD">
<java-types>
<java-type name="JsonSchema">
<java-attributes>
<xml-variable-node
java-attribute="properties" java-variable-attribute="name">
<xml-element-wrapper/>
</xml-variable-node>
</java-attributes>
</java-type>
<java-type name="Property">
<java-attributes>
<xml-transient java-attribute="name"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>




