Sending ArrayList<Object> POST request with Retrofit - android

I want to send something like this to server
{
"InoorPersonID": "",
"Discount": 0,
"DiscountDescription": "",
"Description": "",
"OrderDetailList": [
{
"ProductID": 0,
"Amount": 0
}
],
"ClientId": "",
"ClientSecret": ""
}
and this is my service interface
public interface StoreRetrofitSalesService {
#FormUrlEncoded
#POST(ServiceUrl.URL_ORDER_SET)
Call<ServiceResult<Integer>> orderSet(#Field("OrderDetailList") ArrayList<OrderDetail> orderDetails,
#Field("Discount") String discount,
#Field("ClientId") String clientId,
#Field("ClientSecret") String clientSecret,
#Field("Description") String description,
#Field("InoorPersonID") String inoorPersonId,
#Field("DiscountDescription") String discountDescription);
}
The logcat show this
OrderDetailList=org.crcis.noorreader.store.OrderDetail%408208296&Discount=0&...
I have two question:
Why OrderDetailList can't convert to JSON.
How can I use #FieldMap for this params.
I recently test Map<String, Object> but it returns same result.
Thanks

Use GSON
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(myBaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
Create a model for your data like this
public class Order {
#SerializedName("InoorPersonID")
String inoorPersonId;
#SerializedName("Discount")
int discount;
#SerializedName("DiscountDescription")
String discountDescription;
#SerializedName("Description")
String description;
#SerializedName("OrderDetailList")
ArrayList<OrderDetail> orderDetailList;
#SerializedName("ClientId")
String clientId;
#SerializedName("ClientSecret")
String clientSecret;
//Don't forget to create/generate the getter and setter
}
And change your Service to
public interface StoreRetrofitSalesService {
#POST(ServiceUrl.URL_ORDER_SET)
Call<ServiceResult<Integer>> orderSet(#Body Order order);
}

Related

How to handle json response using retrofit if json field type changed dynamically

I am using retrofit 2 for parsing api.
For some responses it is done successfully but for some it stops and showing error
com.google.gson.JsonSyntaxException: java.lang.NumberFormatException:
Invalid double: ""
Response which parses successfully is:
{
"post_list": [{
"like_count": "1",
"like_id": 47,
"like_user_id": 24,
"like_full_name": "Zika zika",
"like_full_image": "http:\/\/graph.facebook.com\/123456789\/picture?type=large",
"comment_count": 7,
"comment_id": 235,
"comment_text": "Xhhc",
"comment_user_id": 22,
"comment_full_name": "Azz Sha",
"comment_full_image": "http:\/\/demo.net\/apps\/demo\/web\/img\/uploads\/abc.jpg"
}],
"is_last": "N",
"code": 200,
"status": "Success"
}
And the one with failure is:
{
"post_list": [{
"like_count": "0",
"like_id": "",
"like_text": "",
"like_user_id": "",
"like_full_name": "",
"like_full_image": "",
"comment_count": 0,
"comment_id": "",
"comment_text": "",
"comment_user_id": "",
"comment_full_name": "",
"comment_full_image": ""
}],
"is_last": "N",
"code": 200,
"status": "Success"
}
And PostList class:
#SerializedName("like_count")
private String likeCount;
#SerializedName("like_id")
private Integer likeId;
#SerializedName("like_user_id")
private Integer likeUserId;
#SerializedName("like_full_name")
private String likeText;
#SerializedName("like_text")
private String likeFullName;
#SerializedName("like_full_image")
private String likeFullImage;
#SerializedName("comment_count")
private Integer commentCount;
#SerializedName("comment_id")
private String commentId;
#SerializedName("comment_text")
private String commentText;
#SerializedName("comment_user_id")
private String commentUserId;
#SerializedName("comment_full_name")
private String commentFullName;
#SerializedName("comment_full_image")
private String commentFullImage;
//getter setters
I don't understand retrofit a much but I tried using this class as de-serializer, with reference of this but still no luck.
public class TimelineDeserializer implements JsonDeserializer<PostList> {
#Override
public PostList deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Gson gson = new Gson();
PostList postList=gson.fromJson(json, PostList.class);
final JsonObject jsonObject = json.getAsJsonObject();
if(postList.getLikeCount().equals("0")){
final int likeId=jsonObject.get("like_id").getAsInt();
final int likeUserID=jsonObject.get("like_user_id").getAsInt();
postList.setLikeId(likeId);
postList.setLikeUserId(likeUserID);
}
return postList;
}
}
For initializing retrofit:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(PostList.class, new TimelineDeserializer());
Gson gson = new GsonBuilder()
.setLenient()
.create();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson)).build();
I am getting the response body in log but then onFailure method is encountered.
Not getting how to do this. Can anything be done instead of changing that in backend? Help appreciate!
It seems that you define likeUserId and likeUserId as Integer. However, in the JSON, like_id and like_user_id are "" which is String instead of Integer.
Instead of using this ("").. you can also go with likeUserId=null and before fetching the values.. check for null value..
After getting help from commentators I found that such responses cannot be handled with this kind of library which uses reflection to assign values.
Because the server might provide invalid json all together, it is actually invalid json since the server is breaking its own schema. It may be done with a workaround somehow, but that is not a good aim.
So, I ended up using another library for parsing this response.

