HttpMessageNotReadableException: Failed to read JSON: Unrecognized field using Spring for Android

I am developing an Android application that communicates with my server. This post runs through Spring and Jackson framework. I am sending a request to my server successfully, but I am not getting a response. Here is what I did:

Android app:

public Loja getLoja() { RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter()); restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory()); String url = BASE_URL + "/android/played.json"; return restTemplate.getForObject(url, Loja.class); } 

Loja class (I have two versions of it: one in the Android application and the other on the server. They are exactly the same):

 public class Loja { private String nome; private String xValue; private String yValue; private String andar; public Loja(String nome, String xValue, String yValue, String andar) { this.nome = nome; this.xValue = xValue; this.yValue = yValue; this.andar = andar; } public Loja() { } public String getAndar() { return andar; } public void setAndar(String andar) { this.andar = andar; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getxValue() { return xValue; } public void setxValue(String xValue) { this.xValue = xValue; } public String getyValue() { return yValue; } public void setyValue(String yValue) { this.yValue = yValue; } } 

And here is my controller:

 @RequestMapping("/android/played") public ModelAndView getLoja() { System.out.println("Android Resquest."); Loja loja = new Loja("teste", "20", "30", "1"); ModelAndView mav = new ModelAndView(); mav.addObject("Loja", loja); return mav; } 

With all this, I get the following exception in the Android app:

 03-21 22:13:06.197: E/AndroidRuntime(25342): java.lang.RuntimeException: An error occured while executing doInBackground() 03-21 22:13:06.197: E/AndroidRuntime(25342): at android.os.AsyncTask$3.done(AsyncTask.java:299) 03-21 22:13:06.197: E/AndroidRuntime(25342): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 03-21 22:13:06.197: E/AndroidRuntime(25342): at java.util.concurrent.FutureTask.setException(FutureTask.java:124) 03-21 22:13:06.197: E/AndroidRuntime(25342): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) 03-21 22:13:06.197: E/AndroidRuntime(25342): at java.util.concurrent.FutureTask.run(FutureTask.java:137) 03-21 22:13:06.197: E/AndroidRuntime(25342): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) 03-21 22:13:06.197: E/AndroidRuntime(25342): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 03-21 22:13:06.197: E/AndroidRuntime(25342): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 03-21 22:13:06.197: E/AndroidRuntime(25342): at java.lang.Thread.run(Thread.java:856) 03-21 22:13:06.197: E/AndroidRuntime(25342): Caused by: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unrecognized field "Loja" (Class com.example.androidspring.Loja), not marked as ignorable 03-21 22:13:06.197: E/AndroidRuntime(25342): at [Source: org.apache.http.conn.EofSensorInputStream@422e3c58 ; line: 1, column: 10] (through reference chain: com.example.androidspring.Loja["Loja"]); nested exception is org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "Loja" (Class com.example.androidspring.Loja), not marked as ignorable 03-21 22:13:06.197: E/AndroidRuntime(25342): at [Source: org.apache.http.conn.EofSensorInputStream@422e3c58 ; line: 1, column: 10] (through reference chain: com.example.androidspring.Loja["Loja"]) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:125) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:147) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:76) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:484) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:439) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:237) 03-21 22:13:06.197: E/AndroidRuntime(25342): at com.example.androidspring.MainActivity.getLoja(MainActivity.java:59) 03-21 22:13:06.197: E/AndroidRuntime(25342): at com.example.androidspring.MainActivity$DownloadFilesTask.doInBackground(MainActivity.java:72) 03-21 22:13:06.197: E/AndroidRuntime(25342): at com.example.androidspring.MainActivity$DownloadFilesTask.doInBackground(MainActivity.java:1) 03-21 22:13:06.197: E/AndroidRuntime(25342): at android.os.AsyncTask$2.call(AsyncTask.java:287) 03-21 22:13:06.197: E/AndroidRuntime(25342): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 03-21 22:13:06.197: E/AndroidRuntime(25342): ... 5 more 03-21 22:13:06.197: E/AndroidRuntime(25342): Caused by: org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "Loja" (Class com.example.androidspring.Loja), not marked as ignorable 03-21 22:13:06.197: E/AndroidRuntime(25342): at [Source: org.apache.http.conn.EofSensorInputStream@422e3c58 ; line: 1, column: 10] (through reference chain: com.example.androidspring.Loja["Loja"]) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.codehaus.jackson.map.deser.StdDeserializationContext.unknownFieldException(StdDeserializationContext.java:267) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.codehaus.jackson.map.deser.std.StdDeserializer.reportUnknownProperty(StdDeserializer.java:649) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.codehaus.jackson.map.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:635) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.codehaus.jackson.map.deser.BeanDeserializer.handleUnknownProperty(BeanDeserializer.java:1355) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:717) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:580) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2723) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1914) 03-21 22:13:06.197: E/AndroidRuntime(25342): at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:122) 03-21 22:13:06.197: E/AndroidRuntime(25342): ... 15 more 

