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"
Related
I'm trying to figure out a way to selectively de-serialize specific fields from flickr.
{"photos":{"page":1,"pages":10,"perpage":100,"total":1000,"photo":[{"id":"","owner":"","secret":"","server":"","farm":,"title":"","ispublic":,"isfriend":,"isfamily":0,"url_s":"","height_s":"","width_s":""},...]}
I receive an object that contains two lists (photos and photo) and i would like to model in Java only the id, url_s and title from photo.
I figured out that I can create my java module with #expose annotation for the fields i'm interested in and than use
builder.excludeFieldsWithoutExposeAnnotation();
this way I'll control which fields get deserialized from photo (still not sure it's gonne work that way), but what about photos?
My questions are:
Is there a way to ignore that list? do I have to model a Java class that contains two lists (with their respective fields) just to grab what I need from the second list?
expanding upon the former question, if my module class for photo is:
public class GalleryItem {
#Expose()
private String mCaption;
#Expose()
private String mId;
#Expose()
private String mUrl;
}
can i call gson only on the part i need?
Type galleryListType = new TypeToken<ArrayList<GalleryItems>> (){}.getType();
List<GalleryItems> itemsList = gson.fromJson(jsonString, galleryListType);
can I somehow use setExclusionStrategies to skip the Photos list?
gsonBuilder.setExclusionStrategies(new ExclusionStrategy() {
#Override
public boolean shouldSkipField(FieldAttributes f) {
**return f.getName().contains("photos")**;
}
#Override
public boolean shouldSkipClass(Class<?> incomingClass) {
return ;
}
});
I've already implemented a solution using raw JSONObject/JSONArray but I'm curious regarding using GSON for the task at hand.
Thanks in advance!
Gson provides deserialisation on Java fields. If you mark as a transient your variable, Gson will not serialised to JSON. Gson also provides finer deserialisation control via annotations: #Expose(deserialize = false/true)
The last option would be writing your custom JsonDeserializer<T>
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.
I receive from server a response in this form
{"error":null,"id":1,"result":
{"admin":false,
"firstname":"Jason",
"id":346,"idHotel":109,
"idVendor":null,
"lastname":"Butcher",
"sessionkey":"3c8a17ae47a6d131b1a14b44a1d8f9a9",
"urlAvatar":"avatar_316_mjm.jpg",
"urlThumb":"thumb_316_mjm.jpg"}
}
And want to get the various singles attributes,
for example
Boolean error=..;
String admin=....;
String idHotel=...;
and also the images
You should create a wrapper class like this:
public class Response {
public boolean error;
public int id;
public Result result;
}
public class Result {
...
}
then is simple for you to deserialize the json via gson to you classes:
Response response = new Response();
Gson gson = new Gson();
response = gson.fromJson(response, Response.class);
And there's a lot of other nifty things you can do: https://sites.google.com/site/gson/gson-user-guide
Oh forgot one important thing!
Remember to change the namespace on the Gson library, I had problems get it running on htc telephones. You can do this with jar jar links: http://code.google.com/p/jarjar/downloads/list
docs: http://code.google.com/p/jarjar/wiki/CommandLineDocs
I am using Play Framework 1.2.4 with Java and using JPA to persist my database objects. I have several Model classes to be rendered as JSON. But the problem is I would like to customize these JSON responses and simplify the objects just before rendering as JSON.
For instance, assume that I have an object named ComplexClass and having properties id, name, property1,...,propertyN. In JSON response I would like to render only id and name fields.
What is the most elegant way of doing this? Writing custom binder objects or is there simple JSON mapping such as using a template?
Play Framework 1.2.4 directly depends on the gson library so you could use that to render your JSON strings. All you have to do is use gson's #Expose annotation. So in your example, you would mark the fields you want in your JSON string like this:
public class ComplexClass {
#Expose
public Long id;
#Expose
public String name;
...
}
Then in your controller, you would just do this:
public static void someActionMethod() {
// get an instance of your ComplexClass here
ComplexClass complex = ...
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
String json = gson.toJson(complex);
renderJson(json);
}
See documentation here.
If ComplexClass is actually a play.db.jpa.Model and therefore the id field is abstracted away in a parent class and you can't put the #Expose annotation on it, then you could create your own ExclusionStrategy that skips fields that aren't annotated with #Expose and are not called id. So something like this (pseudo-code):
public final class ComplexClassExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipField(FieldAttributes attributes) {
if (name of field is "id") return false;
if (field is annotated with #Expose) return false;
return true;
}
Then the controller would altered slightly to look like this:
GsonBuilder builder = new GsonBuilder();
ComplexClassExclusionStrategy strategy = new ComplexClassExclusionStrategy();
builder.setExclusionStrategies(strategy);
Gson gson = builder.create();
String json = gson.toJson(complex);
renderJson(json);
Use FlexJSON, it's really easy. It allows you to create JSONSerializers which can include/exclude the fields you want.
Check out this article for some examples of using it with Play! Framework.
Here's a simple example:
public ComplexClass {
public Long id;
public String name;
// And lots of other fields you don't want
public String toJsonString() {
// Include id & name, exclude all others.
JSONSerializer ser = new JSONSerializer().include(
"id",
"name",
).exclude("*");
return ser.serialize(this);
}
}
You can add it to your dependencies.yml like so:
require:
- play
- net.sf.flexjson -> flexjson 2.1
What I usually do is write an interface for models that implements a toJSONString() method so that I can call renderJSON(someModel.toJSONString()) in the controller.
Link to official website
EDIT: Extra example for lists/collections
Ok, when you start serializing list you might get some unexpected results. This is because the order of evaluation is important. The first include() or exclude() takes precedence over the following ones.
Here's an example of serializing the childs of a parent entity (OneToMany relation).
JSONSerializer ser = new JSONSerializer();
// Exclude these standard fields from childs
ser.exclude(
"*.persistent",
"*.class",
"*.entityId"
);
// Include childs and all its other fields
ser.include(
"childs",
"childs.*"
);
// Exclude everything else
ser.exclude("*");
String data = ser.serialize(parent);
The * is a wildcard by the way. This piece of documentation explains it perfectly:
An exclude of *.class will match to any path depth. So if flexjson is serializing the field with path of "foo.bar.class" the * in *.class will match foo.bar.
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.