Retrofit Returning Null Response Body

13,630

Based on my previous answer here your model is not correct your stat: "ok" at the end of Response is your mistake.

While you create a Photos Object you need a parent Model to keep both attribute (photos & stat)

So your model would be:

public class Model {

    Photos photos;
    int code;
    String stat;
    String message; // when you text = null


    public class Photos{
        int page;
        int pages;
        int perpage;
        int total;
        List<Photo> photo;



        public class Photo{
            String id;
            String owner;
            String secret;
            //rest of things

        }
    }
}

Also don't forget to change your Call<Photos> to Call<Model>.

Share:
13,630
tccpg288
Author by

tccpg288

I quit my corporate job as a certified public accountant to learn computer programming. I am starting with Java / Android and eventually going to work to Shift / iOS. Currently, I have 2 applications published in the Google Play Store. I am maintaining these applications while finding ways to build new applications at the same time. Right now, I am starting to learn server-side programming, specifically Retrofit and Google App Engine Servlets. Let me know if you have any advice or can offer input!

Updated on August 02, 2022

Comments

  • tccpg288
    tccpg288 almost 2 years

    I am trying to make a call to the FlickR API and am having difficulty as the response.body() is returning null.

    I am not sure if it relates to my JSON/POJO mapping, but I cannot figure out how to access the response from Retrofit when I make the call to FlickR. I know that my call is being completed successfully as I am actually able to view the JSON through the logging interceptor.

    Model:

    public class Model {
    
    Photos photos;
    int code;
    String stat;
    String message; // when you text = null
    
    public class Photos {
    
        @SerializedName("page")
        @Expose
        private int page;
        @SerializedName("pages")
        @Expose
        private int pages;
        @SerializedName("perpage")
        @Expose
        private int perpage;
        @SerializedName("total")
        @Expose
        private String total;
        @SerializedName("photo")
        @Expose
        private List<Photo> photo = new ArrayList<Photo>();
    
        /**
         * @return The page
         */
        public int getPage() {
            return page;
        }
    
        /**
         * @param page The page
         */
        public void setPage(int page) {
            this.page = page;
        }
    
        /**
         * @return The pages
         */
        public int getPages() {
            return pages;
        }
    
        /**
         * @param pages The pages
         */
        public void setPages(int pages) {
            this.pages = pages;
        }
    
        /**
         * @return The perpage
         */
        public int getPerpage() {
            return perpage;
        }
    
        /**
         * @param perpage The perpage
         */
        public void setPerpage(int perpage) {
            this.perpage = perpage;
        }
    
        /**
         * @return The total
         */
        public String getTotal() {
            return total;
        }
    
        /**
         * @param total The total
         */
        public void setTotal(String total) {
            this.total = total;
        }
    
        /**
         * @return The photo
         */
        public List<Photo> getPhoto() {
            return photo;
        }
    
        /**
         * @param photo The photo
         */
        public void setPhoto(List<Photo> photo) {
            this.photo = photo;
        }
    
    }
    
    public class Photo {
    
        @SerializedName("id")
        @Expose
        private String id;
        @SerializedName("owner")
        @Expose
        private String owner;
        @SerializedName("secret")
        @Expose
        private String secret;
        @SerializedName("server")
        @Expose
        private String server;
        @SerializedName("farm")
        @Expose
        private int farm;
        @SerializedName("title")
        @Expose
        private String title;
        @SerializedName("ispublic")
        @Expose
        private int ispublic;
        @SerializedName("isfriend")
        @Expose
        private int isfriend;
        @SerializedName("isfamily")
        @Expose
        private int isfamily;
        @SerializedName("url_m")
        @Expose
        private String urlM;
        @SerializedName("height_m")
        @Expose
        private String heightM;
        @SerializedName("width_m")
        @Expose
        private String widthM;
    
        public Photo(){
    
        }
    
        /**
         * @return The id
         */
        public String getId() {
            return id;
        }
    
        /**
         * @param id The id
         */
        public void setId(String id) {
            this.id = id;
        }
    
        /**
         * @return The owner
         */
        public String getOwner() {
            return owner;
        }
    
        /**
         * @param owner The owner
         */
        public void setOwner(String owner) {
            this.owner = owner;
        }
    
        /**
         * @return The secret
         */
        public String getSecret() {
            return secret;
        }
    
        /**
         * @param secret The secret
         */
        public void setSecret(String secret) {
            this.secret = secret;
        }
    
        /**
         * @return The server
         */
        public String getServer() {
            return server;
        }
    
        /**
         * @param server The server
         */
        public void setServer(String server) {
            this.server = server;
        }
    
        /**
         * @return The farm
         */
        public int getFarm() {
            return farm;
        }
    
        /**
         * @param farm The farm
         */
        public void setFarm(int farm) {
            this.farm = farm;
        }
    
        /**
         * @return The title
         */
        public String getTitle() {
            return title;
        }
    
        /**
         * @param title The title
         */
        public void setTitle(String title) {
            this.title = title;
        }
    
        /**
         * @return The ispublic
         */
        public int getIspublic() {
            return ispublic;
        }
    
        /**
         * @param ispublic The ispublic
         */
        public void setIspublic(int ispublic) {
            this.ispublic = ispublic;
        }
    
        /**
         * @return The isfriend
         */
        public int getIsfriend() {
            return isfriend;
        }
    
        /**
         * @param isfriend The isfriend
         */
        public void setIsfriend(int isfriend) {
            this.isfriend = isfriend;
        }
    
        /**
         * @return The isfamily
         */
        public int getIsfamily() {
            return isfamily;
        }
    
        /**
         * @param isfamily The isfamily
         */
        public void setIsfamily(int isfamily) {
            this.isfamily = isfamily;
        }
    
        /**
         * @return The urlM
         */
        public String getUrlM() {
            return urlM;
        }
    
        /**
         * @param urlM The url_m
         */
        public void setUrlM(String urlM) {
            this.urlM = urlM;
        }
    
        /**
         * @return The heightM
         */
        public String getHeightM() {
            return heightM;
        }
    
        /**
         * @param heightM The height_m
         */
        public void setHeightM(String heightM) {
            this.heightM = heightM;
        }
    
        /**
         * @return The widthM
         */
        public String getWidthM() {
            return widthM;
        }
    
        /**
         * @param widthM The width_m
         */
        public void setWidthM(String widthM) {
            this.widthM = widthM;
        }
    
        }
    
    }
    

    JSON Response:

    {
      photos: {
      page: 1,
      pages: 3683,
      perpage: 100,
      total: "368270",
      photo: [
           {
           id: "29264707352",
           owner: "84316756@N02",
           secret: "9ed355a86e",
           server: "8603",
           farm: 9,
           title: "Tercer Patio de los Claustros de la Compañía/ Arequipa",
           ispublic: 1,
           isfriend: 0,
           isfamily: 0,
           url_m:          "https://farm9.staticflickr.com/8603/29264707352_9ed355a86e.jpg",
           height_m: "500",
           width_m: "333"
              },
            {
            id: "29339070436",
            owner: "146617764@N02",
            secret: "b52f1e9914",
            server: "8509",
            farm: 9,
            title: "2016-04-17 09.24.07",
            ispublic: 1,
            isfriend: 0,
            isfamily: 0,
            url_m: "https://farm9.staticflickr.com/8509/29339070436_b52f1e9914.jpg",
            height_m: "281",
            width_m: "500"
           },
    

    LOGCAT

    09-03 15:11:33.037 1846-1846/com.troychuinard.flickr_test E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                Process: com.troychuinard.flickr_test, PID: 1846
                                                                                java.lang.NullPointerException: println needs a message
                                                                                    at android.util.Log.println_native(Native Method)
                                                                                    at android.util.Log.v(Log.java:118)
                                                                                    at com.troychuinard.flickr_test.MainActivity$1$1.onResponse(MainActivity.java:72)
                                                                                    at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
                                                                                    at android.os.Handler.handleCallback(Handler.java:739)
                                                                                    at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                    at android.os.Looper.loop(Looper.java:135)
                                                                                    at android.app.ActivityThread.main(ActivityThread.java:5254)
                                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                                    at java.lang.reflect.Method.invoke(Method.java:372)
                                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
                                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
    09-03 15:14:21.858 1846-1846/com.troychuinard.flickr_test I/Process: Sending signal. PID: 1846 SIG: 9
    

    Line 72

             Log.v("RESPONSE_BODY", response.body().getTotal());
    

    Activity

    public class MainActivity extends AppCompatActivity {
    
    private EditText mSearchTerm;
    private Button mRequestButton;
    private Button mSearchButton;
    private String mQuery;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        mSearchTerm = (EditText) findViewById(R.id.ediText_search_term);
        mRequestButton = (Button) findViewById(R.id.request_button);
        mSearchButton = (Button) findViewById(R.id.search_button_flickr);
        mRequestButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mQuery = mSearchTerm.getText().toString();
                HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
                interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
                OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
                Retrofit retrofit = new Retrofit.Builder()
                        .baseUrl("https://api.flickr.com/services/rest/")
                        .client(client)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
    
    
                ApiInterface apiInterface = retrofit.create(ApiInterface.class);
                Call<Photos> call = apiInterface.getImages(mQuery);
                call.enqueue(new Callback<Photos>() {
                    @Override
                    public void onResponse(Call<Photos> call, Response<Photos> response) {
                        Log.v("RESPONSE_CALLED", "ON_RESPONSE_CALLED");
                        String didItWork = String.valueOf(response.isSuccessful());
                        Log.v("SUCCESS?", didItWork);
                        Log.v("RESPONSE_CODE", String.valueOf(response.code()));
                        Photos photos = response.body();
                        Log.v("RESPONSE_BODY", "response:" + photos);
                        String total = response.body().getTotal();
                        Log.v("Total", total);
                        List<Photos.Photo> photoResults = response.body().getPhoto();
                        for (Photos.Photo photo : photoResults) {
                            Log.v("PHOTO_URL:", photo.getTitle()
                            );
                        }
    
    
                    }
    
                    @Override
                    public void onFailure(Call<Photos> call, Throwable t) {
    
                    }
                });
            }
        });
    
        mSearchButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent toSearch = new Intent(MainActivity.this, FlickRActivity.class);
                startActivity(toSearch);
            }
        });
    
    
    }
    
    //Synchronous vs. Asynchronous
    public interface ApiInterface {
    
        @GET("?method=flickr.photos.search&api_key=1c448390199c03a6f2d436c40defd90e&format=json&nojsoncallback=1&extras=url_m")
        Call<Photos> getImages(@Query("text") String query);
    
    }
    

    }

  • tccpg288
    tccpg288 over 7 years
    Thanks I am trying to understand. I don't see how this model is different than my original code, and I don't understand what stat and message are for. Not saying you are wrong just trying to figure out where it comes into play
  • Amir
    Amir over 7 years
    @tccpg288 I test your query with simple text; if you scroll to end of response a stat attribute exist; Also if you send null value to server it's return message and code.
  • Amir
    Amir over 7 years
    You get Null value because retrofit expect to see Object which contains photos and stat But saw photos and can't cast this object to each other :)
  • tccpg288
    tccpg288 over 7 years
    How do I scroll to the end of the response? I am having trouble even viewing the response...
  • tccpg288
    tccpg288 over 7 years
    I have updated my code. Can you write the exact line of code that would explain how to call getTotal(), which is in my "Photo" model, from the response.body()?
  • Amir
    Amir over 7 years
    Add public getPhoto() in your Model class which return your photo object; just like other getter in your photos class
  • Amir
    Amir over 7 years
    copy following url in your browser to see response: api.flickr.com/services/rest/…
  • tccpg288
    tccpg288 over 7 years
    Where did you get that URL from? I use the logging interceptor with Retrofit and received the following link: api.flickr.com/services/rest/…