Reputation: 5250
Using Gson 2.2.4 with nested objects and JsonReader for streaming.
JSON:
{
"name": "David",
"address": {
"city": "Bangalore"
},
"role": "Manager"
}
POJO Classes:
public class Data {
private String name;
private String role;
private Address address;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString(){
return getName() + "::"+getRole()+"::"+getAddress().getCity();
}
}
public class Address {
private String city;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
My Code:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
public class TestReader {
public static void main(String[] args) throws IOException {
InputStream is = new FileInputStream("test.txt");
InputStreamReader isr = new InputStreamReader(is);
JsonReader reader = new JsonReader(isr);
Data data = new Data();
data.setAddress(new Address());
String key = null;
while (reader.hasNext()) {
JsonToken token = reader.peek();
switch (token) {
case BEGIN_OBJECT:
reader.beginObject();
break;
case END_OBJECT:
reader.endObject();
break;
case BEGIN_ARRAY:
reader.beginArray();
break;
case END_ARRAY:
reader.endArray();
break;
case NAME:
key = reader.nextName();
break;
case STRING:
if ("name".equals(key))
data.setName(reader.nextString());
else if ("role".equals(key))
data.setRole(reader.nextString());
else if ("city".equals(key))
data.getAddress().setCity(reader.nextString());
break;
case NULL:
reader.nextNull();
break;
case END_DOCUMENT:
break;
default:
break;
}
}
reader.close();
System.out.println(data);
}
}
It prints "David::null::Bangalore" and not able to parse anything after nested object. If I change JSON to
{
"name": "David",
"role": "Manager",
"address": {
"city": "Bangalore"
}
}
It works fine and prints "David::Manager::Bangalore". Tried a lot but not sure what I am missing.
Upvotes: 1
Views: 3508
Reputation: 6934
Since JSON is recursive by nature, also your method should. That is you need to call again your method on Address object instead of Data.
So I fixed your code (I admin it, into a naive way) to work in this specific case. If you have a more complex structure, of course method get more complex too.
package stackoverflow.questions.q19282973;
import java.io.*;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
public class TestReader {
public static void main(String[] args) throws IOException {
String json = "{\"name\": \"David\",\"address\": {\"city\": \"Bangalore\"},\"role\": \"Manager\"}";
String json2 = "{\"name\": \"David\",\"role\": \"Manager\",\"address\": {\"city\": \"Bangalore\"}}";
InputStream is = new ByteArrayInputStream(json2.getBytes("UTF-8"));
InputStreamReader isr = new InputStreamReader(is);
JsonReader reader = new JsonReader(isr);
Data data = new Data();
data.setAddress(new Address());
String key = null;
key = read(reader, data, key);
reader.close();
System.out.println(data);
}
private static String read(JsonReader reader, Object obj, String key)
throws IOException {
while (reader.hasNext()) {
JsonToken token = reader.peek();
switch (token) {
case BEGIN_OBJECT:
reader.beginObject();
if ("address".equals(key)) {
while (reader.hasNext()) {
read(reader, ((Data) obj).getAddress(), key);
}
reader.endObject();
}
break;
case END_OBJECT:
reader.endObject();
break;
case BEGIN_ARRAY:
reader.beginArray();
break;
case END_ARRAY:
reader.endArray();
break;
case NAME:
key = reader.nextName();
break;
case STRING:
if (obj instanceof Data) {
Data data = (Data) obj;
if ("name".equals(key))
data.setName(reader.nextString());
else if ("role".equals(key))
data.setRole(reader.nextString());
}
if (obj instanceof Address) {
Address address = (Address) obj;
if ("city".equals(key))
address.setCity(reader.nextString());
}
break;
case NULL:
reader.nextNull();
break;
case END_DOCUMENT:
break;
default:
break;
}
}
return key;
}
}
But why you want to user a JsonReader? It should be used only for particular cases and anycase it's a very low level Gson class.
You need only something like this
Data d = new Gson().fromJson(yourJsonString, Data.class) to parse.
Or if you want to parse only specific parts of your JSON, you could write your own deserializer.
Upvotes: 3