Thursday, July 10, 2008

Jackson with some Objectivity: TIMTOWTDI

(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, cowtowncoder).

blog comments powered by Disqus

Sponsored By

Related Blogs

(by Author (topics))

Powered By

About me

  • I am known as Cowtowncoder
  • Contact me
Check my profile to learn more.