【问题标题】:HttpMessageNotReadableException: Could not read JSON: Unrecognized field using Spring for AndroidHttpMessageNotReadableException:无法读取 JSON:使用 Spring for Android 无法识别的字段
【发布时间】:2013-03-11 18:25:19
【问题描述】:

我正在开发与我的服务器通信的 Android 应用程序。这种通信是通过 Spring 框架和 Jackson 完成的。我正在成功发送对我的服务器的请求,但没有收到响应。这是我所做的:

安卓应用:

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 类(我有两个版本。一个在 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

据我所知,它不承认我的 Loja 课程。但它们完全一样!还能是什么?

【问题讨论】:

    标签: android spring jackson


    【解决方案1】:

    异常似乎表明,当 Jackson 映射器试图从返回的 json 创建一个 Loja 时,它遇到了一个带有 Loja 键的 json 字段,它不知道如何处理(因为有Loja java 对象中没有名为“Loja”的字段),所以它失败了。这似乎是合乎逻辑的,因为服务器似乎有效地返回了这个 json 结构:

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

    因此,您有两个主要选择。

    1. 更改传递给getForObject()或的对象
    2. 更改从服务器返回的 json。

    对于第一个,您可以让您的客户执行 getForObject() 传递一个包含 LojaObject

    类似这样的类:

    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 对象的实例。 Spring 足够聪明,可以利用 Jackson 将您的 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() 方法可以按照当前的方式读取它。

    【讨论】:

    • 感谢您的回答,但它不起作用..您对生成的 json 是正确的,我不知道为什么,但它在开始时创建了一个字段“Loja”细绳。我尝试按照您的建议将 getLoja() 返回更改为 Loja,但我仍然得到相同的 json .. 根据您的建议,生成的 json 是:{"loja":{"nome":"teste","xValue ":"20","yValue":"30","andar":"1"}}
    • 您做了哪些更改?我相信我提供了几个潜在的解决方案,而不是单一的解决方案。您能否用您所做的无效更改更新您的问题?
    • 感谢您的想法!它有助于弄清楚如何解决它!我发布了一个答案,解释了我是如何做到的。看看吧
    【解决方案2】:

    我发现我的代码有什么问题。 Nicholas 是对的,我的 JSON 类似于:

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

    当发送到 Android 应用程序时,Loja 字段未被识别。

    这就是我所做的:我创建了另一个名为 Lojas 的类,它只不过是一个 Loja 列表。

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

    这样,我可以立即请求 Loja 对象列表。但要做到这一点,我必须更改服务器端以始终返回 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;
        }
    

    【讨论】:

    • 您真的应该接受@nicholas.hauschild 的回答,如果您想为其他人添加更多详细信息,也应该回答它。他做了这项工作,他的回答将引导您找到解决方案。
    【解决方案3】:

    我使用RestTemplate 制作了JSON Post 解决了这个问题。

    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

    我希望它可以帮助某人。

    【讨论】:

      【解决方案4】:

      明确定义一个空的构造函数对我来说很有帮助,否则我使用 restTemplate 的测试会失败。

      【讨论】:

        【解决方案5】:

        在父对象中引入无 args 构造函数将起作用。

        【讨论】:

        • 不要提供描述性答案,而是尝试使用代码 sn-p 来回答以更好地理解
        猜你喜欢
        • 2020-11-29
        • 2015-08-28
        • 2019-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多