如何在测试代码中没有自动生成字段的情况下序列化 Hibernate 实体?

How do I serialize Hibernate entities without auto generated fields in test code?

我有一个包含以下字段的 Hibernate 实体:

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "email")
    private String email;
}

我有一个端点来创建我想测试的员工。为此,我需要发送实体的 json 表示,但不包含数据库生成的 ID。

我更愿意使用 ObjectMapper 来创建这些表示而不是 fiddle 我自己使用字符串。

问题是 ObjectMapper.writeValueAsString(employee) 将在 json 中包含 id。 @JsonIgnore 无法使用,因为我需要服务器的响应包含 id。

我能看到的解决这个问题的唯一方法是创建一个由测试代码使用的自定义员工序列化程序,例如:

public class EmployeeClientSerializer extends StdSerializer<Employee> {
    public EmployeeClientSerializer() {
        this(null);
    }

    public EmployeeClientSerializer(Class<Employee> e) {
        super(e);
    }

    @Override
    public void serialize(Employee employee, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        gen.writeStringField("firstName", employee.getFirstName());
        gen.writeStringField("lastName", employee.getLastName());
        gen.writeStringField("email", employee.getEmail());
        gen.writeEndObject();
    }
}

有更好的方法吗?

您可以创建一个 DTO 对象,它将表示没有 ID 字段的所需实体 class 实例。然后你可以创建一个映射器来自动处理 DTO 实例构建过程(使用 Mapstruct)。然后你可以用ObjectMapper实例序列化DTO实例。

通常情况下,当事情变得复杂时,DTO class 确实是最佳选择,但这也涉及从实体到 DTO 的映射,反之亦然。

我不确定您打算如何序列化您的测试数据。但是,如果您唯一的问题是 id 中会有价值,那应该不是问题,也许自定义序列化程序是一种有点矫枉过正的解决方案。看看这个简化的 class:

@Getter @Setter
public class PrimitiveId {
    private long id;        
    private String firstName;
} 

因为 id 是原始类型 long 它不能是 null 并且默认为 0。所以:

PrimitiveId primitiveId = new PrimitiveId();
primitiveId.setFirstName("Primitive");
System.out.println(om.writeValueAsString(primitiveId));

将打印:

{"id":0,"firstName":"Primitive"}

除了进行一些自定义序列化之外,您无能为力。除非您将 id 更改为盒装 Long,例如:

@Getter @Setter
public class BoxedId {
    private Long id;
    private String firstName; 
}

序列化

BoxedId boxedId = new BoxedId();
boxedId.setFirstName("Boxed");
System.out.println(om.writeValueAsString(boxedId));

现在会生产

{"id":null,"firstName":"Boxed"}

id里的null不会坏,因为不会连载,毕竟是null

如果你真的需要摆脱它,告诉它 ObjectMapper:

om.setSerializationInclusion(Include.NON_NULL); // serializes only non null values
System.out.println(om.writeValueAsString(boxedId));

{"firstName":"Boxed"}