I am new to Android development and learning how to use Retrofit and I am having a hard time to deal with inconsistency response from the server.
There are more than two kinds of responses will be returned from the server.
May I know how to deal with this kind of server response? Should I create different data class to handle it based on the server response?
Server Response
Result - Success
{
"status": true,
"result": {
"id": 1,
"name": "User",
"email": "user#gmail.com"
}
}
Result - Fail
{
"status": false,
"result": []
}
Android Model
public class User implements Serializable {
private boolean status;
private ResultModel result;
public static class ResultModel implements Serializable{
private String id;
private String name;
private String email;
}
}
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 have a web service for registration. and i have a success response for response code 200 like this
{
"data": {
"email": "azadbar#yahoo.com"
},
"code": 201,
"success": true
}
and i have error response with code 422 like this
{
"message": "The given data was invalid.",
"errors": {
"email": [
"The email has already been taken."
]
}
}
but when also i have problem with password the response error show me like this
{
"message": "The given data was invalid.",
"errors": {
"email": [
"The email must be a valid email address."
],
"password": [
"The password must be at least 6 characters.",
"The password confirmation does not match."
]
}
}
the problem is some field some time show and some time is gone. and also we have some response model and in retrofit interface we should only have One response like RegisterResponse in below sample
#POST("/api/v1/register")
Call<RegisterResponse> register(#Body RegisterRequest request);
how can i handle this response?
You need to create a pojo that means a model class of name RegisterResponse that will have the properties that you are getting in your JSON response. So, according to your example case, it would be like :
Class RegisterResponse{
private Data data;
private String code;
private Boolean success;
private String message;
private Error errors;
}
Class Data{
private String email;
}
Class Error{
private List<String> email;
private List<String> password;
}
Now inside every class, you need to create the getter and setter for every properties that you have included.
So when the response comes then handle it accordingly that mean if it comes null, set the property to null else set the received value for the respective property
You need to make a model with all possible fields and depending on result some will be filled or null.
class Model{
private Data data;
private int code;
private boolean success;
private Errors errors;
private String message;
public isSuccess(){
return success;
}
....
}
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'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.