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>