PUT method in Retrofit 2.0 returns null body

How to use properly PUT method with x-www-form-urlencoded? In Postman everything works fine, but in Android App it doesn't.
My interface:
#FormUrlEncoded
#PUT(ApiConstants.REGISTER_URL_PART)
Call<RegisterModel> getStatus(
#Field("username") String username,
#Field("email") String email,
#Field("password") String password,
#Field("fbID") String fbID,
#Field("gmailID") String gmailID,
#Field("twitID") String twitID,
#Field("gender") String gender,
#Field("birthDate") String birthDate,
#Field("location") String location,
#Field("longitude") String longitude,
#Field("latitude") String latitude,
#Field("profileImage") String profileImage
);
Factory class:
class Factory {
private static AuthRegisterUserApi service;
public static AuthRegisterUserApi getInstance() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ApiConstants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
service = retrofit.create(AuthRegisterUserApi.class);
return service;
}
}
Request example:
{
"username": "new_User",
"email": "some#user.com",
"password": "qwerty123",
"gender": "female",
"birthDate": "1999-12-23",
"location": "Cracov",
}
In app throwing code 400 or 500... Any idea how to corectly implement this PUT method into my app?

Retrofit List of object assigns null to data

This is how my JSON response looks
[
{
"id": 1,
"PhName": "sample string 2",
"Longitude": 3.1,
"Latitude": 4.1,
"ApplicationUserId": "sample string 5"
},
{
"id": 1,
"PhName": "sample string 2",
"Longitude": 3.1,
"Latitude": 4.1,
"ApplicationUserId": "sample string 5"
}
]
this is my retrofit interface call
#GET("/api/GPS")
#Headers({
"Accept: application/json"
})
Call<List<UserResponse>> search(#Query("search") String search,
#Header("Authorization") String auth);
Pojo Class
public class UserResponse {
#SerializedName("Id")
int id;
#SerializedName("UserName")
String phName;
#SerializedName("Longitude")
int lon;
#SerializedName("Latitude")
int lat;
#SerializedName("ApplicationUserId")
String appUserId;
//getters and setters
}
Retrofit declaration
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(PerformLogin.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
Getting data and using it
MyApiEndpointInterface apiService =
retrofit.create(MyApiEndpointInterface.class);
Call<List<UserResponse>> call = apiService.search(query,"Bearer "+token);
call.enqueue(new Callback<List<UserResponse>>() {
#Override
public void onResponse(Call<List<UserResponse>> call, Response<List<UserResponse>> response) {
List<UserResponse> userList = response.body();
Log.w("My App", response.message());
for (int i = 0; i <userList.size() ; i++) {
Log.w("My App", userList.get(i).getPhName()+""+i);
}
//mAdapter = new MyAdapter(getContext(),userList);
//mRecyclerView.setAdapter(mAdapter);
}
#Override
public void onFailure(Call<List<UserResponse>> call, Throwable t) {
Log.w("My App", t.getMessage());
}
});
my response
W/My App: OK
W/My App: null 0
W/My App: null 1
W/My App: null 2
W/My App: null 3
In this case I am suppose to receive four result from the search and the names are giving me null.
Is there anything I am doing wrong or a better solution to this?
You are using wrong serialize name. You are trying to assign value from node UserName to phName, which is not available. So, you are getting null.
Change
#SerializedName("UserName")
String phName;
with
#SerializedName("PhName") // change this
String phName;
Also, #SerializedName("Id") should be #SerializedName("id"). It's case sensitive.
Your SerializedName fields and the JSON fields don't match.
JSON: id -> GSON: Id
JSON: PhName -> GSON: UserName
Those two don't add up. You have to alter your annotations accordingly:
#SerializedName("id")
int id;
#SerializedName("PhName")
String phName;

How do I get a foreign key's field using Retrofit and Gson?

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.

Retrofit map json variable to keyword

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.

Categories

Resources