-3

with the next problem, when trying to consume a webservice, then message and presentation;

Expected BEGIN_ARRAY but was BEGIN_OBJECT

I'm not sure how to make a scenario, I've already got data from a webservice, but when it's not a simple array.

I have tried many alternatives, but without success.

response api

  {
    "_links": {
        "self": {
            "href": "http://url.com/service?page=1"
        },
        "first": {
            "href": "http://url.com/service"
        },
        "last": {
            "href": "http://url.com/service?page=1"
        }
    },
    "_embedded": {
        "data": [
            {
                "id": 1,
                "nome": "teste",
                "_links": {
                    "self": {
                        "href": "http://url.com/service/1"
                    }
                }
            },
            {
                "id": 2,
                "nome": "teste 2",
                "_links": {
                    "self": {
                        "href": "http://url.com/service/2"
                    }
                }
            }
        ]
    },
    "page_count": 1,
    "page_size": 25,
    "total_items": 2,
    "page": 1
}

Client

public class ApiClient {

    private static final String BASE_URL = "http://url.com/";


    private static Retrofit getClient() {

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

        Gson gson = new GsonBuilder().setLenient().create();

        return new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();
    }

    /**
     * Get API Service
     *
     * @return API Service
     */
    public static ApiInterface getApiService() {
        return getClient().create(ApiInterface.class);
    }

}

Interface

/**
 * Class ApiInterface
 */
public interface ApiInterface
{

    @Headers("Accept: application/json")
    @GET("/service")
    Call<ArrayList<ServiceData>> getData();


}

Service

public class Service{

    @SerializedName("data")
    private ArrayList<ServiceData> service = new ArrayList<>();

}

Service Data

public class ServiceData {
    @SerializedName("id")
    private int id;


    public ServiceData(int id, String nome) {
        this.id = id;

    }

    public int getId() {
        return id;
    }

}

Activity

 final Call<ArrayList<ServiceData>> service = apiService.getService();
        service.enqueue(new Callback<ArrayList<ServiceData>>() {
            @Override
            public void onResponse(Call<ArrayList<ServiceData>> call, Response<ArrayList<ServiceData>> response) {
                Log.e(TAG, "" + response.body());
            }

            @Override
            public void onFailure(Call<ArrayList<ServiceData>> call, Throwable t) {
                Log.e(TAG, "" + t);

            }
        });
Jerfeson Guerreiro
  • 745
  • 1
  • 10
  • 19

4 Answers4

1

You were in the right path but the response is the whole json and not only the data part you want.

I would create the ResponseApi class:

public class ResponseApi {
    @SerializedName("_embedded")
    private Service embedded;
}

And change on ApiInterface:

Call<ArrayList<ServiceData>> getData(); 

To:

Call<ResponseApi> getData(); 

Also in your activity replace all ArrayList<ServiceData> with ResponseApi.

With only this changes your code should work. And then you'll need to add getters in ResponseApi and Service to access the saved data.


UPDATE adding some getters:

We need the possibility to get the ArrayList of ServiceData of services:

public class Service {
    // Your current code

    public List<ServiceData> getServices() {
        return service;
    }
}

And also we could create a getter in ResponseApi to get embedded getEmbedded (I'll add the code as info only) but since we only want the services we could create a getter to the list of services getEmbededServices and use this last method.

public class ResponseApi {
    // Your current code

    public Service getEmbedded() { // Not used, only shown as info
        return embedded;
    }

    public List<ServiceData> getEmbeddedServices() {
        return embedded.getServices();
    }
}

This way, when you'll receive a ResponseApi object in the onResponse method you can call its getEmbeddedServices to get the List of ServiceData and then you can loop through them to get the ids:

@Override
public void onResponse(Call<ResponseApi> call, Response<ResponseApi> response) {
    Log.d(TAG, "services: " + response.getEmbeddedServices());
    // Here you can loop the response.getEmbeddedServices() which is a List of ServiceData and get each of the ids. Ex:
    for (ServiceData serviceData : response.getEmbeddedServices()) {
        Log.d(TAG, "service Id: " + serviceData.getId());
        // Here you have access to the ids and can do whatever you need with them.
    }
}

By the way, only as a suggestion, I would rename (with refactor in Android Studio) this service var (in Service class):

private ArrayList<ServiceData> service = new ArrayList<>();

To servicesList:

private ArrayList<ServiceData> servicesList = new ArrayList<>();

And maybe also refactor the Service class to ServicesList class.

It's going to work either you rename them or not but, in my opinion, the code is more readable this way.

jeprubio
  • 17,312
  • 5
  • 45
  • 56
  • Your response was human and perfect, thank you, I'm getting my array, a single question, in this scenario my response data will no longer be used? And if I just want to get the id, how could it be? I have tried in some ways to create my attributes using the service, and creating the getters, but I can not access them. – Jerfeson Guerreiro Dec 29 '17 at 12:18
  • 1
    Thanks, don't worry, I've just added an update to explain a way of accessing the needed data by adding some getters. I've not run it but it should work. – jeprubio Dec 29 '17 at 13:17
  • With minor modifications I got the result that I expected, I have no words to thank. – Jerfeson Guerreiro Dec 29 '17 at 14:42
0

Try this

Your Parsing mapping has issues try below Model

ServiceData.java

public class ServiceData {

@SerializedName("_links")
@Expose
private Links links;
@SerializedName("_embedded")
@Expose
private Embedded embedded;
@SerializedName("page_count")
@Expose
private Integer pageCount;
@SerializedName("page_size")
@Expose
private Integer pageSize;
@SerializedName("total_items")
@Expose
private Integer totalItems;
@SerializedName("page")
@Expose
private Integer page;

public Links getLinks() {
return links;
}

public void setLinks(Links links) {
this.links = links;
}

public Embedded getEmbedded() {
return embedded;
}

public void setEmbedded(Embedded embedded) {
this.embedded = embedded;
}

public Integer getPageCount() {
return pageCount;
}

public void setPageCount(Integer pageCount) {
this.pageCount = pageCount;
}

public Integer getPageSize() {
return pageSize;
}

public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}

public Integer getTotalItems() {
return totalItems;
}

public void setTotalItems(Integer totalItems) {
this.totalItems = totalItems;
}

public Integer getPage() {
return page;
}

public void setPage(Integer page) {
this.page = page;
}

}

