无法将 java.util.ArrayList 的实例反序列化出 VALUE_STRING
Posted
技术标签:
【中文标题】无法将 java.util.ArrayList 的实例反序列化出 VALUE_STRING【英文标题】:Can not deserialize instance of java.util.ArrayList out of 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());
...
【问题讨论】:
Jackson deserialization - with contained ArrayList<T>的可能重复 我同意。大概是一样的。但是,这里我的具体问题是如果我不管理 ObjectMapper,如何设置 ACCEPT_SINGLE_VALUE_AS_ARRAY 标志……如果可能的话。 【参考方案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 上以上是关于无法将 java.util.ArrayList 的实例反序列化出 VALUE_STRING的主要内容,如果未能解决你的问题,请参考以下文章
转换 Arrays.asList 导致异常:java.util.Arrays$ArrayList 无法转换为 java.util.ArrayList
错误:找不到字段的设置器。 - java.util.ArrayList 中的大小 - Room 中的嵌入式 ArrayList 无法编译
Hive Generic UDF:Hive 未按预期进行转换,原因是:java.lang.ClassCastException:java.util.ArrayList 无法转换为 java.util.
无法从 START_OBJECT 令牌中反序列化 java.util.ArrayList 的实例
Recyclerview 适配器:java.util.ArrayList 无法转换为 com.google.firebase.firestore.QuerySnapshot