我有一个使用Jersey构建并部署在AppEngine中的REST服务。REST服务实现使用application/json媒体类型的动词PUT 。数据绑定由Jackson进行。
application/json
该动词使用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。但是,我无法控制,ObjectMapper因为在服务方面,它是由Jackson透明制造的。
ACCEPT_SINGLE_VALUE_AS_ARRAY
ObjectMapper
题:
有没有一种方法可以ObjectMapper在服务端配置启用ACCEPT_SINGLE_VALUE_AS_ARRAY?注释?web.xml?
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()); } ...
这是我的老问题的解决方案:
我ContextResolver启用了自己的DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY功能以启用该功能。
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>
…其余所有工作都是由球衣/杰克逊透明完成的。