0

I get this error java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int) on a null object reference' when I try to get the values from the list or return it's size and I can't find what it wrong. First of all, I am using the API from food2fork so I can get some recipes based on user's input(ingredients). This is how the results are returned and how the JSON structure is. If you want to see the parameters go here http://food2fork.com/about/api

This is my interface.

     public interface ApiService {
    @GET("/search")
    Call<List<Recipe>> getRecipes(@Query("api") String api_key, @Query ("q")      StringBuilder st);

}

The objects' class Recipe

public class Recipe {


    @SerializedName("publisher")
    private String publisher; //to onoma tou ekdoth
    @SerializedName("f2f_url")
    private String f2f_url; //to url tis suntaghs sto site food2fork
    @SerializedName("title")
    private String title; //titlos tis suntaghs
    @SerializedName("source_url")
    private String source_url; //to url ths suntaghs se html
    @SerializedName("recipe_id")
    private int recipe_id; //to id ths suntaghs
    @SerializedName("image_url")
    private String image_url; //to url ths eikonas se jpg
    @SerializedName("social_rank")
    private double social_rank;
    @SerializedName("publisher_url")
    private String publisher_url; //to vasiko url tou ekdoth

    public String getPublisher() {
            return publisher;
    }

    public String getF2f_url() {
            return f2f_url;
    }

    public String getSource_url() {
            return source_url;
    }

    public String getTitle() {
            return title;
    }

    public int getRecipe_id() {
            return recipe_id;
    }

    public double getSocial_rank() {
            return social_rank;
    }

    public String getImage_url() {
            return image_url;
    }

    public String getPublisher_url() {
            return publisher_url;
    }

public void setPublisher(String publisher) {
    this.publisher = publisher;
}

public void setF2f_url(String f2f_url) {
    this.f2f_url = f2f_url;
}

public void setTitle(String title) {
    this.title = title;
}

public void setSource_url(String source_url) {
    this.source_url = source_url;
}

public void setRecipe_id(int recipe_id) {
    this.recipe_id = recipe_id;
}

public void setImage_url(String image_url) {
    this.image_url = image_url;
}

public void setSocial_rank(double social_rank) {
    this.social_rank = social_rank;
}

public void setPublisher_url(String publisher_url) {
    this.publisher_url = publisher_url;
}

    public Recipe(String publisher, String f2f_url, String title, String source_url, int recipe_id, String image_url, double social_rank, String publisher_url) {
            this.publisher = publisher;
            this.f2f_url = f2f_url;
            this.title = title;
            this.source_url = source_url;
            this.recipe_id = recipe_id;
            this.image_url = image_url;
            this.social_rank = social_rank;
            this.publisher_url = publisher_url;
    }

}

My main class

public class ResponseMain extends AppCompatActivity {

RecyclerView recyclerView;
public static String getApiKey() {
    return API_KEY;
}

//to key API ths selidas pou mas epistrefei to json antikeimeno
private final static String API_KEY = "fe7a73e01ac9abc09db51ebf67019f94";
StringBuilder words;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("TAG", "MPIKA");
    setContentView(R.layout.activity_response);


    if (API_KEY.isEmpty()) {
        Toast.makeText(getApplicationContext(), "Please obtain your API key from food2fork.com first!", Toast.LENGTH_LONG);
        return;
    }
     recyclerView = (RecyclerView) findViewById(R.id.recipes_recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));


    words = addingItems_activity.getWords();
    getRetrofitArray();
}
public void getRetrofitArray() {

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    ApiService apiService = retrofit.create(ApiService.class);
    Call<List<Recipe>> call = apiService.getRecipes(API_KEY, words);

    call.enqueue(new Callback<List<Recipe>>() {
        @Override
        public void onResponse(Call<List<Recipe>> call, Response <List<Recipe>> response) {
            try {
                Log.d("Here comes the null exception","get title" + response.body().get(0).getTitle());
                List<Recipe> recipes = response.body();
                recyclerView.setAdapter(new Recipe_Adapter(recipes, R.layout.list_item_recipe, getApplicationContext()));
           }
            } catch (Exception e) {
                Log.d("onResponse", "There is an error", e);
                e.printStackTrace();


            }
        }

        @Override
        public void onFailure(Call <List<Recipe>> call,Throwable t) {
            Log.d("onFailure", t.toString());
        }
    });

}

} Also the words get added from another activity like this if

(itemList.size() == 1) {

                    words.append(itemList.get(0));
                }else{
                    for (int i = 0; i < (itemList.size() - 1); i++) {
                        words.append(itemList.get(i) + "%2C");

//the %2C is to show that they are separated ingredients, I found out that that's the symbol it is using to translate the comma }

                    words.append((itemList.get(itemList.size() - 1)));

                }
4
  • Have you tried to debug it? I'm using RxJava instead of enqueue and I don't see a problem in your code from the first glanse. I would try making breakpoint in first line of onResponse() and look what is coming there. Commented Dec 4, 2016 at 21:39
  • As I see the response is coming in the json object but the retrofit is expecting the array since you have Call<List<Recipe>> either you need to wrap your List<Recipe> in a class say Recipes with List<Recipe> as attribute or need a custom deserializer to unwrap the response of json object to json array. Commented Dec 4, 2016 at 21:46
  • Possible duplicate of What is a NullPointerException, and how do I fix it? Commented Dec 4, 2016 at 21:51
  • @Gaket I debugged it and response.body gives me a null value. I can't find what's wrong. Is my ApiService right? Commented Dec 5, 2016 at 8:44

2 Answers 2

1

When you define return type as Call<List<Recipe>> for the method getRecipes() in ApiService interface, Retrofit expects a response from server of type JSONArray which should exactly look like -

[
  {
    "publisher": "Allrecipes.com",
    ...
  },
    ...
]

But the response is coming from the server is following -

{
  "count": 1,
  "recipes": [
    {
      "publisher": "Allrecipes.com"
      ...
    },
      ...
  ]
}

So you either need to unwrap the response writing your custom deserializer or you need to Wrap your List in to wrapper class.

Your wrapper class can be like -

public class Recipes{
        private List<Recipe> recipes;
        private int count;
        public List<Recipe> getRecipes() {
            return recipes;
        }

        public void setRecipes(List<Recipe> recipes) {
            this.recipes = recipes;
        }
    }

and hence your ApiService interface method should return Call<Recipes>

Sign up to request clarification or add additional context in comments.

2 Comments

I tried using a wrapper class and it gives me the same error.
You were right about the class but I had a mistake on the interface too. Thanks a lot for your help.
0

So I solved it by changing the first query tag and of course the class that was used as stated by the commenters. I had the @QUERY api instead of key. That's how I changed my interface:

public interface ApiService {
    @GET("api/search/")
    Call<RootObject> getMyJSON(@Query("key") String api_key, @Query("q") StringBuilder st);

}

Also, I changed the base url of my Rest Class because I put the keywords on the interface

public class RestClient {

//gia na ginei h epikoinwnia me to API prepei na xrhsimopoihsw ton retrofit builder kai na prosdiorisw
//to url tou service
public static final String BASE_URL = "http://food2fork.com/";
private ApiService apiService;
        //"?key=";
        //+  addingItems_activity.getApiKey() + "&q=" + addingItems_activity.getWords();
private static Retrofit retrofit = null;

private static Retrofit getRetrofitInstance() {

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


  }

public static ApiService getApiService()
{
    return getRetrofitInstance().create(ApiService.class);
}
}

The rest of the solution was stated by first answer. Thank you a lot!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.