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>
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'm fetching product types from api using retrofit and gson as the default converter. Problem is the JSON response is not same as the expected value. One field is always null. The field is named banner which is an image url.
The model class looks like this:
public class ProductType {
#SerializedName("id")
#Expose
private String id;
#SerializedName("created_at")
#Expose
private Date createdAt;
#SerializedName("name")
#Expose
private String name;
#SerializedName("description")
#Expose
private String description;
#SerializedName("banner")
#Expose
private String banner;
//getter and setters
The expected results is:
{
"id": "c9f32ed3-877a-4140-97c4-b0982",
"created_at": "2018-09-20T18:49:59.044682+03:00",
"name": "Events",
"description": "",
"banner": "https://my-server-url/types/banners/c9f32ed3-877a-4140-97c4-b0982/98673e1e-d1c0-9d2e165159dc.jpg"
}
Retrofit returns the following response:
{
"id": "c9f32ed3-877a-4140-97c4-b0982",
"created_at": "2018-11-06T10:46:48.552284+03:00",
"name": "Events",
"description": "",
"banner": null
}
Is there anything wrong with with the image Url since other fields are parsed well?
I have tried to use moshi converter but it did not work. Any ideas would help. Thanks
I'm a newbie in Retrofit. How to parse the Json below using retrofit?
{
"data": {
"Aatrox": {
"id": 266,
"title": "a Espada Darkin",
"name": "Aatrox",
"key": "Aatrox"
},
"Thresh": {
"id": 412,
"title": "o GuardiĆ£o das Correntes",
"name": "Thresh",
"key": "Thresh"
}
},
"type":"champion",
"version":"6.23.1"
}
You could make your model POJO contain a Map<String, Champion> to deserialize into, to deal with the dynamic keys.
Example:
public class ChampionData {
public Map<String, Champion> data;
public String type;
public String version;
}
public class Champion {
public int id;
public String title;
public String name;
public String key;
}
I'm not familiar with Retrofit besides that, but as someone in the comments said, the deserializing is done by Gson:
public ChampionData champions = new Gson().fromJson(json, ChampionData.class);
So to build on to the answer someone else posted, you can then do the following, assuming you've added the GsonConverterFactory:
public interface API {
#GET("path/to/endpoint")
Call<ChampionData> getChampionData();
}
Assuming Retrofit2, the first thing you need to do is call following when building your Retrofit instance.
addConverterFactory(GsonConverterFactory.create())
Then it's just a matter of writing a POJO (e.g. MyPojoClass) that maps to the json and then adding something like following to your Retrofit interface.
Call<MyPojoClass> makeRequest(<some params>);
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.
I've been using Retrofit library recently and I like it so far. However, I've come across API that returns response with the following structure:
"data":
{
"meta":
{
"code": 200
"data": "data"
},
"body": [
{
"id": "id",
"field1": "data",
"field2": "data"
},
{
"id": "id",
"field1": "data",
"field2": "data"
}]
}
Assuming I have following class:
public class Entity {
long id;
String field1;
String field2;
}
and following interface:
public interface EntityService {
#GET("/api/method")
void getEntities(Callback<List<Entity>> callback);
}
what is the correct way to use Retrofit if I want to get a list of Entity objects from data.body element from response? I know I could have passed Response object in the callback and manually parse it using org.json package or something else, but is there any better way?
Why not just make a class that represents the data like you've already half done? That's what I've done in multiple apps along with other developers:
public class Meta {
String code;
String data;
}
public class Data {
Meta meta;
List<Entity> body;
}
public interface EntityService {
#GET("/api/method")
void getEntities(Callback<Data> callback);
}
It seems that extra data in your result could be re-used. You should use a generic class like this one:
public class Data<E> {
Meta meta;
E body;
public static class Meta {
int code;
String data;
}
}
Then you could use
Data<List<Entity>>
or whatever you want:
public interface EntityService {
#GET("/api/method")
void getEntities(Callback<Data<List<Entity>>> callback);
}