HttpMessageNotReadableException: не удалось прочитать JSON: непризнанное поле, использующее Spring для Android

Я разрабатываю приложение для Android, которое общается с моим сервером. Это сообщение выполняется через Spring Framework и Jackson. Я отправляю запрос на свой сервер успешно, но я не получаю ответа. Вот что я сделал:

Приложение для Android:

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 (у меня есть две версии: одна в Android-приложении и другие на сервере. Они абсолютно одинаковы):

 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; } } 

И вот мой контроллер:

 @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; } 

Со всем этим я получаю исключение в Android-приложении:

 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 

По тому, что я обнаружил, он не признает мой класс Лоха. Но они точно такие же! Что еще это может быть?

Solutions Collecting From Web of "HttpMessageNotReadableException: не удалось прочитать JSON: непризнанное поле, использующее Spring для Android"

Исключение, по-видимому, предполагает, что, хотя разработчик Джексона пытается создать Loja из возвращенного json, он столкнулся с полем json с ключом Loja, который он не знал, как обращаться (потому что в Loja нет полей Java-объект с именем «Loja»), поэтому он не удался. Это кажется логичным, потому что кажется, что сервер эффективно возвращает эту структуру json:

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

Из-за этого у вас есть два основных варианта.

  1. Измените объект, который передается getForObject() или
  2. Измените json, возвращенный с сервера.

Для первого вы можете заставить своего клиента выполнить getForObject() проходящую в Object который содержит Loja .

Что-то вроде этого класса:

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

Используя этот вызов:

 restTemplate.getForObject(url, MyObj.class); 

Кроме того, вы можете вернуть серверу объекты Loja в качестве части модели или, вернее, вернуть экземпляр созданного вами объекта Loja . Весна достаточно умен, чтобы использовать Джексона, чтобы превратить ваш POJO в подходящую модель json, которую вы ожидаете.

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

Который произведет этот json:

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

Который мог бы быть getForObject() вашим getForObject() на стороне клиента так же, как сейчас.

Я обнаружил, что не так с моим кодом. Николас был прав, мой JSON был чем-то вроде:

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

И поле Loja не узнавалось при отправке в приложение Android.

Вот что я сделал: я создал еще один класс под названием Lojas, который имеет не что иное, как 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; } } 

В моем методе getLoja (), я возвращаю этот новый метод:

 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); } 

Таким образом, я могу запросить объект List of Loja сразу. Но для этого мне пришлось сменить серверную сторону, чтобы всегда возвращать объект List of Loja:

 @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; } 

Я решил эту проблему сделать JSON Post с помощью 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(); } 

Главное, чтобы мой HttpEntity мне пришлось установить в String .

Надеюсь, это может помочь кому-то.