无法从 Spring Webservice 中的 START_ARRAY 令牌反序列化对象实例

Posted

技术标签:

【中文标题】无法从 Spring Webservice 中的 START_ARRAY 令牌反序列化对象实例【英文标题】:Cannot deserialize instance of object out of START_ARRAY token in Spring Webservice 【发布时间】:2014-10-20 00:43:51 【问题描述】:

我目前无法连接到我在 android 上的网络服务。我使用 jackson-core/databind/annotation-2.2.4 和 Spring RESTWebService。如果我从浏览器访问 URL,我可以看到 JSON 响应:(服务器返回 List\Shop\ 看起来像:)

["name":"shopqwe","mobiles":[],"address":"town":"city",
"street":"streetqwe","streetNumber":"59","cordX":2.229997,"cordY":1.002539,
"shoe" ["shoeName":"addidas","number":"631744030","producent":"nike","price":999.0,
"sizes":[30.0,35.0,38.0]]

从客户端端点(Android 应用程序)我收到以下错误消息:

08-26 17:43:07.406: E/AllShopsAsyc(28203): Could not read JSON: Can not deserialize
instance of com.auginzynier.data.ShopContainer out of START_ARRAY token
08-26 17:43:07.406: E/AllShopsAsyc(28203):  at [Source:
com.android.okhttp.internal.http.HttpTransport$ChunkedInputStream@41efbd48; line: 1,
column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException:
Can not deserialize instance of com.auginzynier.data.ShopContainer out of START_ARRAY
token
08-26 17:43:07.406: E/AllShopsAsyc(28203):  at [Source:
com.android.okhttp.internal.http.HttpTransport$ChunkedInputStream@41efbd48; line: 1,
column: 1] 
08-26 17:43:07.406: E/AllShopsAsyc(28203):
org.springframework.http.converter.HttpMessageNotReadableException: Could not read
JSON: Can not deserialize instance of com.auginzynier.data.ShopContainer out of
START_ARRAY token

我的服务器请求

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
ShopContainer response  = restTemplate.getForObject(url, ShopContainer.class);

ShopContainer 在哪里:

public class ShopContainer 
   private List<Shop> shops;

Shop、Address 和 Shoe 的结构是:(我省略了 getter 和 setter):

public class Shop 
@JsonProperty("name")    private String name;
@JsonProperty("mobiles")   private List<String> mobiles = new ArrayList<String>();
@JsonProperty("address")   private Address address;
@JsonProperty("shoe") private List<Shoe> shoe = new ArrayList<Shoe>();

public class Address 
@JsonProperty("town") private String town;
@JsonProperty("street") private String street;
@JsonProperty("streetNumber") private String streetNumber;
@JsonProperty("cordX") private Double cordX;
@JsonProperty("cordY") private Double cordY;

public class Shoe 
@JsonProperty("shoeName") private String shoeName;
@JsonProperty("number") private String number;
@JsonProperty("producent") private String producent;
@JsonProperty("price") private Double price;
@JsonProperty("sizes") private List<Double> sizes = new ArrayList<Double>();

我在这里和谷歌上看过,但仍然无法弄清楚我现在缺少什么。

任何回应都会非常有帮助。

问候。

@UPDATE

我已经通过使用杰克逊的 ObjectMapper 和 RequestMethod.GET 修复了 JSON。它现在返回一个字符串。

list is List<Shop>

ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(new File("D:\\Android\\shop.json"), list);
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(list));
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(list);

控制台中的 JSON 如下所示:

[ 
  "name" : "shopqwe",
  "mobiles" : [ ],
  "address" : 
    "town" : "city",
    "street" : "streetqwe",
    "streetNumber" : "59",
    "cordX" : 2.229997,
    "cordY" : 2.002539
  ,
  "shoe" : [ 
    "shoeName" : "addidas",
    "number" : "631744033",
    "producent" : "nike",
    "price" : 10.0,
    "sizes" : [ 30.0, 35.0, 38.0 ]
   ]
 ]

请求仍然不起作用 - 错误是一样的。

【问题讨论】:

【参考方案1】:

您的 json 包含一个数组,但您正试图将其解析为一个对象。 出现此错误是因为对象必须以 开头。

你有两个选择:

    您可以摆脱 ShopContainer 类并改用 Shop[]

    ShopContainer response  = restTemplate.getForObject(
        url, ShopContainer.class);
    

    替换为

    Shop[] response  = restTemplate.getForObject(url, Shop[].class);
    

    然后从中制作您想要的对象。

    您可以更改服务器以返回对象而不是列表

    return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(list);
    

    替换为

    return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(
        new ShopContainer(list));
    

【讨论】:

什么 id shop[] 是另一个对象的内部字段,而不是主对象。我们如何将其与父对象的映射分开?【参考方案2】:

认为您发布的 JSON 实际上是您在浏览器中看到的内容,那么问题出在 JSON 本身。

您发布的 JSON sn-p 格式不正确。

您已发布:

[
        "name" : "shopqwe",
        "mobiles" : [],
        "address" : 
            "town" : "city",
            "street" : "streetqwe",
            "streetNumber" : "59",
            "cordX" : 2.229997,
            "cordY" : 1.002539
        ,
        "shoe"[
                "shoeName" : "addidas",
                "number" : "631744030",
                "producent" : "nike",
                "price" : 999.0,
                "sizes" : [30.0, 35.0, 38.0]
            ]

而正确的 JSON 应该是:

[
        "name" : "shopqwe",
        "mobiles" : [],
        "address" : 
            "town" : "city",
            "street" : "streetqwe",
            "streetNumber" : "59",
            "cordX" : 2.229997,
            "cordY" : 1.002539
        ,
        "shoe" : [
                "shoeName" : "addidas",
                "number" : "631744030",
                "producent" : "nike",
                "price" : 999.0,
                "sizes" : [30.0, 35.0, 38.0]
            
        ]
    
]

【讨论】:

谢谢,我将 RequestMethod.GET 更改为返回包含 mapper.writeValue(new File("D:\\Android\\shop.json"), list); 的字符串;返回 mapper.writerWithDefaultPrettyPrinter().writeValueAsString(list); 它返回正确的 JSON,但错误并没有消失 尝试实现可序列化接口怎么样?【参考方案3】:

我在使用spring-boot-starter-data-redis 时遇到了非常相似的问题。在我的实现中,为RedisTemplate 提供了一个@Bean,如下所示:

@Bean
public RedisTemplate<String, List<RoutePlantCache>> redisTemplate(RedisConnectionFactory connectionFactory) 
    final RedisTemplate<String, List<RoutePlantCache>> template = new RedisTemplate<>();
    template.setConnectionFactory(connectionFactory);
    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(new Jackson2JsonRedisSerializer<>(RoutePlantCache.class));

    // Add some specific configuration here. Key serializers, etc.
    return template;

修复方法是指定RoutePlantCache 的数组,如下所示:

template.setValueSerializer(new Jackson2JsonRedisSerializer<>(RoutePlantCache[].class));

在我遇到的例外情况下:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `[...].RoutePlantCache` out of START_ARRAY token
 at [Source: (byte[])"[ ... , ... [truncated 1478 bytes]; line: 1, column: 1]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1468) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1242) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1190) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeFromArray(BeanDeserializer.java:604) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:190) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:166) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4526) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3572) ~[jackson-databind-2.11.4.jar:2.11.4]

【讨论】:

以上是关于无法从 Spring Webservice 中的 START_ARRAY 令牌反序列化对象实例的主要内容,如果未能解决你的问题,请参考以下文章

CXF WebService整合Spring

WebService与Spring整合部署

调用 WebService 时出错 - 无法初始化代理 - 没有会话

Spring Boot webservice (REST) - 如何将 JUnit 5 测试从基本身份验证更改为 OAuth2 (Keycloak)

如何通过 Preflight Request 从 javascript 调用 REST Webservice?

Spring boot 开发WebService遇到的问题之一