-
Notifications
You must be signed in to change notification settings - Fork 47
Getting Started
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
andXMLStreamWriter
) - StAX Event API (
XMLEventReader
andXMLEventWriter
) - StAX Factory API (
XMLInputFactory
andXMLOutputFactory
)
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.
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.
-
JsonXMLInputFactory
extendsXMLInputFactory
and is used to create JSON stream/event readers -
JsonXMLOutputFactory
extendsXMLOutputFactory
and is used to create JSON stream/event writers -
JsonXMLConfig
provides a shared configuration interface forJsonXMLInputFactory
andJsonXMLOutputFactory
-
JsonXMLConfigBuilder
provides a fluent API to buildJsonXMLConfig
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.
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"}}
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();
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);
...
Set the virtualRoot
configuration property to omit the root element from the
JSON representation, e.g.
{
"name" : "John Doe",
"phone" : "555-1111"
}
You can trigger arrays in several ways:
- Write a
<?xml-multiple?>
processing instruction to start an array - Use
XMLMultipleStreamWriter
orXMLMultipleEventWriter
and pass it your array paths - Let multiple elements be detected automatically using the
autoArray
configuration property
See Mastering Arrays for details.
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.