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!