How to post a JSON object to an URL?

4k Views Asked by At

I'm trying to post a JSON to a web service so that I can get a JSON in response as return, I have searched in Google but most of the response I found is for Android but not for core Java, this question is for a Swing application I'll give the code the code I used below.

Connection class

public class Connection extends Thread {

private String url1;
private JSONObject data;
String line;
//Constuctor to initialize the variables.

public Connection(String url1, JSONObject data) {
    this.url1 = url1;
    this.data = data;
    start();
}

public void run() {
    ConnectionReaderWriter();
}

//To fetch the data from the input stream
public String getResult() {
    return line;
}

public String ConnectionReaderWriter() {
    URL url;
    HttpURLConnection connection = null;
    ObjectOutputStream out;
    try {
        /*URL url = new URL(Url.server_url + url1);     //Creating the URL.       
         URLConnection conn = url.openConnection();    //Opening the connection.
         conn.setDoOutput(true);
         OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
         wr.write(data);  //Posting the data to the ouput stream.
         wr.flush();
         BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
         line=rd.readLine();     //Reading the data from the input stream.       
         wr.close();
         rd.close();*/
        url = new URL(Url.server_url + url1);     //Creating the URL.
        connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/json");
        connection.setRequestProperty("Accept", "application/json");
        connection.setRequestProperty("api_key", "123456");
        connection.setUseCaches(false);
        connection.setDoInput(true);
        connection.setDoOutput(true);
        //Send request
        out = new ObjectOutputStream(connection.getOutputStream());
        out.writeObject(data);
        out.flush();
        out.close();
    } catch (MalformedURLException ex) {
        Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, null, ex);
        String nonet = "No Network Connection";
        line = nonet;
    } catch (IOException ex) {
        Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, null, ex);
        String nonet = "No Server Connection";
        line = nonet;
    }
    return line;  //Return te stream recived from the input stream.
}
}

The commented code is the one I used before when I was passing as text encoded to the URL. The function call is given below

JSONObject json = new JSONObject();
                json.put("username", username);
                json.put("password", passwordenc);                    
                Connection conn = new Connection(Url.login, json);
                conn.join();

On execution I get the exception shown below

Jan 20, 2014 1:18:32 PM SupportingClass.Connection ConnectionReaderWriter
SEVERE: null
java.io.NotSerializableException: org.json.JSONObject
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at SupportingClass.Connection.ConnectionReaderWriter(Connection.java:74)
at SupportingClass.Connection.run(Connection.java:40)

Please tell me the problem in this code or an alternative to this method.

3

There are 3 best solutions below

0
On

I'll give the answer:

replace out.writeObject(data); with out.write(data.toString().getBytes());

You were trying to write the JSONObject object, and the writeObject() method will attempt to serialize the object, but it will fail since the JSONObject class does not implement Serializable.

0
On

JSon is text, so you cannot use an ObjectOutputStream. The POST method uses the first line of the content as the arguments, so you would need a blank line before the actual content:

    OutputStream stream = connection.getOutputStream();
    stream.write('\r');
    stream.write('\n');
    out = new OutputStreamWriter(stream, "UTF-8");
    out.write(data.toString());
    out.flush();
    out.close();

EDIT: actually we need CR LF, so println() may not work.

0
On

If you find it awkward to use HttpURLConnection natively, you might use an abstraction library. There are many powerful out there. One of them is DavidWebb. You can find a long list of alternatives at the end of that page.

With this library your code would be shorter and more readable:

JSONObject nameAndPassword = new JSONObject();
// set name and password

Webb webb = Webb.create();
JSONObject result = webb.post("your_serverUrl")
        .header("api_key", "123456")
        .useCaches(false)
        .body(nameAndPassword)
        .ensureSuccess()
        .asJsonObject()
        .getBody();

The code shows only the part that would run in your run() method of the Thread. It is not necessary to set the Content-Type header, because this is done automatically by detecting the type of object you set as the body. The same is true for the Accept header.

I assumed that you receive a JSON Object from your REST service, since you set the "Accept" header to "application/json". For receiving a plain String one could write String result = ... .asString().getBody().

BTW the library has been developed with Android in mind, but it can be used with Swing or server-side as well. Maybe you choose another library (e.g. Jersey Client), because you have no restriction about the size. DavidWebb weighs about 20 kilobytes while most other libraries add several hundred kilobytes to your deployment artifacts.

Another thing: you use JSONObject. For small web services, this is not a problem, but if you have to marshal many and/or big objects, you could think about using JAXB + Jackson or Gson. Less code, less errors, more fun!