我有一个rest服务,它使用来自Angular ui和其他rest客户机的json。数据是基于一个复杂的实体结构,这些实体存储在一个有50个表的数据库中。问题是可选的onetoone关系,因为angular将可选对象作为空定义发送,如 "car": {},
. spring数据存储库将它们保存为空条目,我得到了一个json响应,如 "car": {"id": 545234, "version": 0}
回来。我没有发现可以忽略空对象的jackson注解,只有空或null属性。
雇员实体具有以下形式:
@Entity
public class Employee {
@Id
@GeneratedValue
private Long id;
@Version
private Long version;
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "car_id")
@JsonManagedReference
private Car car;
.
. Desk, getters and setters
.
}
另一边是一个参考点
@Entity
public class Car{
@Id
@GeneratedValue
private Long id;
@Version
private Long version;
private String name;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "employee")
@JsonBackReference
private Employee employee;
.
. getters and setters
.
}
例如,我将此作为后期操作发送到我的服务
{
"name": "ACME",
.
.
.
"employee": {
"name": "worker 1",
"car": {},
"desk": {
floor: 3,
number: 4,
phone: 444
}
.
.
.
},
"addresses": [],
"building": {},
.
.
.
}
我得到了保存的数据作为回应
{
"id": 34534,
"version": 0,
"name": "ACME",
.
.
.
"employee": {
"id": 34535,
"version":0,
"name": "worker 1",
"car": {"id": 34536, "version": 0},
"desk": {
"id": 34538,
"version":0,
"floor": 3,
"number": 4,
"phone": 444
}
.
.
.
},
"addresses": [],
"building": {"id": 34539, "version": 0},
.
.
.
}
正如在响应中看到的,我得到了一个id、一个版本、许多空值和空字符串的空表行,因为当我保存(持久化)主反序列化公司类时,其他实体也被保存,因为它们被注解为级联。
我发现了很多例子,比如donotincludeemptobjecttojackson,有一个具体的pojo和一个具体的反序列化程序,但每个实体都需要自己的反序列化程序。这将导致对当前实体和将来的新实体(仅可选实体)进行许多工作。
我试过以下,我写了一个 BeanDeserializerModifier
并尝试在标准beandeserializer上 Package 自己的反序列化程序:
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public List<BeanPropertyDefinition> updateProperties(DeserializationConfig config,
BeanDescription beanDesc,
List<BeanPropertyDefinition> propDefs) {
logger.debug("update properties, beandesc: {}", beanDesc.getBeanClass().getSimpleName());
return super.updateProperties(config, beanDesc, propDefs);
}
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc,
JsonDeserializer<?> deserializer) {
logger.debug("modify deserializer {}",beanDesc.getBeanClass().getSimpleName());
// This fails:
// return new DeserializationWrapper(deserializer, beanDesc);
return deserializer; // This works, but it is the standard behavior
}
});
这是 Package 纸(和错误):
public class DeserializationWrapper extends JsonDeserializer<Object> {
private static final Logger logger = LoggerFactory.getLogger( DeserializationWrapper.class );
private final JsonDeserializer<?> deserializer;
private final BeanDescription beanDesc;
public DeserializationWrapper(JsonDeserializer<?> deserializer, BeanDescription beanDesc) {
this.deserializer = deserializer;
this.beanDesc = beanDesc;
}
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
logger.debug("deserialize in wrapper {} ",beanDesc.getBeanClass().getSimpleName());
final Object deserialized = deserializer.deserialize(p, ctxt);
ObjectCodec codec = p.getCodec();
JsonNode node = codec.readTree(p);
// some logig that not work
// here. The Idea is to detect with the json parser that the node is empty.
// If it is empty I will return null here and not the deserialized pojo
return deserialized;
}
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt, Object intoValue) throws IOException {
logger.debug("deserializer - method 2");
intoValue = deserializer.deserialize(p, ctxt);
return intoValue;
}
@Override
public boolean isCachable() {
return deserializer.isCachable();
}
.
. I try to wrap the calls to the deserializer
.
反序列化 Package 器不工作,在第一次调用后崩溃,出现异常 com.fasterxml.jackson.databind.exc.MismatchedInputException: No _valueDeserializer assigned at [Source: (PushbackInputStream); line: 2, column: 11] (through reference chain: ... Company["name"])
我的问题是:有没有一种方法可以扩展正在工作的标准反序列化程序的行为,即反序列化程序在解析时检测到当前的jsonnode为空并返回null而不是空的类示例?也许我的想法是错误的,有一个完全不同的解决方案?
在Angular ui方面解决它是没有选择的。我们使用Jackson2.9.5。
1条答案
按热度按时间50few1ms1#
使用
BeanDeserializerModifier
使用自定义反序列化程序是个好主意。您只需要改进反序列化程序实现。在您的示例中,问题在于这些行:线路
1.
阅读JSON Object
. 排队2.
以及3.
你想创建一个JsonNode
但是空的JSON Object
已经排成一行了1.
. 接下来的两行将尝试读取负载的其余部分JsonNode
.Jackson
默认使用BeanDeserializer
反序列化正则表达式POJO
班级。我们可以扩展这个类并提供自己的实现。在版本中2.10.1
deserialise
方法如下所示:在大多数情况下,不需要特殊治疗
vanillaDeserialize
方法将被调用。我们来看看:正如你所看到的,它几乎做了我们想要的一切,除了它创建了新的对象,即使是空的
JSON Object
. 它在创建新对象之后检查字段是否存在。一行太远了。不幸的是,这个方法是私有的,我们不能重写它。我们把它复制到我们班上,再修改一下:您可以按以下方式注册:
简单
POC
:对于“空对象”
JSON
有效载荷:以上代码打印:
为了
JSON
带某些字段的有效负载:以上代码打印: