我有一个JSON结构,其中包含字符串到对象的映射:
{
"domains": {
"ldap": {
"users": {
"fwalther": {
"firstName": "Fritz",
"lastName": "Walther"
},
// ...
}
}
},
// ...
}
我想使用Jackson将这个结构反序列化为Domain
和User
对象,并且我希望每个用户都对其映射键(它是用户ID)有一个反向引用。和到Domain
容器。这两种方法都行不通,但是如果我尝试一次获得两个反向引用,都将失败。
具有@JsonManagedReference
和@JsonBackReference
的Java类:
public class Domain {
@JsonManagedReference
@JsonDeserialize(contentUsing = UserDeserializer.class)
private Map<String, User> users;
public Map<String, User> getUsers() {
return users;
}
}
public class User {
@JsonBackReference
private Domain domain;
String userId;
private String firstName;
private String lastName;
// ... getters
}
自定义解串器以获取地图密钥:
public class UserDeserializer extends JsonDeserializer<User> {
@Override
public User deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
String key = p.getCurrentName();
User result = p.readValueAs(User.class);
result.userId = key;
return result;
}
}
两种机制,即@JsonManagedReference
/ @JsonBackReference
对和@JsonDeserialize
与自定义反序列化器一起使用,如果我仅激活其中一种,则它们都起作用。但是,如果我结合了这些机制(如上面的代码所示),则在解析JSON时会收到以下异常:
java.lang.IllegalArgumentException: Cannot handle managed/back reference 'defaultReference': type: value deserializer of type org.example.UserDeserializer does not support them
at com.fasterxml.jackson.databind.JsonDeserializer.findBackReference(JsonDeserializer.java:366) ~[jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.deser.std.ContainerDeserializerBase.findBackReference(ContainerDeserializerBase.java:104) ~[jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase._resolveManagedReferenceProperty(BeanDeserializerBase.java:786) ~[jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:487) ~[jackson-databind-2.9.8.jar:2.9.8]
...
查看引发异常的代码,我发现我需要在自定义反序列化器中实现findBackReference
,但是我不知道如何实现,也找不到关于此的信息要么。有什么想法吗?
或者还有其他方法可以同时获取映射键和对包含对象的引用吗?
答案 0 :(得分:0)
在this answer的帮助下,我找到了解决方案:自定义解串器必须基于默认解串器,该缺省解串器可以正确实现反向引用机制。
这比从正确的基类继承要复杂得多。相反,您需要通过自定义BeanDeserializerModifier
来掌握(完全配置的)默认解串器实例,然后将此实例传递给DelegatingDeserializer
的子类:
public ObjectMapper getMapperWithCustomDeserializer() {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc, JsonDeserializer<?> defaultDeserializer)
if (beanDesc.getBeanClass() == User.class) {
return new UserDeserializer(defaultDeserializer);
} else {
return defaultDeserializer;
}
}
});
objectMapper.registerModule(module);
return objectMapper;
}
然后,自定义解串器将需要如下所示:
public class UserDeserializer extends DelegatingDeserializer {
public UserDeserializer(JsonDeserializer<?> delegate) {
super(delegate);
}
@Override
protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegate) {
return new UserDeserializer(newDelegate);
}
@Override
public User deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
String key = p.getCurrentName();
User result = (User) super.deserialize(p, ctxt);
result.userId = key;
return result;
}
}
最后,您需要删除@JsonDeserialize
批注。然后,自定义解串器和@JsonBackReference
应该可以工作。