如何给Jackson解串器提供类型提示?

时间:2012-05-31 14:32:14

标签: java jackson

我使用杰克逊作为工具来声明一些我无法注释(或完全修改)类的对象。其中一个类有一个用于无类型列表的setter和getter。这是一个消毒版本:

public class Family {
    private List members;
    public List getMembers() { return members; }
    public void setMembers(List members) { this.members = members; }
    //...many, many other properties
}

public class Member {
    private String name;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

这是我尝试反序列化的JSON:

{ "members" : [ { "name" : "Mark" } ] }

我将使用的天真代码是:

ObjectMapper mapper = new ObjectMapper();
Family family = mapper.readValue(json, Family.class);
Member member = (Member) family.getMembers().get(0);
System.out.println(member.getName());

但当然这失败了,因为杰克逊不知道创建一个Members的列表而不是它的后备,一个LinkedHashMap的列表。

指示杰克逊将members视为List<Member>的最简单方法是什么?我认为我不想使用完全自定义该类的反序列化器,因为杰克逊处理的其他许多属性都很好。

使用BeanDeserializerModifier,我能做到最好:

mapper.setDeserializerProvider(new StdDeserializerProvider()
  .withDeserializerModifier(new BeanDeserializerModifier() {
      @Override
      public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BasicBeanDescription beanDesc, BeanDeserializerBuilder builder) {
          if (beanDesc.getBeanClass() == Family.class) {
            CollectionType type = CollectionType.construct(ArrayList.class, SimpleType.construct(Member.class));
            TypeDeserializer typeDeserializer = type.getTypeHandler();
            SettableBeanProperty.MethodProperty membersProperty = (SettableBeanProperty.MethodProperty) builder.removeProperty("members");
            builder.addProperty(new SettableBeanProperty.MethodProperty(
               "members",
               type,
               typeDeserializer,
               beanDesc.getClassAnnotations(),
               (AnnotatedMethod) membersProperty.getMember()
            ));
          }
          return builder;
      }}));

它有效,但对于我正在尝试做的事情,它似乎真的很低级(而且冗长!)。我在这里缺少什么?

修改

我应该注意,我使用的是Jackson 1.8.2,但如果有令人信服的理由可以更新。

1 个答案:

答案 0 :(得分:8)

Mix-in annotations是我失踪的谜题的关键部分。这是解决此问题的很多清洁方法:

ObjectMapper mapper = new ObjectMapper();
mapper.getDeserializationConfig().addMixInAnnotations(Family.class, FamilyMixin.class);

Family family = mapper.readValue(json, Family.class);
Member member = (Member) family.getMembers().get(0);

//...

interface FamilyMixin {
    @JsonDeserialize(contentAs = Member.class)
    void setMembers(List members);
}

您可以使用哪些混合注释来注释受您控制的代理。当混合类应用于真实类时,杰克逊的行为就像那些注释注释了真实类的成员一样。

就我而言,我使用JsonDeserialize.contentAs()来指定容器的内容类型。但我相信大多数注释应该可以使用这种方法。