使用jackson在java中嵌套自定义反序列化

时间:2017-05-11 09:31:50

标签: java json serialization jackson deserialization

我一直想知道如何正确解决这个问题

我有这样的数据模型:

Class B
 String fieldB1;
 String fieldB2;

Class A
 String fieldA1;
 String fieldA2;
 List<B> fieldA3;

(然后另一个第三类与另一个具有相同层次结构的字段和A对象列表,但为了简单起见,我们坚持使用A和B)

现在另一方面,我必须使用相同的名称对类中的这些类进行反序列化,并使用不同的数据类型进行参数

所以^必须读作:

Class B
 int fieldB1;
 double fieldB2;

Class A
 float fieldA1;
 float fieldA2;
 List<B> fieldA3;

由于我没有经验,我的第一个猜测是在Jackson中为A和B编写海关Deserializer,当我反序列化类似B而没有使用自定义反序列化方法引用其他类的类时,转换很容易

但是为A类创建自定义反序列化器呢?当我必须反序列化fieldA3,也就是B对象列表时,我该如何操作?应该尝试在ClassACustomDeserializer中以某种方式调用ClassBCustomDeserializer吗?怎么做? 或者是否有另一个更简单的解决方案,只是告诉杰克逊根据我的个人映射转换一些其他类型的字符串字段?

这就是我如何反序列化B

public class BDeserializer extends StdDeserializer<B> { 

    public BDeserializer() { 
        this(null); 
    } 

    public BDeserializer(Class<?> vc) { 
        super(vc); 
    }

    @Override
    public B deserialize(JsonParser jp, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);

        int fieldB1= node.findValue("fieldB1").asInt();
        double fieldB2= node.findValue("fieldB2").asDouble();

        return new B(fieldB1,fieldB2);
    }
}

1 个答案:

答案 0 :(得分:2)

杰克逊非常聪明,可以将文本值转换为适当的数字类型,因此它应该能够反序列化JSON,如:

{ "fieldB1": 10, "fieldB2" : "0.333" }

到你的

Class B
    int fieldB1;
    double fieldB2;

很好,甚至没有使用自定义反序列化器。

如果您想坚持使用自定义反序列化器,无论出于何种原因, 你可以使用JsonNode.traverse()创建一个子解析器:

JsonParser parser = node.findValue("fieldA3").traverse();
parser.setCodec(jp.getCodec());
List<B> list = parser.readValueAs(new TypeReference<List<B>>() {});

或自行导航令牌流,而不是使用find

while(jp.nextToken() != JsonToken.END_OBJECT) {
    if(jp.currentToken() == JsonToken.FIELD_NAME) {
       switch (jp.getCurrentName()) {
           //...
           case "fieldA3":
             jp.nextToken();
             list=jp.readValueAs(new TypeReference<List<ClassB>>() {}));
           break;
       }
    }
}
如果表现令人担忧,后者应该更有效率。