【问题标题】:Can not deserialize instance of java.util.ArrayList out of VALUE_STRING无法将 java.util.ArrayList 的实例反序列化出 VALUE_STRING
【发布时间】:2013-01-13 08:48:36
【问题描述】:

我有一个使用 Jersey 构建并部署在 AppEngine 中的 REST 服务。 REST 服务实现了使用 application/json 媒体类型的动词 PUT。数据绑定由 Jackson 执行。

动词使用以 JSON 表示的企业-部门关系

{"name":"myEnterprise", "departments":["HR","IT","SC"]}

在客户端,我使用 gson 将 JSON 表示形式转换为 java 对象。然后,我将对象传递给我的 REST 服务,它工作正常。

问题:

当我的 JSON 表示在集合中只有一项时

{"name":"myEnterprise", "departments":["HR"]}

服务无法反序列化对象。

ATTENTION: /enterprise/enterprise: org.codehaus.jackson.map.JsonMappingException: 
Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token at 
[Source: org.mortbay.jetty.HttpParser$Input@5a9c5842; line: 1, column: 2

正如其他用户所报告的,解决方案是添加标志 ACCEPT_SINGLE_VALUE_AS_ARRAY(例如,Jersey: Can not deserialize instance of ArrayList out of String)。尽管如此,我并没有控制ObjectMapper,因为在服务端它是由杰克逊透明地制作的。

问题:

有没有办法在服务端配置ObjectMapper来启用ACCEPT_SINGLE_VALUE_AS_ARRAY?注释? web.xml?

代码详情

Java 对象:

@XmlRootElement
public class Enterprise {
    private String name;
    private List<String> departments;

    public Enterprise() {}

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<String> getDepartments() {
        return departments;
    }
    public void setDepartments(List<String> departments) {
        this.departments = departments;
    }
}

REST 服务端:

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/enterprise") 
    public Response putEnterprise(Enterprise enterprise,
            @Context HttpServletRequest req){
         ...
    }

客户端:

...
String jsonString = "{\"name\":\"myEnterprise\", \"departments\":[\"HR\"]}";
Enterprise enterprise = gson.fromJson(jsonString, Enterprise.class);
System.out.println(gson.toJson(enterprise));
response = webResource              
           .type(MediaType.APPLICATION_JSON)
           .put(ClientResponse.class,enterprise);
if (response.getStatus() >= 400) {
        throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
...

【问题讨论】:

标签: java json arraylist jackson json-deserialization


【解决方案1】:

这是我老问题的解决方案:

我实现了自己的ContextResolver 以启用DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY 功能。

package org.lig.hadas.services.mapper;

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;

@Produces(MediaType.APPLICATION_JSON)
@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper>
{
   ObjectMapper mapper;

   public ObjectMapperProvider(){
       mapper = new ObjectMapper();
       mapper.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
   }
   @Override
   public ObjectMapper getContext(Class<?> type) {
       return mapper;
   }
}

web.xml 中,我将我的包注册到 servlet 定义中...

<servlet>
    <servlet-name>...</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>...;org.lig.hadas.services.mapper</param-value>        
    </init-param>
    ...
</servlet>

...其余的一切都由 jersey/jackson 透明地完成。

【讨论】:

  • 新版本:objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
【解决方案2】:

将此属性设置为 ObjectMapper 实例有效,

objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);

【讨论】:

  • 他的问题是如何在不访问 ObjectManager 的情况下设置该标志。
【解决方案3】:

你试试

[{"name":"myEnterprise", "departments":["HR"]}]

方括号是重点。

【讨论】:

  • 问题出在“部门”级别。这是杰克逊的一个特殊性,我通过创建自己的 ContextResolver 解决了它
【解决方案4】:

从 Jackson 2.7.x+ 开始,有一种方法可以注释成员变量本身:

 @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
 private List<String> newsletters;

更多信息在这里:Jackson @JsonFormat

【讨论】:

    【解决方案5】:

    对于通过搜索错误消息找到此问题的人,如果您在 @JsonProperty 注释中出现错误,例如使用单个名称注释 List-typed 属性,您也会看到此错误值字段:

    @JsonProperty("someSingleValuedField") // Oops, should have been "someMultiValuedField"
    public List<String> getMyField() { // deserialization fails - single value into List
      return myField;
    }
    

    【讨论】:

    • “反序列化”不是使用setter而不是getter吗?据我所知,在序列化期间访问 Getter
    • 反序列化可以使用 setter 或反射,但我记得按惯例注释在 getter 上
    猜你喜欢
    • 2017-03-02
    • 2018-03-30
    • 2019-09-22
    • 1970-01-01
    • 2017-08-25
    • 2022-12-21
    • 2021-06-09
    • 2014-01-17
    相关资源
    最近更新 更多