簡體   English   中英

HttpMessageNotReadableException:無法讀取 JSON:使用 Spring for Android 無法識別的字段

[英]HttpMessageNotReadableException: Could not read JSON: Unrecognized field using Spring for Android

我正在開發與我的服務器通信的 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 類。 但它們完全一樣! 還能是什么?

異常似乎表明,當傑克遜映射器試圖從返回的 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()方法可以按照當前的方式讀取。

我發現了我的代碼有什么問題。 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;
    }

我使用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

我希望它可以幫助某人。

明確定義一個空的構造函數對我有幫助,否則我使用 restTemplate 的測試將失敗。

在父對象中引入 no args 構造函數將起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM