Tuesday, March 03, 2009

Saving Software Developers from Franken-JSON

1. The Setup

When it comes to using JSON for communication, developers often get bait-and-switched by existing frameworks, most of which are designed to use xml as the underlying data interchange format. Spiel usually goes along these lines:

  • Want to use JSON?
  • We can help with that!
  • Just need to use a little thing called convention
  • which allows us to use our existing system as is
  • and things will work just fine
  • don't you worry little coder

Well, except that the "little thing" turns out to be this ugly contraption that mangles clean Json into something that is technically still Json content, but just barely so: in reality it's just a bit of spit and polish to mask underlying xml structure. Sort of like those human masks on lizards on that ancient TV show ("V"). And such systems likewise require similar bastardization as input.

For one example of such convention, consider Badgerfish (which is not the only choice; there are other variants such as "mapped").
Resulting Json content is generally along the lines of "only-mother-could-love" ugliness: for example let's consider how a simple Bean would get transformed to "JSON" using this convention.
Given a bean like:

class Person {
int getAge();
String getName();
}

we would get xml like:

<person>
<age>37</age>
<name>Joe Blow</name>
</person>

which would be ok as xml, but would then be mapped to "Json" that looks something like:

{
"person" : {
"age" : {
"$" : "37"
},
"name" : {
"$" : "Joe Blow"
}
}
}

Yikes!

Or, with "mapped" variant, xml could translate to this:

{
"person" : {
"age" : 37,
"name" : "Joe Blow"
}
}

(if you are lucky -- number may or may not look like one; and String that looks too much like a number may become one... after all, XML content usually has no such type information)

instead of what you might expect:

{
 "age" : 37,
"name" : "Joe Blow"
}

Like it? Me neither. And it gets even worse if you plan to use things like Lists, and some combinations are just illegal (Lists of Lists).

2. Why oh why?

Now: there are legitimate reasons to use such mapping conventions: sometimes one has to do convert things into other uglier things for interoperability reasons. Legacy systems may be practically unmodifiable, and require certain kinds of butt ugly inputs. There are also plenty many XML-based systems, frameworks and protocols in existence.
So it is natural to consider easy ways to make use of this existing infrastructure. And finally, most JSON tools up until fairly recently seem to be have been made by Santa's elves, and professional-grade tools are somewhat of a recent development.

But the fundamental problem is this: if you need and/or want to use XML, use it. And if you do use XML, what purpose would JSON serve in the mix? It's like connecting a Porsche engine to a Jugo transmission system, all enclosed in a Ford Pinto chassis. Or, brains of mr. Ab Normal within poor old Frankenstein's skull.
And even within Javascript execution environment, DOM-based xml trees have been available almost since dawn of the Interweb -- you can already use XML easily. So to have some actual benefits, JSON should be accessed natively, au naturel. Not as a round peg slammed through the square hole.

3. Solution

But why all these ugly workarounds? Perhaps framework builders do not see much need for JSON, and just want to be buzzword compliant? Or perhaps they have been turned off by earlier crop of toy JSON tools.
Whatever the underlying reason is, most seem to just offer the backhanded convention-ridden route.

But here is some good news. Jackson project can help JSON-craving developers; now with a Content conversion provider that is designed to work with any compliant JAX-RS implementation: JacksonJsonProvider is the thing you need to hook up to your JAX-RS implementation (tested with Jersey, as well as RESTEasy). You can download the jar here (look for "jax-rs" jar; uses core and mapper jars).

So what is this mysterious provider? It is the thing that JAX-RS needs to know how to convert from Json to POJOs and back. And as long as you hook this up as a resource you only need to indicate input and output as being Json (with @Consumes and @Produces resource annotations, or by client provided MIME headers that indicate the same) and it will all actually work out, and quite as you would expect it to.

The only remaining detail is that of hooking things up. One way is to write a simple servlet: here's one way to do that:

    
import java.util.*;
import javax.ws.rs.core.*;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider; public final class RestApplication extends Application {
// Best to register as a singleton to allow reuse of ObjectMapper: public Set<Object> getSingletons() { HashSet<Object> singletons = new HashSet<Object>(); singletons.add(new JacksonJsonProvider()); return singletons; } }

For production servlet, you would also want to register actual resources; but just to get the provider hooked up this should be enough.

4. Disclaimer

The provider class is part of just released version of Jackson 0.9.9. It has been tested only lightly, so there may be rough edges.

Code responsibly!

blog comments powered by Disqus

Sponsored By


Related Blogs

(by Author (topics))

Powered By

About me

  • I am known as Cowtowncoder
  • Contact me at@yahoo.com
Check my profile to learn more.