"Dotting" in JSON using Gson on Android - java

I'm trying to parse a JSON feed using Gson in Android. I know the JSON is valid. I suspect that it is because the format is like this:
"Info":[
{
"Id":"",
"Name":"",
"Description":"",
"Date":""
}
In order to parse this I need to "dot" in. Ex: Info.Name
How can I do this in a serialized DTO?
#SerializedName("Name")
public String name;
#SerializedName("Description")
public String desc;
#SerializedName("Date")
public String date;
I tried to put "Info." in front of each serializedName but that didn't work either. I also know my JSON parsing method works properly, because it's used somewhere else with a different DTO. But in that parsing, I don't have to "dotting" issue.
Can anyone help?
EDIT: I have tried everything you guys posted, and nothing works. The error says:
The JsonDeserializer failed to deserialize json object {"Info":[{".......
SECOND EDIT:
I was able to get rid of the error, but now it returns null. Haha, getting pretty damn frustrated right about now!

I am assuming that the actual JSON you are intaking is valid because the example you provided is not. In your JSON example, you have "Info":[ but there is no outer object containing the "Info" property, which is a must. The valid JSON would be:
{
"Info": [
{
"Id":"",
"Name":"",
"Description":"",
"Date":"",
}
]
}
This is a JSON object that has a property "Info" which has a value that is a list of objects. This list of objects contains one object that has the properties "Id", "Name", "Description", and "Date", all of which have empty-string values.
Here is a quick tutorial on how to use GSON to parse a JSON feed such as the above JSON:
You will need a class to represent the items in the list:
public class InfoItem {
public String Id;
public String Name;
public String Description;
public String Date;
public InfoItem() {}
}
And one to represent the list of Items:
public class InfoItemList extends LinkedList<InfoItem> {
public InfoItemList() { super() };
}
This added complexity is because GSON cannot otherwise get the type of a generic collection from the class data.
And one to represent the overall JSON message:
public class InfoMessage {
public InfoItemList Info;
public InfoMessage() {};
}
And then just:
gson.fromJson(jsonString, InfoMessage.getClass());
If just de-serializing a collection:
Type listType = new TypeToken<List<InfoItem>>() {}.getType();
gson.fromJson(jsonString2, listType);

The Info object is a list because of the []. You have to use the following code to deserialze it:
EDIT:
public class Info {
// as in your question
public String name;
...
}
public class Data {
#SerializedName("Info")
public List<Info> info;
}
Then just use the data class to deserialize your json.

Related

How would I use Jackson to flatten JSON with nested array?

I am using JackSon to parse the following JSON:
{
"AwardID": "1111111",
"AwardTitle": "Test Title",
"Effort":
"[
{
"PersonFirstName": "Jon",
"PersonLastName": "Snow"
}
]"
}
I would like to flatten this to be used in the following class:
public class Award {
private String awardId;
private String awardTitle;
private String personFirstName;
private String personLastName;
}
I have tried the following and have gotten the first two values, but I haven't been able to get the values from Effort trying to use JsonUnwrapped. I noted that it doesn't work with arrays, but I am trying the objectMapper.configure(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS, true) configuration in the main method used to get the values.
public class Award {
#JsonProperty("AwardID")
private String awardId;
#JsonProperty("AwardTitle")
private String awardTitle;
#JsonUnwrapped
private Effort effort;
}
public class Effort {
private String personFirstName;
private String personLastName;
}
Note that I only expect one value in the Effort array from the API response at this time.
What is recommended to try next? Thank you!
The easiest way is having a List<Effort> if you have a JSON Array.
If there is always 1 item for Effort, the returning JSON should not have Effort as a JSON Array and instead should be a JSON Object.
But if you can only handle it codewise, you can have something like this (Note that there should always contain one item in Effort, otherwise it will throw Exception):
public class Award {
#JsonProperty("AwardID")
private String awardId;
#JsonProperty("AwardTitle")
private String awardTitle;
#JsonProperty("Effort")
private Effort effort;
}
public class Effort {
#JsonProperty("PersonFirstName")
private String personFirstName;
#JsonProperty("PersonLastName")
private String personLastName;
}
And your ObjectMapper needs to be enabled with DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS as well:
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);
Award award = mapper.readValue(rawJson, Award.class); // rawJson is your JSON String
And it should have the following output:
Award(awardId=1111111, awardTitle=Test Title, effort=Effort(personFirstName=Jon, personLastName=Snow))
Note that the annotation #JsonUnwrapped can only apply on JSON Object, not JSON Array:
Value is serialized as JSON Object (can not unwrap JSON arrays using this mechanism)

How to use dynamic json value on my POJO class with Gson?

{
"localeCode": "",
"map": {
"DynamicName1": [],
"DynamicName2": [
{
"date": "2016-05-15T00:00:00",
"seqId": 1,
"status": 10
},
{
"date": "2016-05-16T00:00:00",
"seqId": 83,
"status": 10
}
],
"DynamicName3": [],
"DynamicName4": []
},
"respCode": 100,
"respMsg": "success",
"status": 1
}
How to correctly map this kind of json. If you can see that, Dynamic is a dynamic name. So far I have done this :
public class MapModel {
public MapObject map;
public static class MapObject{
public java.util.Map<String, Student> queryStudent;
public static class Student{
public String date;
public String seqId;
public String status;
}
}
}
But when run the app. I'm getting NullPointerException. Can somebody help me?
You're getting the NullPointerException accessing queryStudent of your MapObject inside your MapModel since it's not correctly filled when you're trying to deserialize your Json.
So to solve your problem look at Gson documentation where you can see:
You can serialize the collection with Gson without doing anything
specific: toJson(collection) would write out the desired output.
However, deserialization with fromJson(json, Collection.class) will
not work since Gson has no way of knowing how to map the input to the
types. Gson requires that you provide a genericised version of
collection type in fromJson(). So, you have three options:
Use Gson's parser API (low-level streaming parser or the DOM parser
JsonParser) to parse the array elements and then use Gson.fromJson()
on each of the array elements.This is the preferred approach. Here is
an example that demonstrates how to do this.
Register a type adapter for Collection.class that looks at each of the
array members and maps them to appropriate objects. The disadvantage
of this approach is that it will screw up deserialization of other
collection types in Gson.
Register a type adapter for MyCollectionMemberType and use fromJson()
with Collection.
Since your MapObject containts a java.util.Map but your class itself it's not generic, I think that a good approach for your case is create a Deserializer.
Before this try to clean up your class definition, to provide constructors to make the deserializer easy to build. Your POJO classes could be:
Student class
public class Student{
public String date;
public String seqId;
public String status;
public Student(String date, String seqId, String status){
this.date = date;
this.seqId = seqId;
this.status = status;
}
}
MapObject class
Note: I change you Map definition, since in your Json seems that could be multiple students for each DynamicName (look at DynamicName2 from your question), so I use Map<String,List<Student>> instead of Map<String,Student>:
public class MapObject{
public Map<String,List<Student>> queryStudent;
public MapObject(Map<String,List<Student>> value){
this.queryStudent = value;
}
}
MapModel class
public class MapModel {
public MapObject map;
}
Now create a Deserializer for your MapObject:
public class MapObjectDeserializer implements JsonDeserializer<MapObject> {
public MapObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
Map<String,List<Student>> queryStudents = new HashMap<String,List<Student>>();
// for each DynamicElement...
for (Map.Entry<String,JsonElement> entry : json.getAsJsonObject().entrySet()) {
List<Student> students = new ArrayList<Student>();
// each dynamicElement has an Array so convert and add an student
// for each array entry
for(JsonElement elem : entry.getValue().getAsJsonArray()){
students.add(new Gson().fromJson(elem,Student.class));
}
// put the dinamic name and student on the map
queryStudents.put(entry.getKey(),students);
}
// finally create the mapObject
return new MapObject(queryStudents);
}
}
Finally register the Deserializer and parse your Json:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(MapObject.class, new MapObjectDeserializer());
Gson gson = builder.create();
MapModel object = gson.fromJson(YourJson,MapModel.class);
DISCLAIMER: For fast prototyping I test this using groovy, I try to keep the Java syntax but I can forget something, anyway I think that this can put you on the right direction.
Hope it helps,

Parse JSON without object name in Java

I am trying to parse this JSON which is coming as the response to a REST API call. Can you please help me parsing it as key value pairs?
The object names are not present. There is nesting as well. There seems to be no new line between records.
The aim is to extract this data and load it into a database.
[
{
"cc_emails":["feedback#xyz.com"],
"fwd_emails":[],
"reply_cc_emails":["feedback#xyz.com"],
"fr_escalated":false,
"spam":false,
"email_config_id":6000038087,
"group_id":6000110481,
"priority":1,
"requester_id":6010410791,
"responder_id":6002817857,
"source":1,
"company_id":null,
"status":2,
"subject":"fare",
"to_emails":["feedback#xyz.com"],
"product_id":null,
"id":45043,
"type":null,
"due_by":"2016-03-12T08:58:02Z",
"fr_due_by":"2016-03-08T08:58:02Z",
"is_escalated":false,
"description":"Dear xyze Team,\r\n\r\nWhy r u increased fair again and againasas0mail.gmail.com</a>.<br>\n",
"custom_fields":
{
"category":null,
"issue":null,
"route_id":null,
"phone_number":null,
"department":null,
"booking_id":null
},
"created_at":"2016-03-07T08:58:02Z",
"updated_at":"2016-03-07T08:58:03Z",
// ...... repeat
}
]
The best way to do this would be to use http://www.jsonschema2pojo.org/
Enter your json there
Change source type to JSON
set the correct class name and package.
The resulting pojo can be directly mapped from the json
If you are using resttemplate to hit the api then you can use getForObject to automatically set the pojo from the output.
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject-java.lang.String-java.lang.Class-java.lang.Object...-
Using gson you can do this quite simply.
Do a class to match the fields in the json something like:
public class Example {
private List<String> cc_emails;
private List<String> fwd_emails;
private List<String> reply_cc_emails;
private Boolean fr_escalated;
private Boolean spam;
private Integer email_config_id;
...
private CustomFields custom_fields;
private String created_at;
private String updated_at;
}
Then you need to do another to map the custom fields
public class CustomFields {
private String category;
...
}
And using json you can parse it like this:
Type type = new TypeToken<Collection<Example>>(){}.getType();
new Gson().fromJson(json,type);
You have to exaplain to Gson it's a list, if it was a single object it would be this:
new Gson().fromJson(json,Example.class);
This is the aproach I usually take, also in the dates java.sql.Timestamp class might also parse it, you would need to try it though.
You can use Gson (https://github.com/google/gson) or Jackson (https://github.com/FasterXML/jackson) and deserialize it to a Map.

Deserialize an array of objects with Gson

I know how to deserialize normal JSON object with "Gson" library but I am facing problem to deserialize an JSON array with several JSON object and arrays. I am trying to get the time in the arrival_time JSON object in this simple below but I don't know how to structure my class to accomplish that. Can someone explain me how to do that?
Simple:
[{"route": 1,
"info": [
{"direction": "Surrey Quays"},
{"stops": [{"stops_name": " Tenison Way"},
{"arrival_time":{
"mon-fri": [ "05:38", "06:07","06:37"],
"sat": ["05:34","06:01","06:31"],
"son": ["06:02","06:34","07:04"]
}
}
]
}
]
}]
You can parse this Json using following structure:
class ArrivalTime {
public List<String> mon_fri;
public List<String> sat;
public List<String> son;
}
class Stop {
public String stop_name;
public ArrivalTime arrival_time;
}
class Info {
public String direction;
public List<Stop> stops;
}
class RouteInfo {
public Integer route;
public List<Info> info;
}
and then use it like this:
Gson gson = new Gson();
RouteInfo[] routes = gson.fromJson(/* your json string*/, RouteInfo[].class);
Arrival times will be available at something like this (it is ugly but I just want you to present the sample structure for this json string):
System.out.println(routes[0].info.get(1).stops.get(1).arrival_time.sat.get(0));
To learn the structure you could use a javascript object or a online builder.
http://www.jsonschema2pojo.org/

Deserializing a JSON-collection(potentially with another collection) of objects in GSON

I've been fighting with JSON parsing using GSON today and a lot of things went well with a minimum amount of hassle.
Though, for the following JSON string I started running into some issues;
{"success":1,"response":{"dvds":{"IronMan":{"rating":"awesome"},"BatMan":{"rating":"awesome"},"Smurfs":{"rating":"childish"}}}}
In this JSON I have a collection "response" containing a collection of responsetypes. In the example the only responsetype included is dvds.
But my issue lies here; I wish to have every child of "dvds" to be parsed to a List response , each child being a single Dvd-class object (containing a String "title" and a String "rating")
Thus far parsing seperate values/objects and parsing arrays went with no real issues, but I can't wrap my head around how to solve parsing such collections.
googling today kept referencing me to "TypeTokens" but looking at the code in various topics regarding this issue, I still haven't understood how to implement it for my use-scenario at all.
So, to be concrete;
"How can I make GSON correctly recognize both my responsetype and dvd-collections?"
Currently my ResponseData.class looks like this:
public class ResponseData {
public int success;
public List<ResponseTypes> responsetypes;
public class ResponseType{
public List<Dvd> Dvds;
}
public class Dvd{
public String title;
public String rating;
}
}
That's how i'd look at this problem in an array-based form, but this time i need to apply it in the case i run into a collection of objects instead. in all scenarios i can think of the Class of the object should be able to be recognized by the name of it's parent.
Currently the parsing is initiated as follows;
try{
Gson gson = new Gson();
Reader reader = new InputStreamReader(stream);
ResponseData responsedata = gson.fromJson(reader, ResponseData.class);
return responsedata;
}
I really hope someone can help me out! Thanks!
you have here some problems:
the class ResponseData should hold List<ResponseType> and not List<ResponseTypes>
the json that you supplied isnt matching the classes above.
an accurate classes for this json are:
public class ResponseData
{
public int success;
public Map<String, Map<String, Dvd>> response;
public class Dvd
{
public String rating;
}
}
in order to describe a list in json you should use: "[ ]". for example: [1,2,3]. you can read more about json here
if you want the json to describe the class hierarchy you describe above. it should looks like:
{"success":1,"responseTypes":[{"Dvds":[{"title":"IronMan","rating":"awesome"},{"title": "BatMan", "rating":"awesome"},{"title":"Smurfs", "rating":"childish"}]}]}
notice that unless you declare a mapping between the variable names and the json varible names then you should use the same names. for example "Dvds" and "responseTypes"

Categories