【问题标题】:How do I create a safe Lombok JPA entity?如何创建安全的 Lombok JPA 实体?
【发布时间】:2021-07-26 10:35:17
【问题描述】:

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

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

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

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

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

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

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

如何像这样使用 Lombok 安全地创建实体?
我将不得不混合使用注释和手动方法吗?

【问题讨论】:

    标签: java hibernate jpa lombok


    【解决方案1】:

    @EqualsAndHashCode@ToString 等一些 lombok 注释具有 Exclude 选项。但是@Data@AllArgsConstructor 都没有类似的选项。 但是@Data 会为所有未定义 setter 的字段生成 setter。因此,您将为必填字段定义一个如下所示的设置器,它什么都不做。

    private void setId(Long id) {
        // Do nothing
    }
    

    您可以使用@RequiredArgsConstructor,而不是@AllArgsConstructor,但使用@NonNull 注释要在构造函数中的所有字段(或者该字段应该是最终字段)。 Refer this answer for RequiredArgsConstructor.

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

    这将阻止从外部使用构造函数,但同时允许您使用构建器创建对象。此时,您可以使用构建器将值设置为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; 
        }
    
    }
    

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

    【讨论】:

    • stackoverflow.com/a/23778200/7804477 -> SomeArgsContructor 也在开发中。
    • 更好的是,只需编写一个只接受属性的构造函数并将@Builder 添加到其中。这样生成的值就不能被构建器方法更改。
    • @NathanToulbert OP 提到这样的构造函数已经存在。问题还指出“...我想试试 Lombok 看看我是否可以避免这里涉及很多“样板”。该实体有 20 个字段,所以辅助构造函数将有 18 个参数。这是一个非常长的构造函数 :-))。如果你可以使用两个小方法来避免冗长的构造函数(它会存在但你看不到它),那么当目的是减少样板代码。
    • 同意。我昨晚读了这个问题,但忘记了二十个属性。也就是说,在这种情况下,我会通过 IDE 生成构造函数并进行编辑,似乎找到解决方法是这里效率最低的解决方案。
    • AllArgsConstructor / 类级别构建器的主要问题是它正在生成一种方法来设置应该是不可变的属性。如果 Lombok 可以为 NonNull 添加一个免费的方法(例如 Exclude),这样就可以明确地将属性排除在这些方法之外。
    【解决方案2】:

    我们有 @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());
    }
    

    【讨论】:

      猜你喜欢
      • 2021-01-13
      • 2020-01-20
      • 2011-03-04
      • 1970-01-01
      • 2018-04-13
      • 2013-08-30
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多