json Jackson 反序列化 - 包含 ArrayList<T>
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10978748/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hymanson deserialization - with contained ArrayList<T>
提问by Carl Meyer
Good day,
再会,
I am currently integration attempting to consume a REST service that produces JSON (written in .NET) using Hymanson (with Jersey). The JSON consists of a possible error message and an array of objects. Below is a sample of the JSON returned as produced by Jersey's logging filter:
我目前正在集成,尝试使用 Hymanson(与 Jersey)使用生成 JSON(用 .NET 编写)的 REST 服务。JSON 包含一条可能的错误消息和一组对象。下面是由 Jersey 的日志过滤器生成的返回的 JSON 示例:
{
"error":null,
"object":"[{\"Id\":16,\"Class\":\"ReportType\",\"ClassID\":\"4\",\"ListItemParent_ID\":4,\"Item\":\"Pothole\",\"Description\":\"Pothole\",\"Sequence\":1,\"LastEditDate\":null,\"LastEditor\":null,\"ItemStatus\":\"Active\",\"ItemColor\":\"#00AF64\"}]"
}
I have two classes to represent the type (the outer ListResponse):
我有两个类来表示类型(外部 ListResponse):
public class ListResponse {
public String error;
public ArrayList<ListItem> object;
public ListResponse() {
}
}
and (the inner ListItem):
和(内部 ListItem):
public class ListItem {
@JsonProperty("Id")
public int id;
@JsonProperty("Class")
public String classType;
@JsonProperty("ClassID")
public String classId;
@JsonProperty("ListItemParent_ID")
public int parentId;
@JsonProperty("Item")
public String item;
@JsonProperty("Description")
public String description;
@JsonAnySetter
public void handleUnknown(String key, Object value) {}
public ListItem() {
}
}
The class that invokes and returns the JSON looks like this:
调用并返回 JSON 的类如下所示:
public class CitizenPlusService {
private Client client = null;
private WebResource service = null;
public CitizenPlusService() {
initializeService("http://localhost:59105/PlusService/");
}
private void initializeService(String baseURI) {
// Use the default client configuration.
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getClasses().add(HymansonJsonProvider.class);
client = Client.create(clientConfig);
// Add a logging filter to track communication between server and client.
client.addFilter(new LoggingFilter());
// Add the base URI
service = client.resource(UriBuilder.fromUri(baseURI).build());
}
public ListResponse getListItems(String id) throws Exception
{
ListResponse response = service.path("GetListItems").path(id).accept(MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE).get(ListResponse.class);
return response;
}
}
The important call here is the getListItems method. Running the code in a test harness, produces the following:
这里重要的调用是 getListItems 方法。在测试工具中运行代码,产生以下结果:
org.codehaus.Hymanson.map.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
at [Source: java.io.StringReader@49497eb8; line: 1, column: 14] (through reference chain: citizenplus.types.ListResponse["object"])
Please assist.
请协助。
Regards, Carl-Peter Meyer
问候,卡尔-彼得迈耶
采纳答案by Philipp Maschke
Your problem is that the 'object' property value is a String and not an array! The string contains a JSON array but Hymanson expects a native array (without the wrapping quotes).
您的问题是“对象”属性值是字符串而不是数组!该字符串包含一个 JSON 数组,但 Hymanson 需要一个本机数组(不带引号)。
I had the same problem and I created a custom deserializer, which will deserialize a string value to a generic collection of the desired type:
我遇到了同样的问题,我创建了一个自定义反序列化器,它将字符串值反序列化为所需类型的泛型集合:
public class JsonCollectionDeserializer extends StdDeserializer<Object> implements ContextualDeserializer {
private final BeanProperty property;
/**
* Default constructor needed by Hymanson to be able to call 'createContextual'.
* Beware, that the object created here will cause a NPE when used for deserializing!
*/
public JsonCollectionDeserializer() {
super(Collection.class);
this.property = null;
}
/**
* Constructor for the actual object to be used for deserializing.
*
* @param property this is the property/field which is to be serialized
*/
private JsonCollectionDeserializer(BeanProperty property) {
super(property.getType());
this.property = property;
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
return new JsonCollectionDeserializer(property);
}
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
switch (jp.getCurrentToken()) {
case VALUE_STRING:
// value is a string but we want it to be something else: unescape the string and convert it
return HymansonUtil.MAPPER.readValue(StringUtil.unescapeXml(jp.getText()), property.getType());
default:
// continue as normal: find the correct deserializer for the type and call it
return ctxt.findContextualValueDeserializer(property.getType(), property).deserialize(jp, ctxt);
}
}
}
Note that this deserializer will also work if the value actually is an array and not a string, because it delegates the actual deserialization accordingly.
请注意,如果值实际上是数组而不是字符串,则此反序列化器也将起作用,因为它相应地委托了实际的反序列化。
In your example you would now have to annotate your collection field like so:
在您的示例中,您现在必须像这样注释您的集合字段:
public class ListResponse {
public String error;
@JsonDeserialize(using = JsonCollectionDeserializer.class)
public ArrayList<ListItem> object;
public ListResponse() {}
}
And that should be it.
应该就是这样。
Note: HymansonUtil and StringUtil are custom classes, but you can easily replace them. For example by using new ObjectMapper()and org.apache.commons.lang3.StringEscapeUtils.
注意:HymansonUtil 和 StringUtil 是自定义类,但您可以轻松替换它们。例如通过使用new ObjectMapper()和org.apache.commons.lang3.StringEscapeUtils。
回答by Archimedes Trajano
You may be missing a @JsonDeserializeattribute as the type information does get lost in generics at run-time. Also you should avoid using concrete classes for collections if you can.
您可能缺少@JsonDeserialize属性,因为类型信息在运行时会在泛型中丢失。此外,如果可以,您应该避免为集合使用具体的类。
public class ListResponse {
public String error;
@JsonDeserialize(as=ArrayList.class, contentAs=ListItem.class)
public List<ListItem> object;
}
回答by Rashmin H Gadhavi
The register subTypes works!
注册子类型有效!
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
public interface Geometry {
}
public class Point implements Geometry{
private String type="Point";
....
}
public class Polygon implements Geometry{
private String type="Polygon";
....
}
public class LineString implements Geometry{
private String type="LineString";
....
}
GeoJson geojson= null;
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.registerSubtypes(Polygon.class,LineString.class,Point.class);
try {
geojson=mapper.readValue(source, GeoJson.class);
} catch (IOException e) {
e.printStackTrace();
}

