Jackson:如何让@JsonBackReference 和自定义反序列化器同时工作?

我有一个 JSON 结构,其中包含字符串到对象的映射:


{

    "domains": {

        "ldap": {

            "users": {

                "fwalther": {

                    "firstName": "Fritz",

                    "lastName": "Walther"

                },

                // ...

            }

        }

    },

    // ...

}       

我想将此结构反序列化为使用 Jackson 的对象,Domain并且User我希望每个用户都有一个对其映射键(即用户 ID)和Domain容器的反向引用。这两种方法都有效,但如果我尝试同时获取两个反向引用,它就会失败。


@JsonManagedReference带有和的 Java 类@JsonBackReference:


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 时会出现以下异常:

查看引发异常的代码,我发现我需要findBackReference在我的自定义反序列化器中实现,但我不知道如何,我也找不到这方面的信息。有任何想法吗?


还是有其他方法可以同时获取映射键和对包含对象的反向引用?


慕运维8079593
浏览 91回答 1
1回答

郎朗坤

在这个答案的帮助下,我找到了解决方案:自定义反序列化器需要基于默认反序列化器,它正确实现了反向引用机制。这比仅仅从正确的基类继承要复杂一些。相反,您需要通过自定义获取(完全配置的)默认反序列化器实例BeanDeserializerModifier,然后将此实例传递给您的子类DelegatingDeserializer:public ObjectMapper getMapperWithCustomDeserializer() {&nbsp; &nbsp; ObjectMapper objectMapper = new ObjectMapper();&nbsp; &nbsp; SimpleModule module = new SimpleModule();&nbsp; &nbsp; module.setDeserializerModifier(new BeanDeserializerModifier() {&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BeanDescription beanDesc, JsonDeserializer<?> defaultDeserializer) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (beanDesc.getBeanClass() == User.class) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new UserDeserializer(defaultDeserializer);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return defaultDeserializer;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; });&nbsp; &nbsp; objectMapper.registerModule(module);&nbsp; &nbsp; return objectMapper;}然后自定义反序列化器需要如下所示:public class UserDeserializer extends DelegatingDeserializer {&nbsp; &nbsp; public UserDeserializer(JsonDeserializer<?> delegate) {&nbsp; &nbsp; &nbsp; &nbsp; super(delegate);&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegate) {&nbsp; &nbsp; &nbsp; &nbsp; return new UserDeserializer(newDelegate);&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public User deserialize(JsonParser p, DeserializationContext ctxt)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throws IOException {&nbsp; &nbsp; &nbsp; &nbsp; String key = p.getCurrentName();&nbsp; &nbsp; &nbsp; &nbsp; User result = (User) super.deserialize(p, ctxt);&nbsp; &nbsp; &nbsp; &nbsp; result.userId = key;&nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; }}最后,您需要删除@JsonDeserialize注释。然后,自定义反序列化器和@JsonBackReference应该工作。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java