0

I am using Retrofit to connect to my REST API. Please check the below code

   import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Date;
    import java.util.List;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import retrofit2.Call;
    import retrofit2.Callback;
    import retrofit2.Response;
    import retrofit2.Retrofit;
    import retrofit2.converter.gson.GsonConverterFactory;

    /**
     *
     * @author The Ace
     */
    public class SignUpLoaderServlet extends HttpServlet {

        /**
         * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
         * methods.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        protected void processRequest(final HttpServletRequest request, final HttpServletResponse response)
                throws ServletException, IOException {
            response.setContentType("text/html;charset=UTF-8");
            PrintWriter out = response.getWriter();
            System.out.println("RUNNING!!!!!!!!!!!");

            try {
                GsonBuilder gsonBuilder = new GsonBuilder();
                gsonBuilder.registerTypeAdapter(Date.class, new DateTypeDeserializer());
                Gson gson = gsonBuilder.create();

                Retrofit retrofit = new Retrofit.Builder()
                        .baseUrl(BaseURLs.MESSAGING_URL)
                        .addConverterFactory(GsonConverterFactory.create(gson))
                        .build();

                RestEndPointsInterface endPoint = retrofit.create(RestEndPointsInterface.class);
                Call<List<ProfesionalBodyList>> call = endPoint.getAllProfesionalBodyLists();
                call.enqueue(new Callback<List<ProfesionalBodyList>>() {

                    @Override
                    public void onResponse(Call<List<ProfesionalBodyList>> call, Response<List<ProfesionalBodyList>> rspn) 
                    {
                        try {
                            List<ProfesionalBodyList> body = rspn.body();


                            for(int i=0;i<body.size();i++)
                            {
                                System.out.println(body.get(i).getProfessionalBody());
                            }

RequestDispatcher requestDispatcher = request.getRequestDispatcher("/create-account.jsp");
                            requestDispatcher.forward(request, response);


                        } catch (Exception ex) {
                            ex.printStackTrace();
                        } 
                    }

                    @Override
                    public void onFailure(Call<List<ProfesionalBodyList>> call, Throwable ex) {
                        ex.printStackTrace();
                    }
                });



            } finally {


            }
        }

        // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
        /**
         * Handles the HTTP <code>GET</code> method.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
        }

        /**
         * Handles the HTTP <code>POST</code> method.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
        }

    }

This code fires the below exception

java.lang.NullPointerException
    at com.tekhinno.xxx.signup.SignUpLoaderServlet$1.onResponse(SignUpLoaderServlet.java:80)
    at retrofit2.OkHttpCall$1.callSuccess(OkHttpCall.java:132)
    at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:111)
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135)
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

However if I replace the below code line into the finally() block, the issue is gone.

RequestDispatcher requestDispatcher = request.getRequestDispatcher("/create-account.jsp");
requestDispatcher.forward(request, response);

I am not sure why it is not working inside the onResponse(). It is imporant to run there because I load items from the REST API before the forward action take place.

Any idea?

PeakGen
  • 21,894
  • 86
  • 261
  • 463
  • 1
    You're using an asynchronous API, which sends a request in a background thread and then calls you back later when the response is available, and doesn't block the request-handling thread. So the request is already handled when the onResponse callback is executed. – JB Nizet Apr 06 '17 at 06:57
  • @JBNizet: Thanks. So, how can I handle this situation? – PeakGen Apr 06 '17 at 07:02

1 Answers1

0

The issue is mainly because the call was Asynchronous and the requestDispatcher object was already executed. Then the answer is to stay until the REST call complete its work load. That means, do it Synchronous.

Retrofit can be done in Synchronous manner as well. Below is the code.

protected void processRequest(final HttpServletRequest request, final HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        System.out.println("RUNNING!!!!!!!!!!!");

        try {
            GsonBuilder gsonBuilder = new GsonBuilder();
            gsonBuilder.registerTypeAdapter(Date.class, new DateTypeDeserializer());
            Gson gson = gsonBuilder.create();

            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(BaseURLs.MESSAGING_URL)
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .build();

            RestEndPointsInterface endPoint = retrofit.create(RestEndPointsInterface.class);
            Call<List<ProfesionalBodyList>> call = endPoint.getAllProfesionalBodyLists();
            body = call.execute().body();

            for (int i = 0; i < body.size(); i++) {
                System.out.println(body.get(i).getProfessionalBody());
            }

        } finally {
            RequestDispatcher requestDispatcher = request.getRequestDispatcher("/create-account.jsp");
            request.setAttribute("ProfesionalBodyList", body);
            requestDispatcher.forward(request, response);
        }
    }

Simpy pay attention to the place where it says call.execute().body();. This is the Synchronous call.

PeakGen
  • 21,894
  • 86
  • 261
  • 463