I have a REST service built with Jersey and deployed in the AppEngine. The REST service implements the verb PUT that consumes an application/json media type. The data binding is performed by Jackson.
我有一个与Jersey一起构建并部署在AppEngine中的REST服务。REST服务实现使用应用程序/json媒体类型的谓词PUT。数据绑定由Jackson执行。
The verb consumes an enterprise-departments relation represented in JSON as
谓词使用以JSON表示的企业部门关系。
{"name":"myEnterprise", "departments":["HR","IT","SC"]}
In the client side, I use gson to convert the JSON representation into a java object. Then, I pass the object to my REST service and it works fine.
在客户端,我使用gson将JSON表示转换为java对象。然后,我将对象传递给REST服务,它可以正常工作。
Problem:
问题:
When my JSON representation has only one item in the collection
当我的JSON表示在集合中只有一个项时
{"name":"myEnterprise", "departments":["HR"]}
the service cannot deserialize the object.
服务不能反序列化对象。
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
As reported by other users, the solution is to add the flag ACCEPT_SINGLE_VALUE_AS_ARRAY (e.g., Jersey: Can not deserialize instance of ArrayList out of String). Nevertheless, I am not controlling an ObjectMapper because in the service side it is transparently made by Jackson.
正如其他用户所报告的,解决方案是添加flag ACCEPT_SINGLE_VALUE_AS_ARRAY(例如,Jersey:不能将ArrayList的实例从字符串中反序列化)。不过,我并没有控制ObjectMapper,因为在服务端,它是由Jackson透明制作的。
Question:
问题:
Is there a way to configure the ObjectMapper on the service side to enable ACCEPT_SINGLE_VALUE_AS_ARRAY? annotations? web.xml?
是否有办法在服务端配置ObjectMapper以启用ACCEPT_SINGLE_VALUE_AS_ARRAY?注释吗?web . xml ?
Code details
代码的细节
Java object:
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;
}
}
The REST service side:
其余服务端:
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("/enterprise")
public Response putEnterprise(Enterprise enterprise,
@Context HttpServletRequest req){
...
}
Client side:
客户端:
...
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());
}
...
4 个解决方案
#1
41
This is the solution for my old question:
这是我的老问题的解决方案:
I implemented my own ContextResolver in order to enable the DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY feature.
为了启用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;
}
}
And in the web.xml I registered my package into the servlet definition...
和网络。我将我的包注册到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>
... all the rest is transparently done by jersey/jackson.
…剩下的都是由泽西/杰克逊做的。
#2
15
do you try
你试一试
[{"name":"myEnterprise", "departments":["HR"]}]
the square brace is the key point.
方括号是关键。
#3
11
Setting this attribute to ObjectMapper instance works,
将此属性设置为ObjectMapper实例有效,
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
#4
3
For people that find this question by searching for the error message, you can also see this error if you make a mistake in your @JsonProperty
annotations such that you annotate a List
-typed property with the name of a single-valued field:
对于通过搜索错误消息找到这个问题的人,如果您在@JsonProperty注释中犯了错误,您也可以看到这个错误,这样您就可以用一个单值字段的名称来注释一个列表类型的属性:
@JsonProperty("someSingleValuedField") // Oops, should have been "someMultiValuedField"
public List<String> getMyField() { // deserialization fails - single value into List
return myField;
}
#1
41
This is the solution for my old question:
这是我的老问题的解决方案:
I implemented my own ContextResolver in order to enable the DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY feature.
为了启用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;
}
}
And in the web.xml I registered my package into the servlet definition...
和网络。我将我的包注册到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>
... all the rest is transparently done by jersey/jackson.
…剩下的都是由泽西/杰克逊做的。
#2
15
do you try
你试一试
[{"name":"myEnterprise", "departments":["HR"]}]
the square brace is the key point.
方括号是关键。
#3
11
Setting this attribute to ObjectMapper instance works,
将此属性设置为ObjectMapper实例有效,
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
#4
3
For people that find this question by searching for the error message, you can also see this error if you make a mistake in your @JsonProperty
annotations such that you annotate a List
-typed property with the name of a single-valued field:
对于通过搜索错误消息找到这个问题的人,如果您在@JsonProperty注释中犯了错误,您也可以看到这个错误,这样您就可以用一个单值字段的名称来注释一个列表类型的属性:
@JsonProperty("someSingleValuedField") // Oops, should have been "someMultiValuedField"
public List<String> getMyField() { // deserialization fails - single value into List
return myField;
}