By what I discovered, it does not recognize my Loja class. But they are exactly the same! What else could be?

+7
source share
3 answers

The exception seems to be that although Jackson's developer is trying to create Loja from the returned json, he came across a json field with a Loja key that he did not know how to handle (because there are no fields in the Loja java object named "Loja") so he failed. This seems logical, because it seems that the server is effectively returning this json structure:

 {"Loja":{"nome":"teste","xValue":"20","yValue":"30","andar":"1"}} 

Because of this, you have two main options.

  • Change the object that is being passed to getForObject() or
  • Change json returned from server.

For the first, you can make your client getForObject() passing in an Object that contains Loja .

Something like this class:

 class MyObj { private Loja Loja; public void setLoja(Loja loja) { this.Loja = loja; } public Loja getLoja() { return this.Loja; } } 

used with this call:

 restTemplate.getForObject(url, MyObj.class); 

Alternatively, you can return the Loja object tags to the server as part of the model, or rather, return an instance of the Loja object created. Spring is smart enough to use Jackson to turn your POJO into the right json model you expect.

 @RequestMapping("/android/played") public Loja getLoja() { System.out.println("Android Resquest."); return new Loja("teste", "20", "30", "1"); } 

To create this json:

 {"nome":"teste","xValue":"20","yValue":"30","andar":"1"} 

which will be readable by your getForObject() method on the client side just as it is now.

+9
source

I found what is wrong with my code. Nicholas was right, my JSON was something like:

 {"Loja":{"nome":"teste","xValue":"20","yValue":"30","andar":"1"}} 

and the Loja field was not recognized when sent to the Android application.

Here's what I did: I created another class called Lojas, which has nothing but a Loja List.

 public class Lojas { private List<Loja> lojas; public Lojas() { } public List<Loja> getLojas() { return lojas; } public void setLojas(List<Loja> lojas) { this.lojas = lojas; } } 

in my getLoja () method, I return this new created method:

 public Lojas getLoja() { RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter()); restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory()); String url = BASE_URL + "/android/played.json"; return restTemplate.getForObject(url, Lojas.class); } 

that way I can query the List of Loja object right away. but for this I had to change the server side to always return a List of Loja object:

 @RequestMapping("/android/played") public ModelAndView getLoja() { System.out.println("Android Request."); List<Loja> list = new ArrayList<Loja>(); list.add(new Loja("teste", "20", "30", "1")); list.add(new Loja("teste2", "20", "30", "1")); ModelAndView mav = new ModelAndView(); mav.addObject("lojas", list); return mav; } 
+2
source

I solved this problem by creating a JSON Post using RestTemplate .

 HTTP_HEADERS.setContentType(MediaType.APPLICATION_JSON); final ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter(); final String body = ow.writeValueAsString(convertedFireCsvBeans); final HttpEntity<String> entity = new HttpEntity<>(body, HTTP_HEADERS); final ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<String>(){}; final ResponseEntity<String> responseEntity = REST_TEMPLATE.exchange(url, HttpMethod.POST, entity, responseType); if(responseEntity.getStatusCode() != null){ System.out.println("HTTP STATUS CODE: " + responseEntity.getStatusCode() + "\n"+ responseEntity.getStatusCode().getReasonPhrase()); httpStatus = responseEntity.getStatusCode(); } 

The main HttpEntity that for my HttpEntity I need to install String .

I hope this can help someone.

+2
source

All Articles