Self_.java

    public class Self_ {

    @SerializedName("href")
    @Expose
    private String href;

    public String getHref() {
    return href;
    }

    public void setHref(String href) {
    this.href = href;
    }

    }

Self.java

    public class Self {

    @SerializedName("href")
    @Expose
    private String href;

    public String getHref() {
    return href;
    }

    public void setHref(String href) {
    this.href = href;
    }

    }

Links_.java

    public class Links_ {

    @SerializedName("self")
    @Expose
    private Self_ self;

    public Self_ getSelf() {
    return self;
    }

    public void setSelf(Self_ self) {
    this.self = self;
    }

    }

Links.java

    public class Links {

    @SerializedName("self")
    @Expose
    private Self self;
    @SerializedName("first")
    @Expose
    private First first;
    @SerializedName("last")
    @Expose
    private Last last;

    public Self getSelf() {
    return self;
    }

    public void setSelf(Self self) {
    this.self = self;
    }

    public First getFirst() {
    return first;
    }

    public void setFirst(First first) {
    this.first = first;
    }

    public Last getLast() {
    return last;
    }

    public void setLast(Last last) {
    this.last = last;
    }
    }

Last.java

    public class Last {

    @SerializedName("href")
    @Expose
    private String href;

    public String getHref() {
    return href;
    }

    public void setHref(String href) {
    this.href = href;
    }

    }

First.java

    public class First {

    @SerializedName("href")
    @Expose
    private String href;

    public String getHref() {
    return href;
    }

    public void setHref(String href) {
    this.href = href;
    }

    }

Embedded.java

    public class Embedded {

    @SerializedName("data")
    @Expose
    private List<Datum> data = null;

    public List<Datum> getData() {
    return data;
    }

    public void setData(List<Datum> data) {
    this.data = data;
    }

    }

Datum.java

    public class Datum {

    @SerializedName("id")
    @Expose
    private Integer id;
    @SerializedName("nome")
    @Expose
    private String nome;
    @SerializedName("_links")
    @Expose
    private Links_ links;

    public Integer getId() {
    return id;
    }

    public void setId(Integer id) {
    this.id = id;
    }

    public String getNome() {
    return nome;
    }

    public void setNome(String nome) {
    this.nome = nome;
    }

    public Links_ getLinks() {
    return links;
    }

    public void setLinks(Links_ links) {
    this.links = links;
    }

    }
Ramesh sambu
  • 3,577
  • 2
  • 24
  • 39
0

Try to remove ArrayList from every where and direct use ServiceData

Interface

/**
 * Class ApiInterface
 */
public interface ApiInterface
{

    @Headers("Accept: application/json")
    @GET("/service")
    Call<ServiceData> getData();


}

Service Data

public class ServiceData {
    @SerializedName("id")
    private int id;


    public ServiceData(int id, String nome) {
        this.id = id;

    }

    public int getId() {
        return id;
    }

}

Activity

 final Call<ServiceData> service = apiService.getService();
        service.enqueue(new Callback<ServiceData>() {
            @Override
            public void onResponse(Call<ServiceData> call, Response<ServiceData> response) {
                Log.e(TAG, "" + response.body());
            }

            @Override
            public void onFailure(Call<ServiceData> call, Throwable t) {
                Log.e(TAG, "" + t);

            }
        });
Munir
  • 2,548
  • 1
  • 11
  • 20
0

You call and waiting for List. Call<ArrayList<ServiceData>>
But in the response, you have an object.

[...] - is array (list)
{...} - is object

You need to create classes for all parameters properly.

Just try to look at this service (or similar):
http://www.jsonschema2pojo.org/

Or Android Studio (IDEA) also has a plugin (GsonFormat) for converting JSON.

Merov
  • 1,028
  • 1
  • 14
  • 29