Jersey:无法将字符串反序列化为ArrayList实例

13

我有一个使用Jetty、Jersey、Jersey-JSON和Jackson实现的基于json的REST Web服务。

我的其中一个方法接收一个Person实例,其中包含一个类型为List<String>的字段。 即:

Public class Person {
    List<String> names;
}
如果我用一个名字数组来调用它,一切都很正常!例如:
{ "names" : [ "Jhon", "Doe" ] }

但如果这个人只有一个名字,我的客户端将创建一个单值元素,例如:

{ "names" : "Jhon" } 

当我尝试使用单个值调用该服务时,我会收到一个异常:

Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token

问题:

我应该如何创建/配置我的Web服务,以便在将数组字段作为单个元素发送给我时能够反序列化它们。

--

我已经阅读了以下内容:

Jackson反序列化-包含ArrayList<T>

如何自定义JAXB对象列表的JSON序列化?

还有这个参考最后一个答案:

Jersey客户端无法反序列化JSON服务-异常(无法反序列化实例)

JAXB JSON缺少一个元素数组的括号

但是这些都没有解决问题。

非常感谢!

5个回答

14

经过漫长的一天,再次阅读了许多维基和常见问题解答后,它终于起作用了。

我做了以下几点:

  1. 使用Jackson
  2. 强制使用Jackson提供程序
  3. 定义自定义反序列化器
  4. 激活ACCEPT_SINGLE_VALUE_AS_ARRAY标志
  5. 修复依赖项

故事如下:

我一直在使用Jersey 1.13,默认情况下使用(我相信)jaxb。

我将其更改为使用Jackson

<init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
</init-param>

如下所述:

https://stackoverflow.com/a/13895768/660990

这使得我的球衣使用了Jackson,但问题仍然存在;Jackson目前无法反序列化数组。
我强制使用了Jackson提供程序
<init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>
        your.project.packages;
        org.codehaus.jackson.jaxrs</param-value>
</init-param>

https://dev59.com/tnI95IYBdhLWcg3wsQBm#3143214

这是必要的一步,但还不够。需要激活ACCEPT_SINGLE_VALUE_AS_ARRAY标志。

ObjectMapper objectMapper;
objectMapper = new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

我需要定义一个自定义反序列化器。
public class MyResolver implements ContextResolver<ObjectMapper> {

@Override
    public ObjectMapper getContext(final Class<?> objectType) {
        ...            
        return objectMapper;
    }
}

为了做到这一点: 自定义ObjectMapper 尽管完成了所有这些,它仍然没有起作用...
经过更多的搜索时间,我找到了: Jackson 2.0与Jersey 1.12 其中讨论了依赖问题。
这揭示了我的问题,Jersey v1.13附带了Jackson v1.9.2,我需要Jackson v2.0。
我删除了jersey-json的依赖,因为它包含了jackson 1.9.2。
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-json</artifactId>
</dependency>

直接声明依赖项:

<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-json-provider</artifactId>
</dependency>

参考:

jackson-jaxrs-json-provider

注意: 此更改将删除Jersey使用Jaxb或jettison的功能。

离题,可能对某些人有趣:

配置Jersey / Jackson以不使用@XmlElement字段注释进行JSON字段命名


1
谢谢,伙计。以下这行代码解决了我的问题:objectMapper = new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); - mojsilo
@mojsilo,你把这个objectMapper = new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);放在哪里了? - Luke
我已将其放置在服务的构造函数中 mapper.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY,true); - mojsilo

5
您可以使用在类、字段或方法级别的注释来完成此操作,使用JsonFormat注释即可。
@JsonFormat(with = Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
protected List<String> list;

public List<String> getList() {
    return list;
}

public void setList(List<String> list) {
    this.list = list;
}

1

本页面的示例5.10和5.11解释了您的确切问题。您可以配置JSON builder,强制将单项列表转换为数组,就像这样:JSONConfiguration.mapped().arrays("names").build()


1
谢谢!但我想在服务器端解决这个问题。已经更新了我的问题以明确表述。 - lpinto.eu
你会在客户端的哪里添加 **JSONConfiguration.mapped().arrays("names").build()**?是在构建请求后,但发送请求前吗? - Luke

1
{"results": {"place": {"lang": "en-US","woeid": "2168606"}}}

&

{"results": {"place": [{"lang": "en-US","woeid": "2168606"}, {"lang": "en-US","woeid": "2168606"}]}}

使用Yahoo地点API时如何处理此类型...


1

通过在类中添加@JsonSerialize,它对我起作用了。

@JsonSerialize
Public class Person {
    List<String> names;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接