what's up?
I have a JSON which has a Boolean as item 1 and an array of "Socio" objects as item 2 and I have to read with streaming because it's very large.
My +5.0MB JSON is kind of: {"response":true,"result":[{SOCIO OBJECT}, {SOCIO OBJECT}...]
My first code (which threw OutOfMemoryError on API 8, 9) was:
InputStream source = f.retrieveStream(params[0]);
Gson gson = new Gson();
Reader reader = new InputStreamReader(source);
Respuesta response = gson.fromJson(reader, Respuesta.class);
Socio[] socios = response.getSocio();
My new code for streaming is:
InputStream source = f.retrieveStream(params[0]);
Gson gson = new Gson();
JsonReader reader = new JsonReader(new InputStreamReader(source,"UTF-8"));
reader.skipValue(); // Because I have to skip the response... Am i doing this right??
lista = new ArrayList<Socio>();
Socio soc;
reader.beginArray();
while (reader.hasNext()) {
soc = gson.fromJson(reader, Socio.class);
lista.add(soc);
}
reader.endArray();
reader.close();
But it throws this Exception when it's almost loaded:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was END_DOCUMENT at line 1 column 4716089
on the line which has the code: reader.beginArray();
This is where I based my streaming reading.
I've read a lot of parsing with GSON, but I can't find anything for parsing an specific array from a JSON file. I only know to do it with Android Json library but I need to use GSON. I also browsed the 10 first pages of this search on Google and I found no clear response, and I understood this SO question but it's working with objects which has names, so I cannot work with that for array.
Thanks in advance.
Regards.
Rafael.
Your streaming code is wrong, the first skipValue actually makes you skip the whole document.
Try this out:
JsonReader reader = new JsonReader(new InputStreamReader(source,"UTF-8"));
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String strName = jsonReader.nextName();
if (strName.equals("response")) {
reader.skipValue();
}
else if (strName.equals("result")) {
jsonReader.beginArray();
while (reader.hasNext()) {
soc = gson.fromJson(reader, Socio.class);
lista.add(soc);
}
jsonReader.endArray();
}
}
jsonReader.endObject();
...
Related
I have JSONArray of several JSONObjects in a .docx file. I want to write its entries in the local database. For this, I am using Gson. I have used following code for this.
InputStream is = context.getAssets().open("myfile.docx");
JsonReader reader = new JsonReader(new InputStreamReader(is, "UTF-8"));
reader.setLenient(true);
reader.beginArray();
while (reader.hasNext()) {
Gson gson = new Gson();
try {
MyItem item = gson.fromJson(reader, MyItem.class);
getMyDao().create(item);
} catch (Exception e) {
e.printStackTrace();
}
}
reader.endArray();
reader.close();
My file has the string like
[{"key1":"stringValue1","key2":"stringValue2,"key3":intValue1,"key4":"stringValue3"},...]
When I run the app I get Expected BEGIN_ARRAY but was STRING at line 1 column 1 path $. I have gone through all related answers on StackOverflow but didn't help. Please help.
I am making a simple application where i scan the barcode of a book and fetch its title and author from Google APIs,
Now, this is the url for json(for a particular book i am scanning)
https://www.googleapis.com/books/v1/volumes?q=isbn:9788120305960
using this code to get json in a string
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"iso-8859-1"));
String line = "";
while ((line=bufferedReader.readLine())!=null)
{
response+=line;
}
bufferedReader.close();
inputStream.close();
urlConnection.disconnect();
Log.d("Info",response);
return response;
I store the result in a string and use this code to parse through
(json_response is a string)
JSONObject rootObject = new JSONObject(json_response);
JSONArray items = rootObject.getJSONArray("items");
JSONObject items_object = items.getJSONObject(0);
JSONObject volume_info = items_object.getJSONObject("volumeInfo");
book.setTitle(volume_info.getString("title"));
JSONArray authors = volume_info.getJSONArray("authors");
Log.d("Info","authors array length: "+authors.length());
String author="";
for (int i =0;i<authors.length();i++)
{
author+=authors.getString(i)+", ";
}
book.setAuthor(author);
The exception is:
Value null of type org.json.JSONObject$1 cannot be converted to JSONObject
also I used logcat to see what is contained in json_response it looks something like this
null{ "kind": "books#volumes", "totalItems": 1, "items":...
The null here is probably causing the problem, so... any insights how to deal with this???
PS: I am a student , dealing first time with json and android, code is unprofessional, please pardon :)
Having
null{ "kind": "books#volumes", "totalItems": 1, "items":...
means that the response value has not been initialised.
You should therefore initialise it to empty string.
I'm getting a Json from a WebService and I want to print it as a String in my LogCat. I've tried the following:
Gson gson = new Gson();
HttpEntity getResponseEntity = httpResponse.getEntity();
InputStream is = getResponseEntity.getContent();
Reader reader = new InputStreamReader(is);
Type snsType = new TypeToken<SNSRegister>(){}.getType();
snsRegister = gson.fromJson(reader, snsType);
String jsonString = convertStreamToString(is);
snsRegister is an instance of my serializable class, i'm trying to print the JSON in my logcat by converting the InputStream object to String with the convertStreamtoString method:
static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
but my String is always empty and I don't know why. snsRegister is not null, so that isn't the problem.
If this is really important for you to do, Gson can take a String.
I don't recommend reading the Stream twice, though you can do it with mark() and reset(). Since Gson will deserialize a String in addition to Reader, so you can just pass the String into Gson like this:
HttpEntity getResponseEntity = httpResponse.getEntity();
InputStream is = getResponseEntity.getContent();
String jsonString = convertStreamToString(is);
Log.i("MyTAG", jsonString);
Gson gson = new Gson();
Type snsType = new TypeToken<SNSRegister>() {}.getType();
snsRegister = gson.fromJson(jsonString, snsType);
I don't recommend doing this in production though, as the conversion to a String is a lot of extra work. But you can use this temporarily for debugging, obviously; the way you're currently doing it is the best way for production.
Another option would be to convert the SNSRegister object back to JSON with gson.toJson(), but that would be even slower.
Most probably your stream has been read once by GSON.
If you really, really want to read it twice you need to reset() a stream but first you have to mark() the position you want to reset to.
But all you want is to print your JSON in logcat just add toString() method to your SNSRegister class or even better user Retrofit logging mechanism.
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.
My server returned the following string using the jsonencode() in the php code after sending a POST passing variables for the query.
{"distance":"0.00194210443015968","usrlat":"38.5817","usrlong":"-77.3245","globalid":"245"}{"distance":"4.94445650874035","usrlat":"38.6501","usrlong":"-77.2975","globalid":"233"}{"distance":"4.94445650874035","usrlat":"38.6501","usrlong":"-77.2975","globalid":"242"}
Code:
try
{ etc.. connection details..
request = new OutputStreamWriter(connection.getOutputStream());
request.write(parameters);
request.flush();
request.close();
String line = "";
//Convert response to a string
InputStreamReader isr = new InputStreamReader(connection.getInputStream());
BufferedReader reader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
// Response from server will be stored in response variable.
response = sb.toString();
//try parse the string to a JSON object
try{
jObject = new JSONObject(response);
}catch(JSONException e){...
Background - This simple bit of code has produced a jObject which holds only the first element (object) from response. I have tried changing the reponse to an jArray by inserting square brackets before and after, however the elements (objects) from the response are not seperated by a comma. Considered interating through the response to insert comma's however the same root problem exists... parsing and interation. Additionally, I have created a class with properties according to the response. No luck there because the same root problem exist...Parsing and iteration. I have scoured the net, only to discover that JSON is an extremely easy and lite weight alt to XML. I have visted my local book store to discover that JSON is not a book worthy topic...yet. Finally, I have turned to GSON for some clarity.
Question - Using JSON or GSON how do I deserialize and iterate through the response to create useable objects in my android application? Am I asking the right question in my search for a solution?
You basically hit on your issue - that the text is not a valid JSON array. So you have two options:
Preprocess the JSON to make it a valid JSON array
Read each line one by one and create a JSONObject for each line, then manually add each object to a JSONSArray or a plain old java array or collection
FYI - This assumes you have no control over the server side. If you do, change that code to make it a valid JSON array