(that is: "There Is More Than One Way To Do It", aka "Tim Toady")
Now that Jackson is creeping closer to its 1.0 release, package also
contains simple robust functionality to map json data to and from Java
objects. To be precise, Jackson actually has not just one way to do it
but two ways.
Methods are called "Java type mapper" and "JSON type mapper", although
other nicknames can be readily coined. For example: "Poor Man's Objects"
(aka "Everything's a Map with numbers, Strings and booleans") and "DOM
wanna-be" (or "You Know Tree By Nodes It Has").
Java Type Mapper
This mapper is most similar to other Json mappers that everyone (and
their monkey [and monkey's fleas' buddies cousins]) have written. Given
Json content you can get Maps or Lists that contain other Maps, List,
Strings, wrappers (Integer, Long, Boolean) and nulls. And given Maps,
List et al., you can generate Json content. Here's how to use this
functionality:
String jsonContent = "{ \"name\" : \"Jackson\", \"data\" : [ 0, 15 ] }";
JsonFactory jf = new JsonFactory(); // need factory for creating parser to use
Map hash = (Map) new JavaTypeMapper().read(jf.createJsonParser(new StringReader(jsonContent)));
String name = (String) hash.get("name");
List l = (List) hash.get("data");
int maxValue = (Integer) l.get(1);
And to write content back as Json:
StringWriter sw = new StringWriter();
JsonGenerator gen = new jf.createJsonGenerator(sw);
new JavaTypeMapper().writeAny(gen, hash);
Simple enough: values are basic Java data structs and values, and you
modify them using normal List.add(), Map.put() methods; iterate over
elements and so on.
So why do I call it "Poor Man's Objects"? Because most of the time,
Maps, Lists (etc) are used to emulate "real" objects (like beans), with
more dynamic access. In some cases this works well (when accessing data
in a dynamic context, say, from jsp page); in others it just means
losing type-safety without gaining anything. And that is probably the
biggest missing piece: ability to map data to and from beans. That is
something I hope to address in near future (but probably not within core
Jackson project itself).
Json Type Mapper
Whereas the first mapper should be familiar for anyone used to other
Java json processing packages, the other alternative should look
familiar to those who are working with XML using tree models such as
XOM, JDOM, DOM4j, or (unlucky bastards), DOM. This mapper constructs an
in-memory tree, represented as set of Nodes traversable using convenient
path accessors. One obvious benefit here is that one can eliminate
casts: as long as you know type of List entries and Map entry values,
you just use appropriate accessor and get results correctly typed (or,
type cast exception if type didn't match). So, you will do something
like:
JsonNode rootNode = new JsonTypeMapper().read(jf.createJsonParser(new StringReader(jsonContent)));
// for node traversal, can either use getElementValue(int)/getFieldValue(String), or getPath().
// Difference is dealing with missing elements: getPath() allows for safe de-referencing of missing
// values (essentially creating dummy "missing" node that resolves to N/A value)
String name = rootNode.getPath("name").getTextValue(); // or '.getValueAsText()' for extra safety
int maxValue = rootNode.getPath("data").getPath(1).getIntValue();
Looks better? I tend to think so -- while this could be called Poor
Man's XPath, I think it reasonably convenient as is. In addition to data
extraction as shown, tree can be modified, children iterated and so
forth. Beyond explicit traversal using node methods, there are also
future plans for implementing JsonPath
to be able to use more concise notation. Such implementation could be
based on the Json Type Mapper and should be easy to implement.
Which one should I use?
Whichever fits your use case, of course. But what would that be? One way
to think about is whether you prefer path-access (json type mapper), or
Java container traversal (java type mapper). Or more generally: if you
have plenty of Java structs waiting to be thrown around, Java type
mapper may be more convenient way to join things together. Especially so
when you are actually just generating Json content, and not parsing it.
So perhaps it makes most sense to generate Json from java stuff using
Java type mapper; but to extract data from Json content using Json type
mapper.
Anyway: I am using Java Type mapper at work for freezing/thawing state
of a batch processing system (over restarts), but I hope others are
using one or both in more creative ways. Please let me know if you do,
add a comment here or email me (at yahoo.com, cowtowncoder).