How to post a JSON object to an URL? - java

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.

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.

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.

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!

Related

Post Request to WebService in Android

I have a problem with a WebService on Android. I am getting a 400 error but there is no information on the ErrorStream.
What I am trying to do is a POST request on a WCF Webservice using JSON.
I must add that I have includeExceptionDetailInFaults Enabled on my Service. The last time I got a 400 error, it was because I hadn't defined the RequestProperty. Now I don't get any error in the stream.
Here is the code:
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
// In my last error I had not included these lines. Maybe they are still wrong?
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Accept", "application/json");
urlConnection.setRequestMethod("POST");
urlConnection.setDoOutput(true);
urlConnection.setChunkedStreamingMode(0);
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(out);
outputStreamWriter.write(jsonObject.toString(), 0, jsonObject.length());
outputStreamWriter.flush();
//outputStreamWriter.close();
int code = urlConnection.getResponseCode();
System.out.println(code);
if(code == 400) {
BufferedInputStream errorStream = new BufferedInputStream(urlConnection.getErrorStream());
InputStreamReader errorStreamReader = new InputStreamReader(errorStream);
BufferedReader bufferedReader = new BufferedReader(errorStreamReader);
StringBuilder builder = new StringBuilder();
String aux = "";
while ((aux = bufferedReader.readLine()) != null) {
builder.append(aux);
}
String output = builder.toString(); // The output is empty.
System.out.print(output);
}
Check Retrofit library from Square it's more easy and thin for GET/POST request and especially for REST. I suggest you to try it. It will make your life easy.
You can use different JSON parsers, error handlers, etc. Very flexible.
POST request definition using retrofit it's simple like this:
An object can be specified for use as an HTTP request body with the #Body annotation.
#POST("/users/new")
void createUser(#Body User user, Callback<User> cb);
Methods can also be declared to send form-encoded and multipart data.
Form-encoded data is sent when #FormUrlEncoded is present on the method. Each key-value pair is annotated with #Field containing the name and the object providing the value.
#FormUrlEncoded
#POST("/user/edit")
User updateUser(#Field("first_name") String first, #Field("last_name") String last);
After you define method inside your Java interface like shown above instantiate it:
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.soundcloud.com")
.build();
MyInterface service = restAdapter.create(MyInterface.class);
And then you can call your method synchronously or asynchronously (in case you pass Callback instance).
service.myapi(requestBody);
See Retrofit documentation (http://square.github.io/retrofit/javadoc/index.html) and samples on GitHub for more details.
A 400 error might be occuring (and usually occurs in my case) because of incorrect URL or bad JSON format in post. please check those two
Using an HttpPost object will make your job a lot easier in my opinion
HttpPost post = new HttpPost(url);
if(payload != null){
try {
StringEntity entity = new StringEntity(payload,HTTP.UTF_8);
entity.setContentType(contentType);
post.setEntity(entity);
} catch (UnsupportedEncodingException e) {
LOG.d(TAG, "post err url : " + url);
LOG.e(TAG, "post err url" , e);
throw new Exception(1, e);
}
}
HttpResponse response=executeRequest(owner, post);

Selecting one among many possible choices in a Web page using Java

I want to get the HTML code of the following Web Page (http://www.studenti.ict.uniba.it/esse3/ListaAppelliOfferta.do) after:
selecting "Dipartimento di Informatica" among Facoltà
selecting "Informatica" (or one of the others available)
clicking "Avvia Ricerca"
I am not very keen in the matter but I noticed the URL of the page stays the same after each selection!?!
Can anyone help describing, possibly in details, how can I do that? Unfortunately I am not expert in web programming.
Many thanks
After some tests, it refresh the pages with a POST request
fac_id:1012 --
cds_id:197 --
ad_id: -- Attività didattica
docente_id: -- Id of the docent selected
data:06/03/2014 -- Date
Anyway you missed the value of Attività ditattica, Docente and Data esame
Just run a HTTP request using HttpURLConnection (?) with this POST args, and with a XML parser read the output of tplmessage table.
Try this tutorial for HTTP request: click.
Try to read this to understand how to parse response: click
An example using the code of the tutorial:
HttpURLConnection connection = null;
try
{
URL url = new URL("http://www.studenti.ict.uniba.it/esse3/ListaAppelliOfferta.do");
connection = (HttpURLConnection) url.openConnection(); // open the connection with the url
String params =
"fac_id=1012&cds_id=197"; // You need to add ad_id, docente_id and data
connection.setRequestMethod("POST"); // i need to use POST request method
connection.setRequestProperty("Content-Length", "" + Integer.toString(params.getBytes().length)); // It will add the length of params
connection.setRequestProperty("Content-Language", "it-IT"); // language italian
connection.setUseCaches (false);
connection.setDoInput (true);
connection.setDoOutput (true);
DataOutputStream wr = new DataOutputStream(
connection.getOutputStream ());
wr.writeBytes (params); // pass params
wr.flush (); // send request
wr.close ();
//Get Response
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder response = new StringBuilder();
while((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
}
catch (MalformedURLException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
finally
{
// close connection if created
if (connection != null)
connection.disconnect();
}
In response you will have the DOM of the page.
Anyway, use Chrome developers tool to get request args:

Design pattern for using Auth Tokens?

I'm a client side developer, moving over to server side development.
One common problem I am encountering is the need to make one API call (say to get an authentication token) and then make a follow up API call to get the data I want. Sometimes, I need to make two API calls in succession for data, without an auth token as well.
Is there a common design pattern or Java library to address this issue? Or do I need to manually create the string of calls each time I need to do so?
Edit: I'm hoping for something that looks like this
CustomClassBasedOnJson myStuff = callAPI("url", getResponse("authURL"));
This would make a call to the "url" with data received from the "authURL".
The point here is that I'm stringing multiple url calls, using the result of one call to define the next one.
When doing Server side programming, it is acceptable for HTTP calls to be called synchronously.
Therefore the proper pattern is to simply make the first call, receive the result, and then use that in the next line. There is no need to separate the calls into separate threads, or asynchronous calls, unless there is major processing happening between http calls.
For example:
JsonResponseEntry getJsonReportResponse() throws IOException {
String sReportURL = "https://someurl.com/v2/report/report?" +
"startts=" + getDateYesterday("ts") +
"&endts=" + getDateNow("ts") +
"&auth=" + getAuthCode();
URL reportURL = new URL(sReportURL);
URLConnection conn = reportURL.openConnection();
BufferedReader buf = new BufferedReader(new InputStreamReader(conn.getInputStream()));
ObjectMapper mapper = new ObjectMapper();
JsonNode reportResult = mapper.readTree(buf);
return convertJSonNodeToJsonResponseEntry(reportResult);
}
String getAuthCode() throws IOException {
String sReportURL = "https://someurl.com/auth";
URL reportURL = new URL(sReportURL);
HttpURLConnection conn = (HttpURLConnection) reportURL.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.connect();
String urlParameters = "username=myUserName&password=mypassword";
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
BufferedReader buf = new BufferedReader(new InputStreamReader(conn.getInputStream()));
ObjectMapper mapper = new ObjectMapper();
AuthResponse response = mapper.readValue(buf, AuthResponse.class);
return response.toString();
}
The function getAuthCode() is synchronously called within the URL call that requires the response.

Sending JSON POST to Django App

I have a bit of Java code that attempts to send POST data over to t Django application. However, the view is simply never called. If I paste the same URL the java code hits into my browser, the Django view is called. I have no idea what I am missing, but something must be wrong with the Java write.
This is the Java function doing the write:
public void executeWrite(String requestUrl, JsonObject jsonObject)
{
DataInputStream input = null;
try
{
URL url;
HttpURLConnection urlConn;
DataOutputStream printout;
System.out.println(requestUrl);
// URL of CGI-Bin script.
url = new URL (requestUrl);
// URL connection channel.
urlConn = (HttpURLConnection)url.openConnection();
// Let the run-time system (RTS) know that we want input.
urlConn.setDoInput (true);
// Let the RTS know that we want to do output.
urlConn.setDoOutput (true);
// No caching, we want the real thing.
urlConn.setUseCaches (false);
// Specify the content type.
urlConn.setRequestMethod("POST");
urlConn.setRequestProperty("content-type","application/json; charset=utf-8");
OutputStreamWriter wr = new OutputStreamWriter(urlConn.getOutputStream());
wr.write(jsonObject.toString());
wr.flush();
wr.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
Now the requestURL passed into the function directly corresponds to the one for the Django view. The requestURL is:
http://127.0.0.1:8000/events/rest/33456/create
This is the Django Urlconfig:
(r'^events/rest/(?P<key>\d+)/create', 'events.views.restCreateEvent'),
Finally this is the view that never gets called by the Java code
#csrf_exempt
def restCreateEvent(request, key):
#doesn't really matter what is in here it never runs
So, what am I doing wrong that the POST request is never received by the Django sever? I've spent about 2 hours trying to figure it out and I can't find any issues with the Java code. Clearly something is wrong though.
Make sure your view is csrf exempt since you are not sending the appropriate CSRF token from the Java request.
I think the crsf thing was actually the issue. Once I added that I changed the Java code slightly and it worked. I am still not sure what the subtle Java error was, here is the working Java code.
public void executeWrite(String requestUrl, JsonObject jsonObject)
{
InputStreamReader input = null;
try
{
URL url;
HttpURLConnection urlConn;
DataOutputStream printout;
System.out.println(requestUrl);
// URL of CGI-Bin script.
url = new URL (requestUrl);
// URL connection channel.
urlConn = (HttpURLConnection)url.openConnection();
// Let the run-time system (RTS) know that we want input.
urlConn.setDoInput (true);
// Let the RTS know that we want to do output.
urlConn.setDoOutput (true);
// No caching, we want the real thing.
urlConn.setUseCaches (false);
// Specify the content type.
urlConn.setRequestMethod("POST");
urlConn.setRequestProperty("content-type","application/json; charset=utf-8");
OutputStreamWriter wr = new OutputStreamWriter(urlConn.getOutputStream());
wr.write(jsonObject.toString());
wr.flush();
wr.close();
input = new InputStreamReader (urlConn.getInputStream ());
String response = UserInterface.read(new BufferedReader(input));
if(response.length() > 0)
{
System.out.println("Response:" + response);
}
input.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
I remember the URL need change to "http://127.0.0.1:8000/events/rest/33456/create/" when use "POST" type.

FileNotFoundException while getting the InputStream object from HttpURLConnection

I am trying to send a post request to a url using HttpURLConnection (for using cUrl in java).
The content of the request is xml and at the end point, the application processes the xml and stores a record to the database and then sends back a response in form of xml string. The app is hosted on apache-tomcat locally.
When I execute this code from the terminal, a row gets added to the db as expected. But an exception is thrown as follows while getting the InputStream from the connection
java.io.FileNotFoundException: http://localhost:8080/myapp/service/generate
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1401)
at org.kodeplay.helloworld.HttpCurl.main(HttpCurl.java:30)
Here is the code
public class HttpCurl {
public static void main(String [] args) {
HttpURLConnection con;
try {
con = (HttpURLConnection) new URL("http://localhost:8080/myapp/service/generate").openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
File xmlFile = new File("test.xml");
String xml = ReadWriteTextFile.getContents(xmlFile);
con.getOutputStream().write(xml.getBytes("UTF-8"));
InputStream response = con.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(response));
for (String line ; (line = reader.readLine()) != null;) {
System.out.println(line);
}
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Its confusing because the exception is traced to the line InputStream response = con.getInputStream(); and there doesn't seem to be any file involved for a FileNotFoundException.
When I try to open a connection to an xml file directly, it doesn't throw this exception.
The service app uses spring framework and Jaxb2Marshaller to create the response xml.
The class ReadWriteTextFile is taken from here
Thanks.
Edit:
Well it saves the data in the DB and sends back a 404 response status code at the same time.
I also tried doing a curl using php and print out the CURLINFO_HTTP_CODE which turns out to be 200.
Any ideas on how do I go about debugging this ? Both service and client are on the local server.
Resolved:
I could solve the problem after referring to an answer on SO itself.
It seems HttpURLConnection always returns 404 response when connecting to a url with a non standard port.
Adding these lines solved it
con.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) ");
con.setRequestProperty("Accept","*/*");
I don't know about your Spring/JAXB combination, but the average REST webservice won't return a response body on POST/PUT, just a response status. You'd like to determine it instead of the body.
Replace
InputStream response = con.getInputStream();
by
int status = con.getResponseCode();
All available status codes and their meaning are available in the HTTP spec, as linked before. The webservice itself should also come along with some documentation which overviews all status codes supported by the webservice and their special meaning, if any.
If the status starts with 4nn or 5nn, you'd like to use getErrorStream() instead to read the response body which may contain the error details.
InputStream error = con.getErrorStream();
FileNotFound is just an unfortunate exception used to indicate that the web server returned a 404.
To anyone with this problem in the future, the reason is because the status code was a 404 (or in my case was a 500). It appears the InpuStream function will throw an error when the status code is not 200.
In my case I control my own server and was returning a 500 status code to indicate an error occurred. Despite me also sending a body with a string message detailing the error, the inputstream threw an error regardless of the body being completely readable.
If you control your server I suppose this can be handled by sending yourself a 200 status code and then handling whatever the string error response was.
For anybody else stumbling over this, the same happened to me while trying to send a SOAP request header to a SOAP service. The issue was a wrong order in the code, I requested the input stream first before sending the XML body. In the code snipped below, the line InputStream in = conn.getInputStream(); came immediately after ByteArrayOutputStream out = new ByteArrayOutputStream(); which is the incorrect order of things.
ByteArrayOutputStream out = new ByteArrayOutputStream();
// send SOAP request as part of HTTP body
byte[] data = request.getHttpBody().getBytes("UTF-8");
conn.getOutputStream().write(data);
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
Log.d(TAG, "http response code is " + conn.getResponseCode());
return null;
}
InputStream in = conn.getInputStream();
FileNotFound in this case was an unfortunate way to encode HTTP response code 400.
FileNotFound in this case means you got a 404 from your server - could it be that the server does not like "POST" requests?
FileNotFound in this case means you got a 404 from your server
You Have to Set the Request Content-Type Header Parameter
Set “content-type” request header to “application/json” to send the request content in JSON form.
This parameter has to be set to send the request body in JSON format.
Failing to do so, the server returns HTTP status code “400-bad request”.
con.setRequestProperty("Content-Type", "application/json; utf-8");
Full Script ->
public class SendDeviceDetails extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String data = "";
String url = "";
HttpURLConnection con = null;
try {
// From the above URL object,
// we can invoke the openConnection method to get the HttpURLConnection object.
// We can't instantiate HttpURLConnection directly, as it's an abstract class:
con = (HttpURLConnection)new URL(url).openConnection();
//To send a POST request, we'll have to set the request method property to POST:
con.setRequestMethod("POST");
// Set the Request Content-Type Header Parameter
// Set “content-type” request header to “application/json” to send the request content in JSON form.
// This parameter has to be set to send the request body in JSON format.
//Failing to do so, the server returns HTTP status code “400-bad request”.
con.setRequestProperty("Content-Type", "application/json; utf-8");
//Set Response Format Type
//Set the “Accept” request header to “application/json” to read the response in the desired format:
con.setRequestProperty("Accept", "application/json");
//To send request content, let's enable the URLConnection object's doOutput property to true.
//Otherwise, we'll not be able to write content to the connection output stream:
con.setDoOutput(true);
//JSON String need to be constructed for the specific resource.
//We may construct complex JSON using any third-party JSON libraries such as jackson or org.json
String jsonInputString = params[0];
try(OutputStream os = con.getOutputStream()){
byte[] input = jsonInputString.getBytes("utf-8");
os.write(input, 0, input.length);
}
int code = con.getResponseCode();
System.out.println(code);
//Get the input stream to read the response content.
// Remember to use try-with-resources to close the response stream automatically.
try(BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8"))){
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println(response.toString());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (con != null) {
con.disconnect();
}
}
return data;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.e("TAG", result); // this is expecting a response code to be sent from your server upon receiving the POST data
}
and call it
new SendDeviceDetails().execute("");
you can find more details in this tutorial
https://www.baeldung.com/httpurlconnection-post
The solution:
just change localhost for the IP of your PC
if you want to know this: Windows+r > cmd > ipconfig
example: http://192.168.0.107/directory/service/program.php?action=sendSomething
just replace 192.168.0.107 for your own IP (don't try 127.0.0.1 because it's same as localhost)
Please change
con = (HttpURLConnection) new URL("http://localhost:8080/myapp/service/generate").openConnection();
To
con = (HttpURLConnection) new URL("http://YOUR_IP:8080/myapp/service/generate").openConnection();

Categories

Resources