Correct way for parsing JSON objects containing arrays in Java Servlets (with Gson for example)

10,387

Solution 1

You aren't use JSON to send data to the server:

data : myData,

This specifies parameters as a JavaScript object, but not necessarily as JSON. What this means is that if you do a GET request with:

data: {name1: "value1", name2: "value2"}

The request will be:

http://some/page?name1=value1&name2=value2

This is basically what you're seeing with your first calls, where everything is being converted to a string, then sent as a form parameter.

What you're doing in the second version is almost what you're supposed to do. The only difference is that you need to use a JavaScript object as the parameter to data, not just a string:

data: {arbitraryNameHere: JSON.stringify(myData)}

This will post your "myData" object as JSON, in the parameter named "arbitraryNameHere".

Solution 2

JSON to the server using jQuery ajax method

function  send() {
    var myData = {"gameID": 30,
        "nrOfPlayers": 2,
        "playerUIDs": [123, 124]
    };        
    jQuery.ajax({
        url: "servletName",
        data: JSON.stringify(myData),
        success: function(){
            //console.log(JSON.stringify(myData));
        },
        error: function(data) {
            console.log("Error: ", data);
        },
        type: "post",
        timeout: 30000
    });
}

Sender Button

<button onclick="send();" id="send">Send</button>

Java servlet processing

public class servletName extends HttpServlet {
class GameStart {

    protected String gameID;
    protected int nrOfPlayers;
    protected int[] playerUIDs;
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    Gson gson = new Gson();
    Enumeration en = request.getParameterNames();
    GameStart start = null;
    while (en.hasMoreElements()) {
        start = gson.fromJson((String) en.nextElement(), GameStart.class);
    }
    System.out.println(start.gameID);
    System.out.println(start.playerUIDs[0] +" "+ start.playerUIDs[1]);
}
}

Solution 3

In the real world you typically wouldn't send an actual json object to a servlet and you won't often handle populating values from a request in most circumstances. JSON is JavaScript object notation - and it's great when consumed for use in client side coding.

It's easier to use query string for params rather than a post with json (which it appears you are actually doing). host/url?gameId=5&nrPlayers=2

As far as how to populate values, convention-over-configuration is the way to go for cleanest code. You can use a frameworks like struts to offload all of the transfer of values onto the framework. Not sure what your whole application looks, your intention for writing (ie writing servlets from scratch is a great way to learn but not common practice in real application development environments) like so this may or may not be a helpful answer.

Share:
10,387
Tõnis Pool
Author by

Tõnis Pool

I'm a local code droid in Tartu, studying CS in uni and nibbling on different projects here and there, for now mostly I've been more envolved with web technologies (SOAP, RPC), but now would like to get into the mobile game (android). Language wise, I started with python and then moved to Java, which I've been coding now since 2010 autumn. I have a pretty good grip on Django and a little bit of Wordpress (and other PHP based cms systems).

Updated on June 13, 2022

Comments

  • Tõnis Pool
    Tõnis Pool almost 2 years

    I know this is a topic much talked about, but I still wasn't able to find a correct and clear answer to my specific problem.

    I've got a JSON that looks like this:

    var myData = {  "gameID" : gameID,
                    "nrOfPlayers" : 2,
                    "playerUIDs" : [123, 124]
                };
    

    The Question I have is exactly what is the correct way (or best way, style wise) to parse this in a Java servlet (using GSON for example)? First I send this JSON to the server using jQuery ajax method like this:

    jQuery.ajax({
            url : path,
            data : myData,
            success : successFunction,
            error : function(data) {
                console.log("Error: ", data);
            }  ,
            type : "post",
            timeout : 30000
        });
    

    Now in the servlet I've learned that I should have been able to parse that JSON like this:

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            Gson gson = new Gson();
    
            String gameID = gson.fromJson(request.getParameter("gameID"), String.class);
            String nrOfPlayers = gson.fromJson(request.getParameter("nrOfPlayers"), String.class);
            String[] playerUIDs = gson.fromJson(request.getParameter("playerUIDs"), String[].class);
    
            log.info(gameID);
            log.info(nrOfPlayers);
            log.info(playerUIDs[0] +" "+ playerUIDs[1]);
    }
    

    But the playerUIDs variable IS NULL and of course playerUIDs[0] throws an exception!

    Digging deeper I found that when looping over the request parameter names, it contained a parameter named "playerUIDs[]" with the value of only 123 (the first int in the array). This was strange cause I didn't seem to be able to access the next values at all.

    Then I read that JSON objects should be stringifyed before POST-ing so I added JSON.stringify(myData), but now the request parameter names only contained ONE name which was the JSON object itself in a stringified state:

    INFO: Parameter name = {"gameID":"b6a51aabb8364b04bce676eafde1bc87","nrOfPlayers":2,"playerUIDs":[123,124]}
    

    The only way I seemed to get this to work was by creating a inner class:

    class GameStart {
        protected String gameID;
        protected int nrOfPlayers;
        protected int[] playerUIDs;
    }
    

    And parsing the JSON from the request parameter name, like this:

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            Gson gson = new Gson();
            Enumeration en = request.getParameterNames();
            GameStart start = null;
            while (en.hasMoreElements()) {
                start = gson.fromJson((String) en.nextElement(), GameStart.class);
            }
            log.info(start.gameID);
            log.info(String.valueOf(start.nrOfPlayers));
            log.info(start.playerUIDs[0] +" "+ start.playerUIDs[1]);
    }
    

    Now all values are there, but this seems more like a hack (reading JSON from request parameter name) than an elegant solution, so I thought I'd ask you guys what exactly would be the "correct" way of doing this? Am I missing something obvious?

    Thanks in advance!

  • Tõnis Pool
    Tõnis Pool about 12 years
    Many thanks! That cleared the air a lot, I see now that I was foolishly mistaking JavaScript objects as JSON objects, thinking they are interchangable...