Retrofit List of object assigns null to data - android

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;

Related

Parsing unsuccessfully JSON Objects with retrofit2

I am using retrofit2 in my code with gson.
i can parse almost all needed, but when parsing a specific JSON, I have a problem.
This is the JSON:
{
"data": [
{
"id": "001",
"direccion": "Cascada 3",
"provincia": "Burgos"
},
{
"id": "002",
"direccion": "Lago 21",
"provincia": "Zamora"
}
]
}
I know that what I am going to write has been commented a lot but, please, read until the end
When parsing it shows this error:
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
If I delete the name of the object “data” from JSON, then I can parse it perfectly, like this:
[
{
"id": "001",
"direccion": "Cascada 3",
"provincia": "Burgos"
},
{
"id": "002",
"direccion": "Lago 21",
"provincia": "Zamora"
}
]
The JSON continues to open with an object, but it can be parsed perfectly.
This leads me to think that I am not indicating in the code how to parse the object called "data", I think the problem is that.
Tiendas.java (I use #serializedName for a possible solution that I have read but it does not work)
import com.google.gson.annotations.SerializedName;
public class Tiendas {
#SerializedName("id")
private int id;
#SerializedName("provincia")
private String provincia;
#SerializedName("direccion")
private String direccion;
public int getId() {
return id;
}
public String getProvincia() {
return provincia;
}
public String getDireccion() {
return direccion;
}
}
The interface
#GET("tiendas/tiends.json")
Call<List<Tiendas>> getTiendas();
MainActivity.java
private void getGETsinParametros() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.MY_URL_BASE.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
JsonPlaceHolderApi jspAPI = retrofit.create(JsonPlaceHolderApi.class);
Call<List<Tiendas>> call = jspAPI.getTiendas();
call.enqueue(new Callback<List<Tiendas>>() {
#Override
public void onResponse(Call<List<Tiendas>> call, Response<List<Tiendas>> response) {
if (!response.isSuccessful()) {
Log.e(TAG, "Código de respuesta no exítoso:" + response.code());
} else {
Log.d(TAG,"response code:"+response.code());
List<Tiendas> listaObtenida = response.body();
for(Tiendas stores: listaObtenida){
String content = "";
content += "id" + stores.getId() + "\n";
content += "provincia" + stores.getProvincia() + "\n";
content += "direccion" + stores.getDireccion() + "\n";
jsonText.append(content);
}
}
}
#Override
public void onFailure(Call<List<Tiendas>> call, Throwable t) {
Log.e("TAG, "error:" + t.getMessage());
}
});
}
Can someone tell me how to fix the error with "data", or with what is necessary to make it work?
The JSONs are external, so I can't modify them.
Thanks and regards.
You need to create the wrapper for the Array object to get the list of tiendas:
public class Data{
private List<Tiendas> data;
public List<Tiendas> getData() {
return data;
}
}
And call it in your interface:
#GET("tiendas/tiends.json")
Call<Data> getTiendas();
do not forget to use the new object at onResponse:
List<Tiendas> listaObtenida = response.body().getData();
The error has nothing to do with Retrofit. For a JSON, a field is an object, [] is an array, {} is a POJO.
In your first JSON, you have a data object with type List(or Array). Therefore, you will need to create a POJO on top (Access Modifier is omitted for simplicity)
class DataClazz {
List<Tiendas> data;
}

Retrofit2: Expected BEGIN_ARRAY

I am using for first time of Retrofit2 and I got this error:
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
I know my problem is my pojo class but I can't find the right solution to my problem.I create WCF web service an this service return to me a Arraylist of my user class as a json. this is my jsom response from wcf server by poster:
{
"GetUsersResult": [
{
"CreationDateTime": "/Date(1508174478395)/",
"Id": "8e601956-04ab-4464-9f84-c129141b8198",
"Topic": "Topics",
"UserInfo": {
"Age": "15",
"Email": "",
"LastName": "choopani",
"Name": "niloofar",
"SimId": "89984320001079005854"
},
"UserName": "niloo"
},...
According my response I have created pojo class :
public class User {
#SerializedName("UserInfo")
private ExpChild mChildrenList;
private String UserName, CreationDateTime,Id,Topic;
public User(String mUserName,String mCreationDateTime,String mId,
String mTopic) {
UserName = mUserName;
CreationDateTime = mCreationDateTime;
Id = mId;
Topic = mTopic;
}
this is Interface for my client post method:
#POST("json/GetUsers")
Call<List<User>> getAllUsers();
as you can see, I want to be returned a list of my User.
after that I create retrofit service creator and into my main Activity I've used it:
allUsers.enqueue(new Callback<List<User>>() {
#Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
List<User> users = response.body();
}
#Override
public void onFailure(Call<List<User>> call, Throwable t) {
Toast.makeText(MainActivity.this, "faild to connect", Toast.LENGTH_SHORT).show();
Log.i("====>", "onFailure: "+ t.getMessage());
}
});
but I got above error!!where is my mistake?
Your server returns a JSON object, but your interface says it expects a JSON array. (The List type).
You need to have a second object to represent the full response by the server:
public class ServerResponse {
#SerializedName("GetUsersResult")
private List<User> users;
... Constructor and getters here
}
Then the Retrofit interface should return Call<ServerResponse> which matches the returned JSON, fixing the error.

How to parse inner JSON using GSON builder

My JSON like this:-
{
"status": "approved",
"work_flow": {
"id": 27,
"name": "xgfdhx",
"role": "xfhxfhg",
"user_image": null
}
}
And my GsonCode is this:-
EmployeeDTO eDTO = gson.fromJson(json, eDTO.class);
so
Log.d(TAG,"Response: "+eDTO.getStatus())-----o/p:- Approved
means I am successfully get the status but I had problem to iterate the inner JSON,
Can someone explain me or help me how to get the work_flow inner JSON data.
using GSON builder?
Try
1. Change this line EmployeeDTO eDTO = gson.fromJson(json, eDTO.class); to
EmployeeDTO eDTO = gson.fromJson(json, EmployeeDTO.class);
2. Add class EmployeeDTO.java
public class EmployeeDTO {
String status;
#SerializedName("work_flow")
WorkFlow workFlow;
}
3. Add class WorkFlow.java
public class WorkFlow {
int id;
String name;
String role;
String userImage;
}

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.

Sending ArrayList<Object> POST request with Retrofit

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);
}

Categories

Resources