如何创建安全的 Lombok JPA 实体?

opt*_*lic 7 java hibernate jpa lombok

我有@Entity20 个字段,包括索引和由 Hibernate 更新的时间戳:

@Entity
public class MyEntity {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  @UpdateTimestamp
  private LocalDateTime updatedTime;
  private String ....
  private String ....
Run Code Online (Sandbox Code Playgroud)

我有一个 Hibernate 的默认构造函数和一个辅助构造函数来设置除 id 和 UpdatedTime 之外的所有内容。

我不需要(或想要)id 或updatedTime 的setter,因为我只希望Hibernate 设置它们,并且它通过反射来实现。

我想尝试一下 Lombok,看看是否可以避免这里涉及的大量样板,但@Data添加了 getter 和 setter,并且不创建相同的构造函数。

我还担心 Lomboks 生成的 equals/hashCode 和 toString 方法可能会导致 Hibernate 出现微妙的问题。

这意味着我必须结合使用其他 Lombok 注释来执行此操作。

如何像这样使用 Lombok 安全地创建实体?
我是否必须混合使用注释和手动方法?

Gau*_*m M 5

一些 lombok 注释例如@EqualsAndHashCode@ToStringExclude选项。但两者都没有@Data类似@AllArgsConstructor的选择。但会为尚未定义 setter 的@Data所有字段生成 setter 。因此,您可以为必填字段定义一个设置器,如下所示,但它不执行任何操作。

private void setId(Long id) {
    // Do nothing
}
Run Code Online (Sandbox Code Playgroud)

@AllArgsConstructor您可以使用代替@RequiredArgsConstructor,但可以使用 注释构造函数中的所有字段@NonNull(或者该字段应该是最终字段)。 请参阅此答案以获得RequiredArgsConstructor

我建议的方法:另一种方法是使用@Builder注释与@AllArgsConstructor(access = AccessLevel.PRIVATE). (注意:默认情况下,Builder 添加一个私有的所有参数构造函数,但只有在没有其他构造函数时才会这样做。但在您的情况下,存在默认构造函数,您需要显式提及所有参数注释。)

这将阻止从外部使用构造函数,但同时允许您使用构建器创建对象。此时,您可以将值设置为idupdateTime使用构建器。为了防止这种情况,您还需要添加以下代码。

public static class MyEntityBuilder {
    // access is restricted using
    // these private dummy methods.

    private MyEntityBuilder id(Long id) { 
        return this; 
    }

    private MyEntityBuilder updateTime(LocalDateTime time) { 
        return this; 
    }

}
Run Code Online (Sandbox Code Playgroud)

因此,即使不可能直接实现您的要求,您也可以通过在构建器类中添加两个虚拟 setter 方法和另外两个虚拟方法来实现。


sai*_*999 1

我们有 @NoArgsConstructor @AllArgsConstructor 用于使用 lombok 生成构造函数。

这就是我创建它们的方式。


@Entity
@Table(schema = "S25", name = "bank")
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Getter
@Setter
public class Bank {

  @Id
  @SequenceGenerator(name = "bankEntitySeq", sequenceName = "SEQ_BANKS", allocationSize = 1)
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "bankSeq")
  @Column(name = "bank_id")
  private Long bankId;

  @Column(name = "bank_name")
  private String bankName;

  
  @Column(name = "created_on")
  private Date createdOn =
      new Date(); //Date.from(Instant.now().atZone(ZoneId.of("UTC")).toInstant());
}
Run Code Online (Sandbox Code Playgroud)