I am having problems deserializing a custom object using gson.
I have this class:
public class Content implements java.io.Serializable {
private Long id;
private int tipo;
private String title;
private String content;
private Integer reward;
/** Not-null value. */
private String imageUrl;
private String bannerUrl;
private String logoUrl;
/** Not-null value. */
private String actionUrl;
private Integer templateType;
private String expiresAt;
private Integer unlockReward;
private Integer reportType;
private String completionType;
private Integer interactionType;
private Integer productId;
private Integer views;
private Boolean saved;
private Double weight;
/** Used to resolve relations */
private transient DaoSession daoSession;
/** Used for active entity operations. */
private transient ContentDao myDao;
private List<Rule> ruleList;
private List<Category> categoryList;
...
// all getters and setters code
...
}
What I want is to deserialize the categoryList using a custom adapter. I created one using the following code:
Type typeOfListOfCategory = new com.google.gson.reflect.TypeToken<List<Category>>(){}.getType();
builder.registerTypeAdapter(typeOfListOfCategory, new JsonDeserializer<List<Category>>() {
#Override
public List<Category> deserialize(JsonElement element, Type type,
JsonDeserializationContext context) throws JsonParseException {
// my code goes in here
}
});
Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
And then I used it on a rest adapter
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("http://localhost/api")
.setConverter(new GsonConverter(gson)).build();
But my custom adapter is never called.
The json that I am receiving is like this:
[
{
"id": 1,
"tipo": 1,
"title": "title",
"content": "content",
"reward": 2.0,
"image_url": "url1",
"banner_url": "url2",
"logo_url": "url3",
"action_url": "url4",
"template_type": 0,
"expires_at": "2014-08-31T00:00:00.000Z",
"unlock_reward": 2,
"report_type": 0,
"completion_type": 0,
"rules": [
{
"range": "1",
"operator": "==",
"key": "key1"
}
],
"categories": [
{
"description": "description"
}
]
},
...
]
Any ideas?
If you are not using annotation to tag the Name of the JSON field, your field name should match the JSON field name. Like list of List<Rule> ruleList in your java class should be List<Rule> rules since the list name in JSON is rules. Cross check all the field names.
This is just my guess because you just said you have problem in deserializing which is very very vague term. If this solution does not work, post your error message by updating your question.
Related
I have a nested JSON object, for example :
{
"references": [
"CONTRACT",
"DURATION",
"EDUCATIONLEVEL",
"EXPERIENCELEVEL",
"LANGUAGELEVEL",
"CIVILITY",
"AVAILABILITY"
],
"unavailablenetworks": [
{
"content": "Service unavailable",
"id": "100"
},
{
"content": "Service unavailable",
"id": "200"
}
],
"urls": {
"apiurl": "https://xxxxxxxxxxx",
"base": "https://yyyyyyyyyyyyyy",
"video": "https://zzzzzzzzzzzzz"
}
}
and the following Java classes :
public class Version implements Serializable {
#SerializedName("references")
private List<String> references;
#SerializedName("unavailablenetworks")
private List<UnavailableNetwork> unavailableNetworks;
#SerializedName("urls")
private BKUrls urls;
}
public class BKUrls implements Serializable {
#SerializedName("apiurl")
private String api;
#SerializedName("base")
private String base;
#SerializedName("video")
private String video;
#SerializedName("edition")
private String edition;
#SerializedName("offer")
private String offer;
#SerializedName("search")
private String search;
}
public class UnavailableNetwork implements Serializable {
#SerializedName("content")
private String content;
#SerializedName("id")
private String id;
}
Getter and Setter methods are omitted here to simplify reading.
I use GSON to parse the JSON :
Gson g = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
Version version = g.fromJson(json.toString(), Version.class);
This code is using in an Android application that I'm developping.
If I install and run the application on an Android Smartphone in debug mode using Android Studio, Gson parses the Json Object correctly.
But If I try to generate an apk and then, install that apk on the same smartphone, Gson does not parse the JSON entirely. The result is like this :
{
"references": [
"CONTRACT",
"DURATION",
"EDUCATIONLEVEL",
"EXPERIENCELEVEL",
"LANGUAGELEVEL",
"CIVILITY",
"AVAILABILITY"
],
"unavailablenetworks": [
{
"id": "100"
},
{
"id": "200"
}
],
"urls": {
}
}
"references" is ok
"unavailablenetworks" is incomplete, missing "content" field
"urls" is empty
I don't understand why Gson doesn't work the same ? Why some data are missing using apk while using Android Studio in debug mode all data are ok ?
I want to save the following JSON from an online API directly to Realm using Retrofit. I am struggling to define the model because there are no keys and the values are dynamic.
JSON:
{
"Plants": {
"Green": [
"Ascia",
"Musca Arabica"
...
],
"Yellow": [
"Campona",
"Zirata",
...
],
...
}
}
Is this even doable? I know I can use a Map<String, Map<String, Set<String>>>, but makeing the Realm model is causing me trouble.
You could flatten it completely.
public class Data extends RealmObject {
#PrimaryKey
private String typeCategoryName; // "Plants_Green_Ascia"
#Index
private String type; // "Plants"
#Index
private String category; // "Green"
private String name; // "Ascia"
}
Then you could query it like
RealmResults<Data> data = realm.where(Data.class)
.equalTo("type", "Plants")
.equalTo("category", "Green")
.findAll();
I'm trying to parse a JSON object using retrofit 2.0 following this guide, but it doesn't work. I think it's because of a difference in JSON format.
Here is a nested JSON object with the format:
{
"SearchService": {
"list_total_count": 531,
"RESULT": {
"CODE": "INFO-001",
"MESSAGE": "SUCCESS"
},
"row": [{
"ID": "1983",
"NAME": "SAN",
"NUM": "38",
}, {
"ID": "1984",
"NAME": "DU",
"NUM": "27",
}]
}
}
Here is class code using SerializedName:
RowList.java
public class RowList {
#SerializedName("row")
#Expose
private ArrayList<Row> rows= new ArrayList<>();
public ArrayList<Row> getRows() {
return rows;
}
public void setRows(ArrayList<Row> rows) {
this.rows= rows;
}
}
Row.java
public class Row{
#SerializedName("ID")
#Expose
private String id;
#SerializedName("NAME")
#Expose
private String name;
#SerializedName("NUM")
#Expose
private String num;
/*getter setter*/
}
Read that guide.
There are two approaches to create Model class. The first way is the manual approach, which requires you to learn how to use the Gson library. The second approach is you can also auto-generate the Java classes you need by capturing the JSON output and using jsonschema2pojo
Looks like you've attempted approach one, but haven't (yet?) tried reading over the Gson documentation.
Okay, you have a Row. That covers the objects within "row": [...], so you also need objects for the following:
"SearchService": {}
"RESULT": {}
I don't think the RowList class is necessary. List<Row> is fine.
For example,
class Result {
#SerializedName("CODE")
String code;
#SerializedName("MESSAGE")
String message;
}
class SearchService {
#SerializedName("list_total_count")
long count;
#SerializedName("RESULT")
Result result;
#SerializedName("row")
private ArrayList<Row> rows= new ArrayList<>();
}
(removed #Expose for conciseness)
Then, Retrofit would use Call<SearchService>
I have an api endpoint which outputs this json for an event table
{
"name": "",
"time": null,
"event_pic_url": null,
"description": "",
"event_type": null,
"invite_only": false,
"free": false,
"age_restriction": false,
"ticket_price": null,
"venue": null
}
The venue field is a foreign key to a Venue table that has this format.
{
"name": "",
"rating": null,
"longitude": null,
"latitude": null
}
After getting the list of events, I would like to get them on a recyclerview (I can already get the list and know how to use an adapter)but I don't want to show the venue's {id}, I want to use the venue's {name}. How do I do this? Is it related to how nested json is deserialized?
After all the comments I will assume that now you have something like:
{
"name": "",
"time": null,
"event_pic_url": null,
"description": "",
"event_type": null,
"invite_only": false,
"free": false,
"age_restriction": false,
"ticket_price": null,
"venue": {
"name": "",
"rating": null,
"longitude": null,
"latitude": null
}
}
Since you're using Gson, you'll want to have the following models
public class Venue {
#SerializedName("name")
#Expose
private String name;
#SerializedName("rating")
#Expose
private Integer rating;
#SerializedName("longitude")
#Expose
private Double longitude;
#SerializedName("latitude")
#Expose
private Double latitude;
// ...
}
public class Event {
#SerializedName("name")
#Expose
private String name;
#SerializedName("time")
#Expose
private String time;
#SerializedName("event_pic_url")
#Expose
private String eventPicUrl;
#SerializedName("description")
#Expose
private String description;
#SerializedName("event_type")
#Expose
private String eventType;
#SerializedName("invite_only")
#Expose
private Boolean inviteOnly;
#SerializedName("free")
#Expose
private Boolean free;
#SerializedName("age_restriction")
#Expose
private Boolean ageRestriction;
#SerializedName("ticket_price")
#Expose
private Double ticketPrice;
#SerializedName("venue")
#Expose
private Venue venue;
// ...
}
Please note that I'm assuming some data types here, i.e., for latitude and longitude as well as event_type. Since in the json they were null I couldn't really be sure, but I guess you can understand from this example. Also please add the appropriate getters and setters.
I want you to focus on the venue part. As you see I'm basically recreating the "nested" json part in Java objects. And that's just it, Gson and retrofit will do the rest for you. Here's how. A word of caution - This may vary a lot depending on how you're doing things. I prefer rxjava, but I'll use the callback approach here since it's easier to explain.
Retrofit 1.9 you can do:
public interface EventService {
#GET("/url/to/events/endpoint/")
public void get(Callback<Event> callback);
}
Provided everything goes well, on the success method of your callback you'll get an instance of Event where you can access the Venue object provided the returned json is actually the one above.
Retrofit 2 the interface changes a bit, but essentially it's the same idea as before:
public interface EventService {
#GET("/url/to/events/endpoint/")
public Call<Event> get();
}
Once you enqueue the request and define the Callback object you will also get an Event object in your success method that would have a reference to a venue. Here's how these callbacks might be implemented with Retrofit 2 (Might slightly change between retrofit versions. I don't fully remember):
eventService.get().enqueue(new Callback<Event>() {
#Override public void onResponse(Call<Event> call, Response<Event> response) {
if (!response.isSuccessful()) {
// Handle http error
return;
}
Event event = response.body();
Venue venue = event.getVenue();
// do something with it
}
#Override public void onFailure(Call<Event> call, Throwable t) {
// Handle error
}
});
}
Here eventService is an object created by Retrofit.create(EventService.class).
Again the retrofit bit might change depending which method you want to use. Important is to understand how you map from the json response to the java objects and basically you just need to replicate the same json structure but in java objects. Hope it helps.
So I'm working with retrofit with an API that has a variable called "public". How would I go about getting it to automatically map like all the other variables do.
Example:
#GET("/?filter=my_images")
void getMyImages(
#Query("client_id") String id,
#Query("api_key") String key,
Callback<ImageList> callback
);
public static class Image{
int id;
String name;
String distribution;
String slug;
// Can't do this:
boolean public;
}
public static class ImageList{
String status;
List<Image> images;
}
Example API results (json):
{
"status": "OK",
"images": [
{
"id": 1,
"name": "My first snapshot",
"distribution": "Ubuntu",
"slug": "ubuntu-12.10-x32",
"public": true
},
{
"id": 2,
"name": "Automated Backup",
"distribution": "Ubuntu"
}
]
}
Retrofit uses Gson for serialization to and from JSON.
Gson provides a #SerializedName annotation in order to change the key to which a field or method is mapped. You can use this for handling your reserved word:
#SerializedName("public")
public String isPublic;
Please look at this link, which is a neater solution if there are underscores in each key.