Retrofit JSON - Error Expected BEGIN_ARRAY but was BEGIN_OBJECT

Asked

Viewed 1,067 times

0

I’ve done some Retrofit projects and it always worked but I’m doing one that consumes the end-point of api.github.com and is giving an error and I’m not able to find a solution, I’ve done everything I can, if anyone knows what to do.

The Classes:

public class Items implements Serializable{

    private int id;
    private String name;
    private String full_name;

    @SerializedName("stargazers_count")
    private int stars;
    private Owner owner;
    private int forks;
    private String pulls_url;

    public Items() {
    }

    public Items(String name, String full_name, int stars, Owner owner, int forks, String pulls_url) {
        this.name = name;
        this.full_name = full_name;
        this.stars = stars;
        this.owner = owner;
        this.forks = forks;
        this.pulls_url = pulls_url;
    }

    public Items(int id, String name, String full_name, int stars, Owner owner, int forks, String pulls_url) {
        this.id = id;
        this.name = name;
        this.full_name = full_name;
        this.stars = stars;
        this.owner = owner;
        this.forks = forks;
        this.pulls_url = pulls_url;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getFull_name() {
        return full_name;
    }

    public void setFull_name(String full_name) {
        this.full_name = full_name;
    }

    public int getStars() {
        return stars;
    }

    public void setStars(int stars) {
        this.stars = stars;
    }

    public Owner getOwner() {
        return owner;
    }

    public void setOwner(Owner owner) {
        this.owner = owner;
    }

    public int getForks() {
        return forks;
    }

    public void setForks(int forks) {
        this.forks = forks;
    }

    public String getPulls_url() {
        return pulls_url;
    }

    public void setPulls_url(String pulls_url) {
        this.pulls_url = pulls_url;
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Items that = (Items) o;

        return id == that.id;

    }

    @Override
    public int hashCode() {
        return id;
    }


    @Override
    public String toString() {
        return "Items{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", owner=" + owner +
                '}';
    }
}
public interface RepositoryAPI {

    @GET("repositories?q=language:Java&sort=stars&page=1")
    public Call<List<Items>> getAllRepositories();

    Gson gson = new GsonBuilder().registerTypeAdapter(Items.class, new ItemDeserializer()).create();

    public static final Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.github.com/search/")
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();
}
public class ControllerAccessWS {

    RepositoryAPI repositoryAPI;

    //public synchronized List<Items> getAllRepositores()  {
    public void getAllRepositores() {
        Log.i("app", "getAllRepositores");

        Gson gson = new GsonBuilder().registerTypeAdapter(Items.class, new ItemDeserializer()).create();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/search/")
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();
        Log.i("app", "retrofit");

        repositoryAPI = retrofit.create(RepositoryAPI.class);
        Call<List<Items>> callListRepositore = repositoryAPI.getAllRepositories();

        Log.i("app", "repositoryAPI = retrofit.create");

        callListRepositore.enqueue(new Callback<List<Items>>() {
            @Override
            public void onResponse(Call<List<Items>> call, Response<List<Items>> response) {
                List<Items> listItems = new ArrayList<Items>();
                listItems.addAll(response.body());
                for (int i = 0; i < listItems.size(); i++) {
                    Log.i("app", "Repositori ID: " + listItems.get(i).getId());
                }

              /**
                List<Items> listRepositore;
                Log.i("app", "callListRepositore.enqueue - onResponse");
                if (response.isSuccessful()) {
                    Log.i("app", "callListRepositore.enqueue - response.isSuccessful()");

                        listRepositore = response.body();
                        Log.i("app", "callListRepositore.enqueue - onResponse - response.code() == 200");
                        for (int i = 0; i < listRepositore.size(); i++) {
                            Log.i("app", "Repositori ID: " + listRepositore.get(i).getId());
                        }

                }else{
                    Log.e("app", "Erro no Response: " + response.code());
                }

                **/
            }

            @Override
            public void onFailure(Call<List<Items>> call, Throwable t) {
                Log.e("app", "onFailure - Erro no Response: " + t.getMessage());
            }
        });


        //return null;
    }


}
public class ItemDeserializer implements JsonDeserializer<Items>{


    @Override
    public Items deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonElement items = json.getAsJsonObject();

        if(json.getAsJsonObject().get("items") != null){
            items = json.getAsJsonObject().get("items");
        }

        return (new Gson().fromJson(items, Items.class));
    }
}
public class MainActivity extends AppCompatActivity {

    private Toolbar mTbMain;
    private Drawer mNavDrawer;
    private AccountHeader mAccountNavDrawer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        ControllerAccessWS controllerAccessWS = new ControllerAccessWS();
        controllerAccessWS.getAllRepositores();

    }
}

1 answer

1

This API does not return a List, you have to create a class and change your Return to it as the below:

package com.example;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
    "total_count",
    "incomplete_results",
    "items"
})
public class Example {

    @JsonProperty("total_count")
    private Integer totalCount;
    @JsonProperty("incomplete_results")
    private Boolean incompleteResults;
    @JsonProperty("items")
    private List<Item> items = null;
    @JsonIgnore
    private Map<String, Object> additionalProperties = new HashMap<String, Object>();

    @JsonProperty("total_count")
    public Integer getTotalCount() {
        return totalCount;
    }

    @JsonProperty("total_count")
    public void setTotalCount(Integer totalCount) {
        this.totalCount = totalCount;
    }

    @JsonProperty("incomplete_results")
    public Boolean getIncompleteResults() {
        return incompleteResults;
    }

    @JsonProperty("incomplete_results")
    public void setIncompleteResults(Boolean incompleteResults) {
        this.incompleteResults = incompleteResults;
    }

    @JsonProperty("items")
    public List<Item> getItems() {
        return items;
    }

    @JsonProperty("items")
    public void setItems(List<Item> items) {
        this.items = items;
    }

    @JsonAnyGetter
    public Map<String, Object> getAdditionalProperties() {
        return this.additionalProperties;
    }

    @JsonAnySetter
    public void setAdditionalProperty(String name, Object value) {
        this.additionalProperties.put(name, value);
    }

}

It has a List of Items.

  • This code I posted about the problem is on an Android using Retrofit, you mean that Retrofit does not return List ???

  • Exact. You can call your URL directly in the browser and you will see that it returns an object with the attributes { total_count: 3596358, incomplete_results: false, items: [ ... ] } In it you have an attribute items that you are set to return.

  • I was confused because I’ve done this before, I’ve already picked up a @GET public Call<List<class>> getClasseMeuObject();

  • 1

    You have to change Return, it has to look like this: @GET("repositories?q=language:Java&sort=stars&page=1") public Call<Repositorie> getAllRepositories();. It cannot be a LIST because the return of the API is not a list, it is an object. Then Voce has to create a Repositorie class similar to the one I created above but with the name "Example"

  • Man, it worked, vlw even, you saved me hhehehehhehe!!!! Then when I did as you said here I remembered that I had already done it kkkkkkkk

Browser other questions tagged

You are not signed in. Login or sign up in order to post.