【问题标题】:Advanced bidirection jackson serialization to avoid infinite recusion高级双向杰克逊序列化以避免无限递归
【发布时间】:2021-03-10 03:01:19
【问题描述】:

我有一个 Spring Data 项目,它大致有实体设置,我在下面的最小实现中展示了我的问题:

public class JacksonTest {
  @Test
  public void userWithRoles() throws JsonProcessingException {
    User u1 = new User();
    u1.setName("U1");

    Role r1 = new Role();
    r1.setName("R1");

    UserRole ur1 = new UserRole();
    ur1.setRole(r1);
    ur1.setUser(u1);
    ur1.setMetaData("metaData1");

    u1.setRoles(Collections.singletonList(ur1));
    r1.setUsers(Collections.singletonList(ur1));

    String result = new ObjectMapper().writeValueAsString(u1);

    /*
    Expected result
    {
    name: U1,
    roles: [{metaData: metaData1, role: {name: R1}}]
    }
     */

  }

  @Test
  public void roleWithUsers() throws JsonProcessingException {
    User u1 = new User();
    u1.setName("U1");

    Role r1 = new Role();
    r1.setName("R1");

    UserRole ur1 = new UserRole();
    ur1.setRole(r1);
    ur1.setUser(u1);
    ur1.setMetaData("metaData1");

    u1.setRoles(Collections.singletonList(ur1));
    r1.setUsers(Collections.singletonList(ur1));

    String result = new ObjectMapper().writeValueAsString(r1);

    /*
    Expected result
    {
    name: R1,
    users: [{metaData: metaData1, user: {name: U1}}]
    }
     */
  }
}

@Data
class UserRole {
  User user;
  Role role;
  String metaData;
}

@Data
class User {
  String name;
  List<UserRole> roles;
}

@Data
class Role {
  String name;
  List<UserRole> users;
}

运行任何一个测试都会导致无限递归。

我曾尝试使用@JsonIgnore@JsonManagedReference@JsonBackReference 来解决我的问题,但它们都不能使两个测试都变成绿色。

我遇到的主要问题是序列化应该给出不同版本的UserRole,这取决于我是序列化User 还是Role,如两个测试中所示。

我的问题是如何使这里的两个测试都与预期的输出一起工作?

【问题讨论】:

  • 在这两种情况下,您都在序列化用户,那么为什么要区分呢?
  • 我的错,我已经更新了这个例子。问题是一样的

标签: json spring-boot spring-data-jpa jackson spring-data


【解决方案1】:

写一个自定义JsonSerializer

  • 一个用于List&lt;UserRole&gt; roles 中的User @see UserUserRoleSerializer
  • 和另一个List&lt;UserRole&gt; users in Role @see RoleUserRoleSerializer
@Data
class UserRole {
    User user;
    Role role;
    String metaData;
}

@Data
class User {
    String name;
    @JsonSerialize(using = UserUserRoleSerializer.class)
    List<UserRole> roles;
}

@Data
class Role {
    String name;
    @JsonSerialize(using = RoleUserRoleSerializer.class)
    List<UserRole> users;
}

class RoleUserRoleSerializer extends JsonSerializer<List<UserRole>>  {

    @Override
    public void serialize(List<UserRole> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartArray();
        for (UserRole userRole : value) {
            gen.writeStartObject();
            gen.writeObjectField("role", userRole.role.name);
            gen.writeObjectField("metadata", userRole.metaData);
            gen.writeEndObject();
        }
        gen.writeEndArray();
    }
}

class UserUserRoleSerializer extends JsonSerializer<List<UserRole>> {

    @Override
    public void serialize(List<UserRole> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartArray();
        for (UserRole userRole : value) {
            gen.writeStartObject();
            gen.writeObjectField("user", userRole.user.name);
            gen.writeObjectField("metadata", userRole.metaData);
            gen.writeEndObject();
        }
        gen.writeEndArray();
    }
}

这将输出:

userWithRoles:{"name":"U1","roles":[{"user":"U1","metadata":"metaData1"}]}

roleWithUsers:{"name":"R1","users":[{"role":"R1","metadata":"metaData1"}]}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-10
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    • 2017-02-15
    • 2018-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多