Retrofit / Gson puts empty model in List<>

Daniel Spiess :

Im trying to retrive json with retrofit and gson from the API http://api.themoviedb.org/3/movie/. Im my main activity it is working fine, but when i call some additional information in my DetailsActivity i figure out that the models in my array are emty. This is weird because i am recieving even the right number of objects in the array from the api. But when i Log a value from the model (for example Log.d(TAG, movieTrailers.get(0).getName()) the app crashes. Whit an if statement i figure out that this value is null.

This is the API http://api.themoviedb.org/3/movie/297802/videos?api_key= for example. (Unfortunatly i am not allowed to post the api key) It contains in a jsonarray of videos about the movie.

This is my Code:

The Model:

public class MovieTrailer {

    @SerializedName("key")
    private String key;
    @SerializedName("name")
    private String name;
    @SerializedName("type")
    private String type;

    public MovieTrailer(String key, String name, String type){
        this.key = key;
        this.name = name;
        this.type = type;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getName() {
        return name;
    }

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

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}

The Model for the List:

public class TrailersList {
    @SerializedName("results")
    @Expose
    private List<MovieTrailer> trailers = null;

    public List<MovieTrailer> getTrailers() {
        return trailers;
    }

    public void setTrailers(List<MovieTrailer> trailers) {
        this.trailers = trailers;
    }
}

The Adapter:

public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoAdapterViewHolder> {

    private List<MovieTrailer> movieTrailers;

    private final  VideoOnClickHandler videoOnClickHandler;

    public interface VideoOnClickHandler{
        void onClick(MovieTrailer movieTrailer);
    }

    public VideoAdapter(VideoOnClickHandler onClickHandler) {videoOnClickHandler = onClickHandler;}

    public class VideoAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

        public final TextView videoTypeText;
        public final TextView videoNameText;

        public VideoAdapterViewHolder(View view){
            super(view);
            videoTypeText = (TextView) view.findViewById(R.id.tv_video_type);
            videoNameText = (TextView) view.findViewById(R.id.tv_video_name);
            view.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            int adapterPosition = getAdapterPosition();
            MovieTrailer movieTrailer = movieTrailers.get(adapterPosition);
            videoOnClickHandler.onClick(movieTrailer);
        }
    }

    @NonNull
    @Override
    public VideoAdapterViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        Context context = viewGroup.getContext();
        int gridItem = R.layout.movie_trailer;
        LayoutInflater inflater = LayoutInflater.from(context);
        boolean shouldAttachToParentImmediately = false;

        View view = inflater.inflate(gridItem, viewGroup,shouldAttachToParentImmediately);

        return new VideoAdapter.VideoAdapterViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull VideoAdapterViewHolder videoAdapterViewHolder, int i) {
        MovieTrailer movieTrailer = movieTrailers.get(i);
        videoAdapterViewHolder.videoTypeText.setText(movieTrailer.getType());
        videoAdapterViewHolder.videoNameText.setText(movieTrailer.getName());
    }

    @Override
    public int getItemCount() {
        if (null == movieTrailers) return 0;
        return movieTrailers.size();
    }

    //Function to set movieTrailers
    public void setMovieTrailerArray(List<MovieTrailer> trailerArrayToSet){
        movieTrailers = trailerArrayToSet;
        notifyDataSetChanged();
    }


}

The Interface:

public interface GetDataService {

    @GET("{path}?api_key=" + BuildConfig.API_KEY)
    Call<MoviesList> getAllMovies(@Path("path") String path);

    @GET("{movieId}/reviews?api_key=" + BuildConfig.API_KEY)
    Call<TrailersList> getAllTrailers(@Path("movieId") String movieId);

    @GET("{movieId}/videos?api_key=" + BuildConfig.API_KEY)
    Call<ReviewsList> getAllReviews(@Path("movieId") String movieId);
}

The Retrofit Instance:

public class RetrofitClientInstance {

    //Base URL for API request
    private static final String MOVIE_DATABASE_URL_POPULAR =
            "http://api.themoviedb.org/3/movie/";

    /**
     * Get Retrofit Instance
     */
    private static Retrofit getRetrofitInstance() {
        return new Retrofit.Builder()
                .baseUrl(MOVIE_DATABASE_URL_POPULAR)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

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

And the method from the DetailsActivity:

private void loadMovieTrailers(String movieId){
        GetDataService api = RetrofitClientInstance.getApiService();
        Call<TrailersList> call = api.getAllTrailers(movieId);

        call.enqueue(new Callback<TrailersList>() {
            @Override
            public void onResponse(Call<TrailersList> call, Response<TrailersList> response) {
                if(response.isSuccessful()){
                    movieTrailers = response.body().getTrailers();
                    if(movieTrailers.get(0).getName() == null){
                        Log.d("MODEL", "Null");
                    }else {
                        Log.d("MODEL", "Not Null");
                    }

                    videoAdapter.setMovieTrailerArray(movieTrailers);
                }
            }

            @Override
            public void onFailure(Call<TrailersList> call, Throwable t) {
            }
        });
    }

Someone has an idea where the mistake is?

Shashanth :

I think the problem is in your interface class with these methods,

@GET("{movieId}/reviews?api_key=" + BuildConfig.API_KEY)
Call<TrailersList> getAllTrailers(@Path("movieId") String movieId);

@GET("{movieId}/videos?api_key=" + BuildConfig.API_KEY)
Call<ReviewsList> getAllReviews(@Path("movieId") String movieId);

From {movieId}/reviews you'll get the following JSON response,

{
  "id": 297761,
  "page": 1,
  "results": [
    {
      "id": "57a814dc9251415cfb00309a",
      "author": "Frank Ochieng",
      "content": "Summertime 2016 has not been very kind to DC Comics-based personalities looking to shine consistently like their big screen Marvel Comics counterparts.",
      "url": "https://www.themoviedb.org/review/57a814dc9251415cfb00309a"
    }
  ],
  "total_pages": 1,
  "total_results": 1
}

and {movieId}/videos returns,

{
  "id": 550,
  "results": [
    {
      "id": "533ec654c3a36854480003eb",
      "iso_639_1": "en",
      "iso_3166_1": "US",
      "key": "SUXWAEX2jlg",
      "name": "Trailer 1",
      "site": "YouTube",
      "size": 720,
      "type": "Trailer"
    }
  ]
}

So, both of them returns almost same result with JSONArray (results) enclosed withing JSONObject. JSON response is proper there's no problem at all.

While parsing JSON response, Gson converter factory fails to find the equivalent POJO class for the response. You don't even get any errors because both are returning same type response.

A simple fix is to change (inter change) the URLs of the following methods.

@GET("{movieId}/videos?api_key=" + BuildConfig.API_KEY)   // change from reviews to videos
Call<TrailersList> getAllTrailers(@Path("movieId") String movieId);  

@GET("{movieId}/reviews?api_key=" + BuildConfig.API_KEY)   // change from videos to reviews
Call<ReviewsList> getAllReviews(@Path("movieId") String movieId);

That's it!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=81928&siteId=1