Sunday, July 13, 2014

How to get JSON response from JSF?

Many JavaScript widgets expect data and options in JSON format. Nowadays, it is really easy to choose a cool widget and wrap it in a composite component. But the first question is how to send an AJAX request and to recieve a response in a proper JSON format. This question is often raised by JSF users. All what you need is a XHTML facelet like this one
<f:view encoding="UTF-8" contentType="text/html"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core">
  <h:outputText value="#{stationView.getClosestStations(param.longitude, param.latitude)}" escape="false"/>
</f:view>
Please consider the contentType="text/html" (application/json will not work here) and escape="false" in the h:outputText. The method getClosestStations() in the bean StationView produces an JSON output for a list of special Java objects. I advise to use the Gson library in order to serialize any Java object to JSON. Short example:
String[] strings = {"abc", "def", "ghi"};
Gson gson = new Gson();
gson.toJson(strings);  ==> prints ["abc", "def", "ghi"]
The XHTML file above is located under the web context. Say, under the path /rest/stations.xhtml. Ajax call in your JavaScript code should look like this one:
$.ajax({
    url: requestContextPath + '/rest/stations.xhtml',
    type: "GET",
    data: {
        "longitude": x,
        "latitude": y
    },
    dataType: "json",
    success: function (data) {
        $.each(data, function (i, station) {
            ...
        });
    },
    error: function () {
        ...
    }
});
Please refer the jQuery docu for more information regarding $.ajax. Note: if you omit dataType: "json", you have to parse the JSON string manually.
success: function (data) {
    $.each($.parseJSON(data), function (i, station) {
        ...
    });
}
The response is a pure JSON string (no HTML tags) like this one:
[{"latitude":46.947045,"longitude":7.443922,"distanz":110,"name":"Bern, Bundesplatz"},{....},...]
Need more examples for JSON response in JSF? In one of my next post I will probably explain how to implement a cool autocomplete component without writing too much code.

5 comments:

  1. Good post , say i'm in page1.xhtml that is backed by a jsf bean of viewscope and make an ajax request to stations.xhtml to get a json response , wouldn't that ajax request break my view scope since it is going to a different page ?
    MK

    ReplyDelete
    Replies
    1. No, why it should break your view scope? Even if you use the same view scoped bean on the page1.xhtml and stations.xhtml, a new instance of the bean will be created for the stations.xhtml. But the first bean instance for the page1 will still exist. I suggest to use different beans or session scoped beans if you think it will break something.

      Delete
  2. hi, thanks for that article. wou wrote:

    " Even if you use the same view scoped bean on the page1.xhtml and stations.xhtml, a new instance of the bean will be created for the stations.xhtml. "

    i have this situation, but i don't want to create a new instance because data is submitted by ajax before i call stations.xhtml. and the before sended data is now lost, because a new instance was created. how can i do that? thanks in advance.



    ReplyDelete
  3. Very useful article. I wonder if this concept can be expanded further to simplify JSF-REST (non-JAX-RS) front end architecture. I am experimenting with fronting a backing bean to expose it to UI widgets (typically jquery based). With all the new frameworks the model in MVC moves to the client where I believe it should be a happy medium between client and server (model brokering).

    I also wonder how this compares to JAX-RS with respect to performance?

    Cheers.

    ReplyDelete
    Replies
    1. I think JAX-RS is better, more native and faster because a request doesn't pass all JSF phases (it doesn't go through FacesServlet).

      Delete

Note: Only a member of this blog may post a comment.