简体   繁体   English

用Jackson和@JsonCreator反序列化JSON

[英]Deserialize JSON with Jackson and @JsonCreator

I receive JSON documents from a third party tool, which is under development, ie the JSON is extended frequently. 我从正在开发的第三方工具接收JSON文档,即JSON经常扩展。 I would like to stick with the simplest deserialization mechanism in order to avoid increased maintenance that comes with custom deserializers. 我想坚持使用最简单的反序列化机制,以避免自定义反序列化器附带的增加的维护。

Here's the relevant part of the JSON: 这是JSON的相关部分:

{
"key1": "value1",
"key2": "value2",
"variants": {
    "columns": ["chr", "pos", "id", "ref", "alt", "qual", "filter", "type", "genotype", "alignpos", "basepos", "signalpos"],
    "rows": [
        ["17", 19561093, ".", "G", "C", 51, "PASS", "SNV", "het.", 97, 147, 1761],
        ["17", 19561123, ".", "T", "G", 51, "PASS", "SNV", "het.", 127, 177, 2120],
        ["17", 19561149, ".", "G", "A", 51, "PASS", "SNV", "het.", 153, 203, 2432]],
    "xranges": [
        [829, 1129],
        [1480, 1780],
        [1492, 1792]],
}}

The issue is with the variants tag, specifically with the "rows". 问题出在variants标记上,尤其是“行”。 It looks as if "rows" were serialized with @JsonValue annotation in order to get rid of the field names that would otherwise be part of every "row". 看起来好像用@JsonValue批注对“行”进行了序列化,以消除否则将成为每个“行”一部分的字段名。 Instead an additional "columns" field was serialized to at least mention the column names once. 而是将一个附加的“列”字段序列化为至少提及一次列名。

Without the variants tag, I've been successful deserializing the JSON into a POJO using ObjectMapper: 没有variants标签,我已经成功地使用ObjectMapper将JSON反序列化为POJO:

public class Pojo {
    private String key1;
    private String key2;
    public String getKey1() {
        return key1;
    }
    public void setKey1(String key1) {
        this.key1 = key1;
    }
    public String getKey2() {
        return key2;
    }
    public void setKey2(String key2) {
        this.key2 = key2;
    }
}

and

public static void main(String[] args) {
    final ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    Pojo pojo = objectMapper.readValue(jsonFile, Pojo.class);
}

Now, in order to deserialize the variants, I added this to my original POJO 现在,为了反序列化变体,我将其添加到原始POJO中

@JsonProperty("variants")
private PojoVariants pojoVariants;

Then, implemented PojoVariants 然后,实现PojoVariants

public class PojoVariants {

    @JsonProperty("columns")
    private String[] columnNames;

    @JsonProperty("rows")
    private PojoVariant[] pojoVariantArr;

    public String[] getColumnNames() {
        return columnNames;
    }

    public void setColumnNames(String[] columnNames) {
        this.columnNames = columnNames;
    }

    public PojoVariant[] getPojoVariantArr() {
        return pojoVariantArr;
    }

    public void setPojoVariantArr(PojoVariant[] pojoVariantArr) {
        this.pojoVariantArr = pojoVariantArr;
    }

}

and finally PojoVariant 最后是PojoVariant

@JsonPropertyOrder({
        "chr", "pos",
        "id", "ref", "alt",
        "quality", "filter", "type", "genotype",
        "alignPos", "basePos", "signalPos" })
public class PojoVariant {

    private String chr;
    private int pos;

    private String id;
    private String ref;
    private String alt;

    private int quality;
    private String filter;
    private String type;
    private String genotype;

    private int alignPos;
    private int basePos;
    private int signalPos;

    @JsonCreator
    public PojoVariant(
            String chr, int pos,
            String id, String ref, String alt,
            int quality, String filter, String type, String genotype,
            int alignPos, int basePos, int signalPos) {

    }

}

Setting @JsonPropertyOrder, I hoped that Jackson would be able to figure out that I would like to read every "row" into a PojoVariant instance. 设置@JsonPropertyOrder,我希望杰克逊能够弄清楚我想将每个“行”读入PojoVariant实例。 However, using the original main method, I get this stack trace: 但是,使用原始的main方法,我得到此堆栈跟踪:

org.codehaus.jackson.map.JsonMappingException: Argument #0 of constructor [constructor for my.json.stuff.PojoVariant, annotations: {interface org.codehaus.jackson.annotate.JsonCreator=@org.codehaus.jackson.annotate.JsonCreator()}] has no property name annotation; must have name when multiple-paramater constructor annotated as Creator

I understand that Jackson would like me annotate the constructor arguments with property-names. 我知道杰克逊希望我用属性名称注释构造函数参数。 But the JSON contains none to begin with. 但是JSON不包含任何开头。 What am I missing? 我想念什么? Or is this approach simply not supported - do I have to implement a custom deserializer? 还是根本不支持这种方法-我必须实现自定义解串器吗?

From jackson annotations javadoc , @JsonPropertyOrder is used for serialization, not deserialization: jackson注释javadoc中@JsonPropertyOrder用于序列化,而不是反序列化:

Annotation that can be used to define ordering (possibly partial) to use when serializing object properties. 可用于定义序列化对象属性时使用的排序(可能是部分)的注释。

Also, when the constructor is annotated with @JsonCreator , constructor must either be: 另外,在使用@JsonCreator注释构造函数时,构造函数必须为:

  • Single-argument constructor /factory method without JsonProperty annotation for the argument: if so, this is so-called "delegate creator", in which case Jackson first binds JSON into type of the argument, and then calls creator . 对于参数,不带JsonProperty批注的单参数构造函数 / factory方法:如果是这样,这就是所谓的“委托创建者”,在这种情况下, Jackson首先将JSON绑定到参数的类型中,然后调用creator
  • Constructor/factory method where every argument is annotated with either JsonProperty or JacksonInject, to indicate name of property to bind to. 构造函数/工厂方法,其中每个参数都用JsonProperty或JacksonInject注释,以指示要绑定的属性的名称。

The problem is that you try to deserialize from a json list ["17", 19561093, ".", ..] to a PojoVariant . 问题是您尝试从json列表["17", 19561093, ".", ..]反序列PojoVariant Jackson is smart but not that smart. 杰克逊很聪明,但没有那么聪明。 Here he needs some help and you can help him implementing a custom deserializer. 在这里他需要一些帮助,您可以帮助他实现自定义解串器。 We don't wanna do that, so let's hope we can find something else. 我们不想这样做,所以我们希望可以找到其他东西。

The hint comes from the @JsonCreator javadoc (first bullet, bold text). 提示来自@JsonCreator javadoc(第一个项目符号,粗体文本)。 And, because Jackson knows how to bind the list into an array of objects, we can rewrite PojoVariant constructor like this: 并且,由于Jackson知道如何将列表绑定到对象数组中,因此我们可以像下面这样重写PojoVariant构造函数:

@JsonCreator
public PojoVariant(Object[] params) {
    this.chr = (String) params[0];
    this.pos = (int) params[1];
    this.id = (String) params[2];
    this.ref = (String) params[3];
    this.alt = (String) params[4];
    this.quality = (int) params[5];
    this.filter = (String) params[6];
    this.type = (String) params[7];
    this.genotype = (String) params[8];
    this.alignPos = (int) params[9]; 
    this.basePos = (int) params[10];
    this.signalPos = (int) params[11];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM