使用 Jackson 和 @JsonCreator 反序列化 JSON
Deserialize JSON with Jackson and @JsonCreator
我从正在开发的第三方工具收到 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]],
}}
问题出在变量标签上,特别是 "rows"。看起来好像 "rows" 是用 @JsonValue 注释序列化的,以便摆脱字段名称,否则这些字段名称将成为每个 "row" 的一部分。相反,一个额外的 "columns" 字段被序列化以至少提及一次列名。
没有 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;
}
}
和
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 能够弄清楚我想将每个"row" 读入一个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 希望我用 属性-names 注释构造函数参数。但是 JSON 首先包含 none 。我错过了什么?或者这种方法根本不受支持 - 我是否必须实现自定义解串器?
来自jackson annotations javadoc,@JsonPropertyOrder
用于序列化,不是反序列化:
Annotation that can be used to define ordering (possibly partial) to use when serializing object properties.
此外,当构造函数被注释为 @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.
- Constructor/factory method where every argument is annotated with either JsonProperty or JacksonInject, to indicate name of property to bind to.
问题是您尝试从 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];
}
我从正在开发的第三方工具收到 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]],
}}
问题出在变量标签上,特别是 "rows"。看起来好像 "rows" 是用 @JsonValue 注释序列化的,以便摆脱字段名称,否则这些字段名称将成为每个 "row" 的一部分。相反,一个额外的 "columns" 字段被序列化以至少提及一次列名。
没有 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;
}
}
和
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 能够弄清楚我想将每个"row" 读入一个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 希望我用 属性-names 注释构造函数参数。但是 JSON 首先包含 none 。我错过了什么?或者这种方法根本不受支持 - 我是否必须实现自定义解串器?
来自jackson annotations javadoc,@JsonPropertyOrder
用于序列化,不是反序列化:
Annotation that can be used to define ordering (possibly partial) to use when serializing object properties.
此外,当构造函数被注释为 @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.
- Constructor/factory method where every argument is annotated with either JsonProperty or JacksonInject, to indicate name of property to bind to.
问题是您尝试从 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];
}