杰克逊 JsonUnwrapped 属性碰撞
Jackson JsonUnwrapped properties collision
我有两个 类 具有相似的结构:
class Outer {
String id;
String someOuterProp;
@JsonUnwrapped
@JsonInclude(JsonInclude.Include.NON_NULL)
Inner inner;
}
class Inner {
String id;
String someOuterProp;
}
Inner
对象可以在某些情况下独立创建,而在其他情况下可以嵌套在 Outer
中。可以看出两者都有一个具有相同 (id) 名称的字段。
当 Outer
对象被序列化时 - 如果 inner 不为空 - Inner
属性应该被解包,因此 @JsonUnwrapped
用法。
序列化时,我希望保留 Outer
id 值,但是此断言失败:
Outer o = new Outer();
o.setId("outerId");
Inner i = new Inner();
i.setId("innerId");
o.setInner(i);
Map<?,?> map = objectMapper.convertValue(o, Map.class);
assertEquals("outerId", map.get("id"));
所以,我的问题是,如何在 属性 名称冲突时展平嵌套对象属性,同时保留包含的对象值?
这里有两件事你可以做。
解决方案 1:订购您的属性
只需指定序列化属性的顺序即可强制Outer.id
最后写入。在反序列化过程中最后读取该字段时,它将覆盖前面的值(假设您正在反序列化为地图):
@JsonPropertyOrder({ "inner", "id", "someOuterProp" })
class Outer {
String id;
String someOuterProp;
@JsonUnwrapped
@JsonInclude(JsonInclude.Include.NON_NULL)
Inner inner;
}
@JsonPropertyOrder({ "inner", "id"})
强制首先写入从 inner
扁平化的属性。
解决方案 2:使用不同的 JSON 属性 名称
只需为 Inner
字段添加前缀名称。这将使它使用唯一的字段名称写入值:
class Outer {
String id;
String someOuterProp;
@JsonUnwrapped(prefix = "inner.")
@JsonInclude(JsonInclude.Include.NON_NULL)
Inner inner;
}
当你从这个class序列化一个对象时,你会得到类似
的东西
{
"id" : "a",
"someOuterProp" : "some",
"inner.id" : "A",
"inner.someOuterProp" : "SOME"
}
并将其反序列化为 Outer
对象会将正确的值放在它们所属的位置。这同样适用于您调用 convertValue
:
生成的地图
{id=a, someOuterProp=some, inner.id=A, inner.someOuterProp=SOME}
我有两个 类 具有相似的结构:
class Outer {
String id;
String someOuterProp;
@JsonUnwrapped
@JsonInclude(JsonInclude.Include.NON_NULL)
Inner inner;
}
class Inner {
String id;
String someOuterProp;
}
Inner
对象可以在某些情况下独立创建,而在其他情况下可以嵌套在 Outer
中。可以看出两者都有一个具有相同 (id) 名称的字段。
当 Outer
对象被序列化时 - 如果 inner 不为空 - Inner
属性应该被解包,因此 @JsonUnwrapped
用法。
序列化时,我希望保留 Outer
id 值,但是此断言失败:
Outer o = new Outer();
o.setId("outerId");
Inner i = new Inner();
i.setId("innerId");
o.setInner(i);
Map<?,?> map = objectMapper.convertValue(o, Map.class);
assertEquals("outerId", map.get("id"));
所以,我的问题是,如何在 属性 名称冲突时展平嵌套对象属性,同时保留包含的对象值?
这里有两件事你可以做。
解决方案 1:订购您的属性
只需指定序列化属性的顺序即可强制Outer.id
最后写入。在反序列化过程中最后读取该字段时,它将覆盖前面的值(假设您正在反序列化为地图):
@JsonPropertyOrder({ "inner", "id", "someOuterProp" })
class Outer {
String id;
String someOuterProp;
@JsonUnwrapped
@JsonInclude(JsonInclude.Include.NON_NULL)
Inner inner;
}
@JsonPropertyOrder({ "inner", "id"})
强制首先写入从 inner
扁平化的属性。
解决方案 2:使用不同的 JSON 属性 名称
只需为 Inner
字段添加前缀名称。这将使它使用唯一的字段名称写入值:
class Outer {
String id;
String someOuterProp;
@JsonUnwrapped(prefix = "inner.")
@JsonInclude(JsonInclude.Include.NON_NULL)
Inner inner;
}
当你从这个class序列化一个对象时,你会得到类似
的东西{
"id" : "a",
"someOuterProp" : "some",
"inner.id" : "A",
"inner.someOuterProp" : "SOME"
}
并将其反序列化为 Outer
对象会将正确的值放在它们所属的位置。这同样适用于您调用 convertValue
:
{id=a, someOuterProp=some, inner.id=A, inner.someOuterProp=SOME}