I have a servlet that has the following purpose:
Receive data via the URL (that is, using get). Then returns a message, based on this input, back to the caller. I am new to this stuff, but have come to learn that using json (actually, Gson) is suitable for this.
My question now is, how do I retrieve this json message? What URL do I target? The relevant lines in the servlet are:
String json = new Gson().toJson(thelist);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().println(json);
This is how I try to retrieve the json:
try{
DefaultHttpClient defaultClient = new DefaultHttpClient();
HttpGet httpGetRequest = new HttpGet("http://AnIPno:8181/sample/response?first=5&second=92866");
HttpResponse httpResponse = defaultClient.execute(httpGetRequest);
BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "UTF-8"));
String json = reader.readLine();
JSONObject jsonObject = new JSONObject(json);
} catch(Exception e){
e.printStackTrace();
}
But apparently this does not work, as I have found jsonObject has a size of 0 (it should be an array with three elements).
Previously, I had a write() instead of println() in the servlet. I'm not sure if that matters in this case. But I'm assuming I've misunderstood something about how the json object is retrieved. Is it not enough to point it towards the URL of the servlet?
Reading an InputStream whether from a File on the file system or from an HTTP request is, in most cases, the same.
What you have is correct only if your servlet wrote a single line. If the Gson object toString() method returns multiple lines, you're going to have to read multiple lines from the InputStream. I like to use the Scanner class for reading from an InputStream.
try {
DefaultHttpClient defaultClient = new DefaultHttpClient();
HttpGet httpGetRequest = new HttpGet("http://localhost:8080/cc/jsonyeah");
HttpResponse httpResponse = defaultClient.execute(httpGetRequest);
Scanner scanner = new Scanner(httpResponse.getEntity().getContent(), "UTF-8");
while(scanner.hasNextLine()) { // scanner looks ahead for an end-of-line
json += scanner.nextLine() + "\n"; // read the full line, you can append a \n
}
// do your serialization
} catch(Exception e) {
e.printStackTrace();
}
So we've done the same thing we would've done if we were reading from a file. Now the json object contains the json you received from the servlet, as a String.
For the serialization, you have a few options.
A Gson object has an overloaded method fromJson() that can take a String or a Reader, among other things.
From where we are with the code above, you can do
MyClass instance = new Gson().fromJson(json, MyClass.class);
where MyClass is the type you are trying to create. You will have to use a TypeToken for generic classes (such as a list). TypeToken is an abstract class, so generate an anonymous class and call getType()
Type type = new com.google.gson.reflect.TypeToken<List<String>>(){}.getType();
List<MyClass> list = new Gson().fromJson(json, type);
Another option is to use the overloaded method that takes a Reader directly instead of reading line by line from the InputStream:
BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "UTF-8"));
MyClass instance = new Gson().fromJson(reader , MyClass.class);
You'll get to skip a step.
Don't forget to close your streams.
I have this function to readJsonData from a a request to a JSON String. You can use this function to retrieve the JSON, then use GSON to parse it to the object that you like. It works for my application. Hope it works for you too.
protected String readJson(HttpResponse resp)
throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(
resp.getEntity().getContent()));
StringBuffer buffer = new StringBuffer();
int read;
char[] chars = new char[1024];
while ((read = reader.read(chars)) != -1)
buffer.append(chars, 0, read);
} finally {
if (reader != null)
reader.close();
}
return buffer.toString();
}
So based on your code. I guess this should work:
String jsonData = readJson(httpResponse);
YourObject obj = new Gson().fromJson(jsonData, YourObject.class);
Before trying this, make sure your servlet prints out the JSON data that you want. I suggest using these Chrome Extensions: Postman - REST Client and JSON Formatter, to test your data from servlet. It's pretty helpful.
Related
I'm relatively new to Android (I'm an iOS-Developer) and I want to call a Webservice like I'm used to in iOS with NSURLConnectionDelegate's method
didReceiveData:(NSData *)data
I need to get the data incrementally because I'm building a streaming API that gets a lot of JSON data in response and needs to check the data for complete blocks.
Would be great if someone could help me, I've been searching for a while and didn't find a satisfying solution so far.
If you try to call web services in Android you should use the AsyncTask where the request would be made asynchronously. Have a look at the documentation. Every time you're request would be finished the method onPostExecute(Object result) would be called. Thats the method where you can go on with further processes.
The URLConnection documentation contain following example:
URL url = new URL("ftp://mirror.csclub.uwaterloo.ca/index.html");
URLConnection urlConnection = url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
try {
readStream(in);
finally {
in.close();
}
If i right understood your question, just implement readStream function as you need.
I found out how to do this with the help of a friend and some links.
You need to implement an own ResponseHandler like this:
class ChunkedResponseHandler implements ResponseHandler<String> {
#Override
public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
StringBuffer output = new StringBuffer();
byte[] b = new byte[4096];
int n;
while ((n = stream.read(b)) != -1) {
output.append(new String(b, 0, n));
// do something while input is streaming
}
return output.toString();
}
}
Now you simply have to assign the response handler when starting the request:
HttpClient client = new DefaultHttpClient();
HttpGet getRequest = new HttpGet("someURL");
ResponseHandler<String> responseHandler = new ChunkedResponseHandler();
String responseBody = client.execute(postRequest, responseHandler);
I have made a HTTP-post inside my android application. Values are sent as strings from my app to my webserver. Problem is, the values are not in UTF-8 as I want them to be. My webserver has UTF-8 encoding so I know that there is code inside my app that I need to change.
See my snippet below:
private void sendPostRequest(String facebookId, String name, String email) {
class SendPostReqAsyncTask extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... bcs) {
String bcFacebookId = bcs[0];
String bcName = bcs[1];
String bcEmail = bcs[2];
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("URL");
BasicNameValuePair facebookIdBasicNameValuePair = new BasicNameValuePair("bcFacebookId", bcFacebookId);
BasicNameValuePair nameBasicNameValuePair = new BasicNameValuePair("bcName", bcName);
BasicNameValuePair emailBasicNameValiePair = new BasicNameValuePair("bcEmail", bcEmail);
List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();
nameValuePairList.add(facebookIdBasicNameValuePair);
nameValuePairList.add(nameBasicNameValuePair);
nameValuePairList.add(emailBasicNameValiePair);
try {
UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(nameValuePairList);
httpPost.setEntity(urlEncodedFormEntity);
try {
HttpResponse httpResponse = httpClient.execute(httpPost);
InputStream inputStream = httpResponse.getEntity().getContent();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuilder stringBuilder = new StringBuilder();
String bufferedStrChunk = null;
while((bufferedStrChunk = bufferedReader.readLine()) != null){
stringBuilder.append(bufferedStrChunk);
}
return stringBuilder.toString();
} catch (ClientProtocolException cpe) {
cpe.printStackTrace();
} catch (IOException ioe) {
System.out.println("Second Exception caz of HttpResponse :" + ioe);
ioe.printStackTrace();
}
} catch (UnsupportedEncodingException uee) {
System.out.println("An Exception given because of UrlEncodedFormEntity argument :" + uee);
uee.printStackTrace();
}
return null;
}
For an example, the letter 'ö' becomes a '?'. How do I fix this?
Cheers!
The biggest single reason that characters get converted into question marks is the conversion of characters to bytes, and then back into characters, not matching.
The code you have supplied has this line:
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
This is problematic because you are not specifying how to convert the bytes into characters. Instead you probably want this:
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
What you specify for the character encoding will depend upon the character encoding that you have specified elsewhere. Without specifying the character encoding, you will get the "default" character encoding, and that depends upon settings in both the client and the server. Java uses Unicode, and UTF-8 is the only encoding that will preserve all the characters that Java allows.
For debugging, you may want to use the InputStream and retrieve bytes from that, and print out the byte values, in order to verify that they are indeed UTF-8 encoded representations of the original character values. The proper encoding of 'ö' (x00F6) is 'ö' (x00C3 x00B6).
You will also need to assure that the original POST request is properly UTF-8 encoded. The UrlEncodedFormEntity class also uses the default character encoding, which might not be UTF-8. Change this:
UrlEncodedFormEntity uefe = new UrlEncodedFormEntity(nameValuePairList);
to
UrlEncodedFormEntity uefe = new UrlEncodedFormEntity(nameValuePairList, "UTF-8");
if database coding is set properly + table coding is set properly + columns coding set properly, then all data are stored properly. That's the first part. Now the second, important part - make sure you have this command after your mysql connection : SET NAMES utf8
This was my case for the same issue. Hope this this will work for you as well.
I'm sending images and json text from the android client to a tomcat server and the other way around by using Multipart HttpPost's. Sending a Multipart Entity to the server is no big deal, because you can process the parts easily using request.getPart(<name>). But at the client side you can only access the response as a Stream. So I end up appending both, the JSON string and the image to the same ServletOutputStream and have to parse them by hand on the client side. I found apache-mime4j in the web but its hardly documented and I cant find a single example how to use it.
On the server side I build the response like this:
ServletResponse httpResponse = ctx.getResponse();
ResponseFacade rf = (ResponseFacade) httpResponse;
rf.addHeader("Access-Control-Allow-Origin", "*");
rf.addHeader("Access-Control-Allow-Methods", "POST");
rf.addHeader("content-type", "multipart/form-data");
httpResponse.setCharacterEncoding("UTF-8");
MultipartResponse multi = new MultipartResponse((HttpServletResponse) httpResponse);
ServletOutputStream out = httpResponse.getOutputStream();
multi.startResponse("text/plain");
out.println(CMD + "#" + content);
multi.endResponse();
multi.startResponse("image/jpeg");
out.write(data);
multi.endResponse();
multi.finish();
ctx.complete();
And on the client side on Android I want to access the text and the image data:
InputStream is = response.getEntity().getContent();
MimeStreamParser parser = new MimeStreamParser();
MultipartContentHandler con = new MultipartContentHandler();
parser.setContentHandler(con);
try {
parser.parse(is);
String json = con.getJSON(); //get extracted json string
byte[] imgBytes = con.getBytes(); //get extracted bytes
} catch (MimeException e) {
e.printStackTrace();
} finally {
is.close();
}
class MultipartContentHandler implements ContentHandler{
public void body(BodyDescriptor bd, InputStream in) throws MimeException, IOException {
//if MIME-Type is "text/plain"
// process json-part
//else
// process image-part
}
In the method body(BodyDescriptor bd, InputStream in) my whole response is treated as text\plain mime type. So I finally have to parse every byte manually again and the whole apache-mime4j is useless. Can you tell me what I am doing wrong? Thanks!
Ok i finally solved it myself. No here's what i did:
First I need to create a multipart/mixed Response at the server side. It can be done using apache-mime-4j API:
ServletResponse httpResponse = ctx.getResponse();
ResponseFacade rf = (ResponseFacade) httpResponse;
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("multipart/mixed");
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, "SEPERATOR_STRING",Charset.forName("UTF-8"));
entity.addPart("json", new StringBody(CMD + "#" + content, "text/plain", Charset.forName("UTF-8")));
entity.addPart("image", new ByteArrayBody(data, "image/jpeg", "file"));
httpResponse.setContentLength((int) entity.getContentLength());
entity.writeTo(httpResponse.getOutputStream());
ctx.complete();
Now at the client side to access the MIME-Parts of the HttpResponse I use the javax.mail API.
ByteArrayDataSource ds = new ByteArrayDataSource(response.getEntity().getContent(), "multipart/mixed");
MimeMultipart multipart = new MimeMultipart(ds);
BodyPart jsonPart = multipart.getBodyPart(0);
BodyPart imagePart = multipart.getBodyPart(1);
But you can't use the native API, instead take this one http://code.google.com/p/javamail-android/
Now you can proceed handling your individual parts.
It is also possible with apache-mime-4j:
HttpURLConnection conn = ...;
final InputStream is = conn.getInputStream();
try {
final StringBuilder sb = new StringBuilder();
sb.append("MIME-Version: ").append(conn.getHeaderField("MIME-Version")).append("\r\n");
sb.append("Content-Type: ").append(conn.getHeaderField("Content-Type")).append("\r\n");
sb.append("\r\n");
parser.parse(new SequenceInputStream(new ByteArrayInputStream(sb.toString().getBytes("US-ASCII")), is));
} catch (final MimeException e) {
e.printStackTrace();
} finally {
is.close();
}
Here is the code I'm using inside my AsyncTask
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
HttpResponse response = httpClient.execute(request);
HttpEntity responseEntity = response.getEntity();
char[] buffer = new char[(int)responseEntity.getContentLength()];
InputStream stream = responseEntity.getContent();
InputStreamReader reader = new InputStreamReader(stream);
reader.read(buffer);
stream.close();
result = new String(buffer);
return result;
This returns a string result and in my onPostExecute method I try to parse that input string:
JSONObject vehicle = new JSONObject(new String(result));
makeEdit.setText(vehicle.getString("make"));
plateEdit.setText(vehicle.getString("plate"));
modelEdit.setText(vehicle.getString("model"));
yearEdit.setText(vehicle.getString("year"));
As soon as it reaches makeEdit.setText it throws an error - no value for make. I'm still very new to android, so don't send death threats if there was some obvious error. The input text is the following JSON string:
{"GetJSONObjectResult":{"make":"Ford","model":"Focus","plate":"XXO123GP","year":2006}}
No value for x error message is pretty common when dealing with JSON. This usually resulted by overlooked code.
usually, when dong JSON, I try to see the human readable structure first. For that, I usually use JSONViewer.
In your case, the structure is something like this:
You see that make is within another object called GetJSONObjectResult. Therefore, to get it, you must first get the container object first:
JSONObject vehicle = ((JSONObject)new JSONObject(result)).getJSONObject("GetJSONObjectResult");
//a more easy to read
JSONObject container = new JSONObject(result);
JSONObject vehicle = container.getJSONObject("GetJSONObjectResult");
and finally use the object to get make:
makeEdit.setText(vehicle.getString("make"));
plateEdit.setText(vehicle.getString("plate"));
modelEdit.setText(vehicle.getString("model"));
yearEdit.setText(vehicle.getString("year"));
Your JSON Object contains itself a JSONObject. To acces to your data, you have to do like this:
vehicle.getJSONObject("GetJSONObjectResult").getString("make");
Hi there i'm creating my first android app and i'm wanting to know what is the best and most efficient way of parsing a JSON Feed from a URL.Also Ideally i want to store it somewhere so i can keep going back to it in different parts of the app. I have looked everywhere and found lots of different ways of doing it and i'm not sure which to go for. In your opinion whats the best way of parsing json efficiently and easily?
I'd side with whatsthebeef on this one, grab the data and then serialize to disk.
The code below shows the first stage, grabbing and parsing your JSON into a JSON Object and saving to disk
// Create a new HTTP Client
DefaultHttpClient defaultClient = new DefaultHttpClient();
// Setup the get request
HttpGet httpGetRequest = new HttpGet("http://example.json");
// Execute the request in the client
HttpResponse httpResponse = defaultClient.execute(httpGetRequest);
// Grab the response
BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "UTF-8"));
String json = reader.readLine();
// Instantiate a JSON object from the request response
JSONObject jsonObject = new JSONObject(json);
// Save the JSONOvject
ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDir(),"")+"cacheFile.srl"));
out.writeObject( jsonObject );
out.close();
Once you have the JSONObject serialized and save to disk, you can load it back in any time using:
// Load in an object
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(new File(getCacheDir(),"")+"cacheFile.srl")));
JSONObject jsonObject = (JSONObject) in.readObject();
in.close();
Your best bet is probably GSON
It's simple, very fast, easy to serialize and deserialize between json objects and POJO, customizable, although generally it's not necessary and it is set to appear in the ADK soon. In the meantime you can just import it into your app. There are other libraries out there but this is almost certainly the best place to start for someone new to android and json processing and for that matter just about everyone else.
If you want to persist you data so you don't have to download it every time you need it, you can deserialize your json into a java object (using GSON) and use ORMLite to simply push your objects into a sqlite database. Alternatively you can save your json objects to a file (perhaps in the cache directory)and then use GSON as the ORM.
This is pretty straightforward example using a listview to display the data. I use very similar code to display data but I have a custom adapter. If you are just using text and data it would work fine. If you want something more robust you can use lazy loader/image manager for images.
Since an http request is time consuming, using an async task will be the best idea. Otherwise the main thread may throw errors. The class shown below can do the download asynchronously
private class jsonLoad extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
#Override
protected void onPostExecute(String result) {
// Instantiate a JSON object from the request response
try {
JSONObject jsonObject = new JSONObject(result);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
File file = new File(getApplicationContext().getFilesDir(),"nowList.cache");
try {
file.createNewFile();
FileOutputStream writer = openFileOutput(file.getName(), Context.MODE_PRIVATE);
writer.write(result);
writer.flush();
writer.close();
}
catch (IOException e) { e.printStackTrace(); return false; }
}
}
Unlike the other answer, here the downloaded json string itself is saved in file. So Serialization is not necessary
Now loading the json from url can be done by calling
jsonLoad jtask=new jsonLoad ();
jtask.doInBackground("http:www.json.com/urJsonFile.json");
this will save the contents to the file.
To open the saved json string
File file = new File(getApplicationContext().getFilesDir(),"nowList.cache");
StringBuilder text = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
br.close();
}
catch (IOException e) {
//print log
}
JSONObject jsonObject = new JSONObject(text);