首页 > 解决方案 > 杰克逊与建设者模式和反向参考

问题描述

我现在不太清楚如何制定我的标题,但是我遇到了我正在处理的代码的问题,我只能通过示例来解释,所以就这样吧。

我有一个嵌套的对象结构,当它发生变化时我会坚持归档。这是模型的要点:

@JsonDeserialize(builder = Parent.Builder.class)
public class Parent {

    private String id;
    private List<Child> children;

    private Parent(Builder builder) {
        id = builder.id;
        children = builder.children;
        setParentChildRelationship();
    }

    private void setParentChildRelationship() {
        children.forEach(c -> c.setParent(this));
    }

    public String getId() {
        return id;
    }

    public List<Child> getChildren() {
        return children;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {
        private String id;
        private List<Child> children = Collections.emptyList();

        private Builder() {
        }

        public Builder withId(final String id) {
            this.id = id;
            return this;
        }

        public Builder withChildren(final List<Child> children) {
            this.children = children;
            return this;
        }

        public Parent build() {
            return new Parent(this);
        }
    }
}
@JsonDeserialize(builder = Child.Builder.class)
public class Child {

    private String id;

    @JsonBackReference
    private Parent parent;

    private Child(Builder builder) {
        id = builder.id;
    }

    public String getId() {
        return id;
    }

    public Parent getParent() {
        return parent;
    }

    public static Builder builder() {
        return new Builder();
    }

    public void setParent(final Parent parent) {
        this.parent = parent;
    }

    public static class Builder {
        private String id;

        private Builder() {
        }

        public Builder withId(final String id) {
            this.id = id;
            return this;
        }

        public Child build() {
            return new Child(this);
        }
    }
}

然后我可以很好地序列化它:

@Test
void serialize() throws JsonProcessingException {
    final Parent parent = Parent.builder()
            .withId("1")
            .withChildren(List.of(Child.builder()
                    .withId("2")
                    .build()))
            .build();

    System.out.println(parent.getChildren().get(0).getParent().getId());
    System.out.println(JSONUtil.toPrettyJSON(parent));
}

上面的测试输出一个1和以下 JSON 结构:

{
    "id": "1",
    "children": [{
        "id": "2"
    }]
}

我也可以将它反序列化到我的父类中,这个测试输出与上面的测试相同。

@Test
void deserialize() throws JsonProcessingException {
    final String json = "{\"id\":\"1\",\"children\":[{\"id\":\"2\"}]}";
    final Parent parent = JSONUtil.fromString(json, Parent.class);

    System.out.println(parent.getChildren().get(0).getParent().getId());
    System.out.println(JSONUtil.toPrettyJSON(parent));
}

一旦反序列化,我一直努力保持这个状态不可变,但我现在需要修改一个孩子(听起来很可怕),所以我toBuilder()在孩子身上引入了一种方法:

public Builder toBuilder() {
    return new Builder().withId(id);
}

我像这样使用它:

@Test
void modify_child() {
    final Parent parent = Parent.builder()
            .withId("1")
            .withChildren(List.of(Child.builder()
                    .withId("2")
                    .build()))
            .build();

    final Child modifiedChild = parent.getChildren().get(0).toBuilder().withId("3").build();
    System.out.println(modifiedChild.getParent());
}

这个测试的输出当然是null,因为我不维护对 parent 的引用,因为它不是构建器的一部分。

如何在允许修改子代的同时改进我的模式并保持父子关系?

这是使用杰克逊解决的,还是简单地以更合适的方式处理修改?

标签: javajsonjackson

解决方案


推荐阅读