Search code examples
javajsongwtgxtjsni

GWT JSONObject to overlay types (or using JSONObject in shared)


I fill an JSONArray (org.JSON) on my GWT server side, then want to use the object on the client side. When I use a JSONObject (or Array) in my shared package, I get the exception that there was no source found (while it works on the server). Thus, I presume it cannot be used client side, or shared (could not confirm that despite googling).

Since shared would not use JSONObject, I presumed JSNI would work in shared. I have read into GWT overlay types on google developer and here on stackoverflow, and have made one in my shared package. However, since it is JSNI, it is not usable on the server. Therefore, I try to pass the JSONObject.toString() to my shared class, then use it as parameter for calling the following JSNI method:

public native UserOverlay getUser(String jsonObj) /*-{
    return jsonObj;
}-*/;

the call:

UserOverlay user = getUser(jsonobj);

However, this gives an UnsatisfiedLinkError at the location of the call, which as far as I know means that the JSNI method was not found, meaning that the shared package does NOT work with JSNI.

Conclusion

I need a method to use my JSON data on both Client, shared and server. If that method differs, then I need a way to convert one method to the other. I have seen threads that handle converting from overlay types to JSONObject, but not the other way around.


Solution

  • If you're referring to Crockford's JSON implementation for Java, the reason it can't be used on the client code is that it needs to be emulated first. For your purposes, you'd wanna use a different approach;

    Have the server returning a JSON text response (over HTTP, naturally), request it via XHR on the client, and than use the response in its raw form — as JSON is a subset of JavaScript's literal object notation, it can be used transparently within JavaScript code.

    To implement this approach in GWT, create a servlet that returns the JSON as text (outputs it to the response's writer). This servlet can than be called from the client using RequestBuilder (which wraps XHR), and overlay types can be used to convert each JSON response to Java managed objects according to its contract.

    The Google Developer documentation offers a tutorial on Retrieving JSON, discussing just that. I'll encompass the highlights and some snippets, just for the sake of completeness:

    1. Create a servlet serving JSON

      Don't forget to configure the webapp's deployment descriptor (web.xml) accordingly.

      public class JsonDataServlet extends HttpServlet {
      
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                  throws ServletException, IOException {
      
              PrintWriter out = resp.getWriter();
              out.println('{');
              // fill with JSON construct
              out.println('}');
              out.flush();
          }
      
      }
      
    2. Construct the overlay types according to the response's interface

    3. Create client side utilities to convert the JSON response to a concrete JavaScriptObject

      The tutorial suggests the use of eval() inside a JSNI method, but I prefer to utilize JSONParser.parseStrict() as it will first try and call JavaScript's JSON.parse() on supporting browsers.

      public static UserOverlay asUserOverlay(String json) {
          JSONValue jsonVal = JSONParser.parseStrict(json);
          JSONObject jsonObj = jsonVal.isObject();
          UserOverlay userOverlay = (UserOverlay) jsonObj.getJavaScriptObject();
      }
      

      Note: If you're gonna use the eval() implementation anyway, the json argument needs to be wrapped in parentheses, i.e. eval('(' + json + ')').

    4. Call the servlet

      RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, GWT.getModuleBaseURL() + "path/to/servlet");
      rb.setCallback(new RequestCallback() {
      
          public void onError(Request request, Throwable exception) {
              // do something
          }
      
          public void onResponseReceived(Request request, Response response) {
              if (200 == response.getStatusCode()) {
                  UserOverlay userOverlay = asUserOverlay(response.getText());
                  // continue handling
              }
          }
      });
      rb.send();
      

    References on the Google Web Toolkit documentation