Skip to content

Round trip with json io

John DeRegnaucourt edited this page Sep 7, 2016 · 6 revisions

json-io is commonly used to send Java Data Transfer Objects (DTO) to browser or mobile clients. The JsonWriter class adeptly converts the Java object graph to a JSON string.

But, what else do you need to get the JSON to the browser, and how to handle the JSON that is sent from the browser (or mobile) client?

JsonCommandServlet

On the receiving end, that is JsonCommandServlet. This servlet is similar to Spring MVC, however, it is much easier to use. It supports a JSON return type as well as streaming for the response.

This servlet receives REST requests in the form of POST like this:

http://mywebsite/context/controller/method < http headers > CR LF CR LF [command arguments]

or a an HTTP GET with a URL like this: http://mywebsite/context/controller/method?json=["hello, world"]

The JsonCommandServlet fetches the Spring bean named 'controller', reflectively finds 'method', converts the command arguments to Java from JSON, and then calls the method on the controller. When the method returns, the servlet packages up the method's return value into JSON, along with a return message structure to put it in (includes status info), and writes the HTTP response.

A method can be marked with an annotation to indicate that the method writes its own response, in which case the JsonCommandServlet will not write the HTTP response. In this case, the method could, for example, stream back a video, graph, or PDF file.

The method being called has access to the HttpServletRequest and HttpServletResponse objects. Effectively, any controller method can now be used as (and thought of) as a servlet.

jsonUtil.js (packaged in resource folder with json-io)

This Javascript file includes a utility method 'call' that allows you to easily make an Ajax / XHR request to a JsonCommandServlet:

call("controllerName.methodName", [arguments]);

This will cause the browser to make a REST request to the server, invoking the controller's method with the appropriate arguments. By default, it is a synchronous request. There is an additional argument, which is a Javascript object, that allows you to indicate that the call should be made asynchronously, and it allows you to supply a call back method that will be called when the asynchronous method returns.

When JSON data arrives from the server, there is the chance that the data structure sent from the server includes 'cycles' in it. For example, an object A points to object B, which in turn points to object C, which points back to object A. A->B->C->A. The JsonWriter / JsonReader handle this perfectly fine, by marking referenced objects in the JSON output with an {"@id":234,...}, and then references to this object are marked with {"@ref":234}.

This ID/REF technique is borrowed from the XML standard way for supporting cycles in XML documents. Any data structure that is a 'graph' can have cycles in it.

When the JSON graph returned from the server is read in by call(), the call() method unpacks these @ref objects and replaces them with the object that was pointed to, creating the proper, original graph. Furthermore, JsonWriter places @keys / @items entries in the JSON so that Java Maps that do not have String keys can be supported. The call() method reshapes these into Javascript Maps and eliminates the @items and @keys.

Finally, before Javascript data (JSON) is sent inbound to the server, any cycles in the Javascript graph are converted to having @id/@ref fields so that the proper object graph can be sent to the server.