【问题标题】:Deserialize JSON with Jackson and @JsonCreator使用 Jackson 和 @JsonCreator 反序列化 JSON
【发布时间】:2019-06-23 20:56:27
【问题描述】:

我从第三方工具接收 JSON 文档,该工具正在开发中,即 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]],
}}

问题在于变体标签,特别是“行”。看起来好像“行”是用 @JsonValue 注释序列化的,以便摆脱原本会成为每个“行”一部分的字段名称。相反,一个额外的“列”字段被序列化以至少提及一次列名。

没有变体标签,我已经使用 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;
    }
}

和

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);
}

现在,为了反序列化变体,我将其添加到我原来的 POJO 中

@JsonProperty("variants")
private PojoVariants 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;
    }

}

最后是 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) {

    }

}

设置@JsonPropertyOrder,我希望Jackson 能够弄清楚我想将每一“行”读入PojoVariant 实例。但是,使用原始的 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

我了解 Jackson 希望我用属性名称注释构造函数参数。但是 JSON 一开始就不包含任何内容。我错过了什么?还是根本不支持这种方法 - 我必须实现自定义反序列化器吗?

【问题讨论】:

  • 我从未使用过 Jackson,但它似乎过于复杂。使用 gson。

标签: java json jackson json-deserialization objectmapper


【解决方案1】:

来自jackson annotations javadoc,@JsonPropertyOrder是用来序列化的,不是反序列化的:

可用于定义序列化对象属性时使用的顺序(可能是部分)的注解。

另外,当构造函数使用@JsonCreator注解时,构造函数必须是:

  • 单参数构造函数/factory方法,参数没有JsonProperty注解:如果是这样,这就是所谓的“委托创建者”,在这种情况下Jackson首先将JSON绑定到参数的类型中,然后调用 creator。
  • 构造函数/工厂方法,其中每个参数都使用 JsonProperty 或 JacksonInject 进行注释,以指示要绑定到的属性名称。

问题是您尝试从 json 列表 ["17", 19561093, ".", ..] 反序列化为 PojoVariant。杰克逊很聪明,但没有那么聪明。在这里他需要一些帮助,您可以帮助他实现自定义反序列化器。我们不想那样做,所以希望我们能找到别的东西。

提示来自@JsonCreator javadoc(第一个项目符号,粗体文本)。而且,因为 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];
}

【讨论】:

  • 很好的答案。好细节。作品!非常感谢!!
猜你喜欢
  • 2020-03-17
  • 1970-01-01
  • 1970-01-01
  • 2014-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-02
相关资源
最近更新 更多