Skip to content

Getting Started

Christoph Beck edited this page Sep 24, 2012 · 11 revisions

StAXON lets you read and write JSON using the Java Streaming API for XML (javax.xml.stream).

More specifically, StAXON provides implementations of the

  • StAX Cursor API (XMLStreamReader and XMLStreamWriter)
  • StAX Event API (XMLEventReader and XMLEventWriter)
  • StAX Factory API (XMLInputFactory and XMLOutputFactory)

for JSON.

The XML-to-JSON Mapping Convention used by StAXON is similar to the Badgerfish convention but attempts to avoid needless text-only JSON objects to generate a more compact JSON.

Setup

Add the following dependency to your Maven POM file:

<dependency>
	<groupId>de.odysseus.staxon</groupId>
	<artifactId>staxon</artifactId>
	<version>...</version>
</dependency>

or get the latest staxon-<version>.jar from the Downloads page and add it to your classpath.

Core API

  • JsonXMLInputFactory extends XMLInputFactory and is used to create JSON stream/event readers
  • JsonXMLOutputFactory extends XMLOutputFactory and is used to create JSON stream/event writers
  • JsonXMLConfig provides a shared configuration interface for JsonXMLInputFactory and JsonXMLOutputFactory
  • JsonXMLConfigBuilder provides a fluent API to build JsonXMLConfig configuration instances

If you know StAX, you'll notice that there's little new: just obtain a reader or writer from StAXON and you're ready to go.

Writing JSON

Create a JSON-based writer:

XMLOutputFactory factory = new JsonXMLOutputFactory();
XMLStreamWriter writer = factory.createXMLStreamWriter(System.out);

Write your document:

writer.writeStartDocument();
writer.writeStartElement("customer");
writer.writeStartElement("name");
writer.writeCharacters("John Doe");
writer.writeEndElement();
writer.writeStartElement("phone");
writer.writeCharacters("555-1111");
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndDocument();
writer.close();

With an XML-based writer, this would have produced something like

<customer><name>John Doe</name><phone>555-1111</phone></customer>

However, with our JSON-based writer, the output is

{"customer":{"name":"John Doe","phone":"555-1111"}}

Reading JSON

Create a JSON-based reader:

StringReader json = new StringReader("{\"customer\":{\"name\":\"John Doe\",\"phone\":\"555-1111\"}}");

XMLInputFactory factory = new JsonXMLInputFactory();
XMLStreamReader reader = factory.createXMLStreamReader(json);

Read your document:

assert reader.getEventType() == XMLStreamConstants.START_DOCUMENT;
reader.nextTag(); 
assert reader.isStartElement() && "customer".equals(reader.getLocalName());
reader.next();
assert reader.isStartElement() && "name".equals(reader.getLocalName());
reader.next();
assert reader.hasText() && "John Doe".equals(reader.getText());
reader.nextTag();
assert reader.isEndElement();
reader.next();
assert reader.isStartElement() && "phone".equals(reader.getLocalName());
reader.next();
assert reader.hasText() && "555-111".equals(reader.getText());
reader.nextTag();
assert reader.isEndElement();
reader.next();
assert reader.isEndElement();
reader.next();
assert reader.getEventType() == XMLStreamConstants.END_DOCUMENT;
reader.close();

Factory Configuration

The JsonXMLInputFactory and JsonXMLOutputFactory classes can be configured via the standard setProperty(String, Object) API. The factory classes define several constants for properties they support:

JsonXMLInputFactory inputFactory = new JsonXMLInputFactory();
inputFactory.setProperty(JsonXMLInputFactory.PROP_VIRTUAL_ROOT, "customer");
...
JsonXMLOutputFactory outputFactory = new JsonXMLOutputFactory(config);
outputFactory.setProperty(JsonXMLOutputFactory.PROP_VIRTUAL_ROOT, "customer");
outputFactory.setProperty(JsonXMLOutputFactory.PROP_PRETTY_PRINT, true);
...

Anyway, the JsonXMLConfig interface provides a convenient way to hold the configuration of both - input and output - factories:

JsonXMLConfig config = new JsonXMLConfigBuilder().
	virtualRoot("customer").
	prettyPrint(true).
	build();
XMLInputFactory inputFactory = new JsonXMLInputFactory(config);
...
XMLOutputFactory outputFactory = new JsonXMLOutputFactory(config);
...

Virtual Roots

Set the virtualRoot configuration property to omit the root element from the JSON representation, e.g.

{
  "name" : "John Doe",
  "phone" : "555-1111"
}

Triggering Arrays

You can trigger arrays in several ways:

  • Write a <?xml-multiple?> processing instruction to start an array
  • Use XMLMultipleStreamWriter or XMLMultipleEventWriter and pass it your array paths
  • Let multiple elements be detected automatically using the autoArray configuration property

See Mastering Arrays for details.

Using JAXB

Consider a JAXB-annotated Customer class:

@JsonXML(virtualRoot = true, prettyPrint = true, multiplePaths = "phone")
@XmlRootElement
public class Customer {
	public String name;
	public List<String> phone;
}

The @JsonXML annotation is used to configure the mapping details. In the above example, the customer root element is stripped from the JSON representation, phone elements are wrapped into an array and JSON output is nicely formatted, e.g.

{
  "name" : "John Doe",
  "phone" : [ "555-1111" ]
}

Now, the JsonXMLMapper class enables for dead-simple mapping to and from JSON:

/*
 * Create mapper instance.
 */
JsonXMLMapper<Customer> mapper = new JsonXMLMapper<Customer>(Customer.class);

/*
 * Read customer.
 */
InputStream input = getClass().getResourceAsStream("input.json");
Customer customer = mapper.readObject(input);
input.close();

/*
 * Write back to console
 */
mapper.writeObject(System.out, customer);

Please refer to Using JAXB for further documentation and a more complete example.

Clone this wiki locally