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

                }
Newera
  • 65
  • 7
  • 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. – Gaket Dec 04 '16 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> either you need to wrap your List in a class say Recipes with List as attribute or need a custom deserializer to unwrap the response of json object to json array. – Sanjeet A Dec 04 '16 at 21:46
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – denvercoder9 Dec 04 '16 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? – Newera Dec 05 '16 at 08:44

2 Answers2

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>

Sanjeet A
  • 5,171
  • 3
  • 23
  • 40
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!

Newera
  • 65
  • 7