我有以下
JSON:
{ "item": [ { "foo": 1 },{ "foo": 2 } ] }
这基本上是一个包含项目集合的对象.
所以我做了一个反序列化的课:
public class ItemList { @JsonProperty("item") List<Item> items; // Getters,setters & co. // ... }
一切都很好,直到现在为止.
现在,为了使我的生活更容易在别的地方,我决定能够迭代ItemList对象并让它实现Collection接口是很好的.
所以基本上我的班成了:
public class ItemList implements Collection<Item>,Iterable<Item> { @JsonProperty("item") List<Item> items; // Getters,setters & co. // Generated all method delegates to items. For instance: public Item get(int position) { return items.get(position); } }
实施工作正常,很好.但是,反序列化现在失败了.
看起来杰克逊变得困惑:
com.fasterxml.jackson.databind.JsonMappingException: Can not
deserialize instance of com.example.ItemList out of START_OBJECT token
我已经尝试添加@JsonDeserialize(as = ItemList.class),但是没有这样做.
有什么办法?
解决方法
显然,它不起作用,因为Jackson使用标准集合解串器作为Java集合类型,它们对ItemList属性一无所知.
它可以使其工作,但不是非常优雅的方式.您需要配置ObjectMapper来替换为相应类型手动创建的bean解串器上的默认集合解串器.我已经写了一个例子,在BeanDeserializerModifier中为使用自定义注释注释的所有类执行此操作.
请注意,我必须重写ObjectMapper以访问ObjectMapper的受保护方法createDeserializationContext,以创建适当的反序列化上下文,因为bean修饰符无法访问它.
这是代码:
public class JacksonCustomList { public static final String JSON = "{\n" + " \"item\": [\n" + " { \"foo\": 1 },\n" + " { \"foo\": 2 }\n" + " ]\n" + "} "; @Retention(RetentionPolicy.RUNTIME) public static @interface PreferBeanDeserializer { } public static class Item { public int foo; @Override public String toString() { return String.valueOf(foo); } } @PreferBeanDeserializer public static class ItemList extends ArrayList<Item> { @JsonProperty("item") public List<Item> items; @Override public String toString() { return items.toString(); } } public static class Modifier extends BeanDeserializerModifier { private final MyObjectMapper mapper; public Modifier(final MyObjectMapper mapper) { this.mapper = mapper; } @Override public JsonDeserializer<?> modifyCollectionDeserializer( final DeserializationConfig config,final CollectionType type,final BeanDescription beanDesc,final JsonDeserializer<?> deserializer) { if (type.getRawClass().getAnnotation(PreferBeanDeserializer.class) != null) { DeserializationContext context = mapper.createContext(config); try { return context.getFactory().createBeanDeserializer(context,type,beanDesc); } catch (JsonMappingException e) { throw new IllegalStateException(e); } } return super.modifyCollectionDeserializer(config,beanDesc,deserializer); } } public static class MyObjectMapper extends ObjectMapper { public DeserializationContext createContext(final DeserializationConfig cfg) { return super.createDeserializationContext(getDeserializationContext().getParser(),cfg); } } public static void main(String[] args) throws IOException { final MyObjectMapper mapper = new MyObjectMapper(); SimpleModule module = new SimpleModule(); module.setDeserializerModifier(new Modifier(mapper)); mapper.registerModule(module); System.out.println(mapper.readValue(JSON,ItemList.class)); } }