Search code examples
androidspringrestwebservice-clientresttemplate

Getting http 400 Bad Request Error with spring and resttemplate postForObject


I keep getting Bad Request HttpClient 400 Exception when executing the POST call to my Webservice. I cant figure out wether the error is originated on client or server side ... pls help me to track down this error. But since the pst call with curl is working fine i supspect that the error origins on the client side with the construction of springs resttemplate

The GET call is working fine! Also the post call with curl is working fine

C:\Users\pk>curl -v  -H "Accept: application/json" -H "Content-Type: application
/json" -X POST http://127.0.0.1:8080/TblGps/update -d @json.txt

Appriciate if someone can point out where i got it wrong.

my client code is:

when is comes to resttemplate.postForObject .... a Http 400 Bad Request Exception is thrown - the GET is working fine and the curl command line call with post is also working

    private class HttpRequestTask extends AsyncTask<Void, Void, TblGps> {
        @Override
        protected TblGps doInBackground(Void... params) {
            try {
                final String urlGET = "http://10.0.2.2:8080/TblGps/get?id=1";
                final String urlPOST = "http://10.0.2.2:8080/TblGps/update/";


                RestTemplate restTemplate = new RestTemplate();
                restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

                //get Object from Service
                TblGps gps = (TblGps) restTemplate.getForObject(urlGET,TblGps.class);


                // alter the Object Data
               gps.setDescr("success");

              //POST Object to Service Endpoint
              TblGps gpsResult = restTemplate.postForObject(urlPOST, "POST", TblGps.class, gps);


             return gpsResult;


            } catch (Exception e) {
                Log.e("REST call", e.getMessage(), e);
            }

            return null;
        }
}
}

and i've also tried with restTemplate.postForEntity

 HttpHeaders headers = new HttpHeaders();

            headers.add("Accept", "application/json");
            headers.add("Content-Type", "application/json");
    HttpEntity ent = new HttpEntity(gps,headers);
          ResponseEntity<TblGps> out  = restTemplate.postForEntity(urlPOST, HttpMethod.POST, TblGps.class,ent);

my controller code:

  @RequestMapping(value="/TblGps/update", method=RequestMethod.POST, consumes = "application/json",produces="application/json")
  @ResponseBody public TblGps post(@RequestBody  TblGps gps){

        logger.debug("/TblGps/update: " + gps.getId());
          System.out.println("save.............."+ gps);
          return Application.DataRepository.save(gps);
    }

my console log: the mapping of the Endpoints looks also ok on console log

2014-05-14 08:15:37.850  INFO 2280 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-05-14 08:15:41.457  INFO 2280 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/TblGps/List],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.util.List<com.pekam.TblGps> com.pekam.TblGpsController.findAll()
2014-05-14 08:15:41.464  INFO 2280 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/TblGps/get],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public com.pekam.TblGps com.pekam.TblGpsController.findById(long)
2014-05-14 08:15:41.471  INFO 2280 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/TblGps/update],methods=[POST],params=[],headers=[],consumes=[application/json],produces=[application/xml || application/json],custom=[]}" onto public com.pekam.TblGps com.pekam.TblGpsController.post(com.pekam.TblGps)
2014-05-14 08:15:41.478  INFO 2280 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/*],methods=[GET || POST || DELETE || PUT || HEAD],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.pekam.TblGpsController.allFallback()
2014-05-14 08:15:42.701  INFO 2280 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-05-14 08:15:42.706  INFO 2280 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-05-14 08:15:56.645  INFO 2280 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-05-14 08:15:57.551  INFO 2280 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-05-14 08:15:57.665  INFO 2280 --- [           main] com.pekam.Application                    : Started Application in 46.091 seconds (JVM running for 46.681)

stacktrace of exception:

400 Bad Request
: org.springframework.web.client.HttpClientErrorException: 400 Bad Request
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:76)
    at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:524)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:481)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:439)
    at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:317)
    at com.pekam.myandroid.MainActivity$HttpRequestTask.doInBackground(MainActivity.java:106)
    at com.pekam.myandroid.MainActivity$HttpRequestTask.doInBackground(MainActivity.java:1)
    at android.os.AsyncTask$2.call(AsyncTask.java:288)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    at java.lang.Thread.run(Thread.java:841)

here is my code of the data class:

/**
 * The persistent class for the tblGps database table.
 * 
 */
@Entity
@Table(name="tblGps")
@NamedQuery(name="TblGps.findAll", query="SELECT t FROM TblGps t")
public class TblGps implements Serializable {
    private static final long serialVersionUID = 1L;
    private long id;
    private Timestamp date ;
    private String descr;
    private int gpsCordsX;
    private int gpsCordsY;
    private int userid;

    @SuppressWarnings("deprecation")
    public TblGps() {


        date= new Timestamp(0,0,0,0,0, 0, 0);
    }


    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(unique=true, nullable=false)
    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }


    @Column(nullable=false)
    public Timestamp getDate() {
        return this.date;
    }

    public void setDate(Timestamp date) {
        this.date = date;
    }


    public String getDescr() {
        return this.descr;
    }

    public void setDescr(String descr) {
        this.descr = descr;
    }


    @Column(nullable=false, precision=53)
    public int getGpsCordsX() {
        return this.gpsCordsX;
    }

    public void setGpsCordsX(int gpsCordsX) {
        this.gpsCordsX = gpsCordsX;
    }


    @Column(nullable=false, precision=53)
    public int getGpsCordsY() {
        return this.gpsCordsY;
    }

    public void setGpsCordsY(int gpsCordsY) {
        this.gpsCordsY = gpsCordsY;
    }


    @Column(nullable=false)
    public int getUserid() {
        return this.userid;
    }

    public void setUserid(int userid) {
        this.userid = userid;
    }

}

Solution

  • I don't know why this is the way it is, but the error was that I had to receive the @RequestBody as TblGps[] Array and not as single object!

    Although i've fetched and received the same object before and received the result as single object, ...and then I posted it back to the server, and received it as array of objects ... ist it wired?

    Does anybody has an explanation for this behaviour ??

        TblGps gps = (TblGps) restTemplate.getForObject(urlGET,TblGps.class);
    
    
     // alter the Object Data
    
    
     gps.setDescr("success");
    
          //POST Object to Service Endpoint
          TblGps gpsResult = restTemplate.postForObject(urlPOST, "POST", TblGps.class, gps);
    

    and my Controller code

     @RequestMapping(value="/TblGps/update", method=RequestMethod.POST, consumes = "application/json",produces="application/json")
          @ResponseBody public TblGps postSingleObject(@RequestBody  TblGps[] gps){
    
                logger.debug("/TblGps/update: " + gps[0].getId());
    
                  return Application.DataRepository.save(gps[0]);
            }