【问题标题】:Lombok - expose @EmbeddedId fields to @SuperBuilderLombok - 将 @EmbeddedId 字段暴露给 @SuperBuilder
【发布时间】:2021-10-28 16:16:22
【问题描述】:

有没有办法将@EmbeddedId 中定义的属性暴露给@SuperBuilder

// Composite id class
@Data
@Builder(builderMethodName = "having")
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
public class TheId {
    @Column(name = "name", insertable = false)
    private String name;

    @Column(name = "description", insertable = false)
    private String description;
}

// Base entity class
@SuperBuilder 
@Getter
@Immutable
@MappedSuperclass
@AllArgsConstructor
@NoArgsConstructor
public class BaseEntity implements Serializable {
    @Delegate
    @EmbeddedId
    private TheId id;

    @Column(name = "long_description", insertable = false)
    private String longDescription;
}

// Concreate entity over database view
@Entity
@Table(name = "view_number_1")
@Getter
@Setter
@Immutable
@AllArgsConstructor(staticName = "of")
@SuperBuilder(builderMethodName = "having")
public class ConcreteEntity1 extends BaseEntity {}

我希望能够编写这样的代码:

ConcreateEntity1.having()
    .name("the name")
    .description("something")
    .longDescription("akjsbdkasbd")
    .build();

而不是

ConcreateEntity1.having()
    .id(TheId.having()
        .name("the name")
        .description("something")
        .build())
    .longDescription("akjsbdkasbd")
    .build();

整个概念背后的原因: 同名列存在于多个视图中,因此为所有视图使用一个基类是合乎逻辑的。虽然实体本身是不可变的(基于数据库视图),但我想在测试中使用builder,这就是为什么我想像上面那样使用它们。

【问题讨论】:

    标签: java spring lombok


    【解决方案1】:

    没有自动方式将代理插入@(Super)Builder。 但是,如果您的被委托人类(在这种情况下为TheId)不包含太多字段,则可以手动将相应的 setter 方法添加到构建器类中。只需添加正确的构建器类头,将您的代码放入其中,Lombok 将添加您未手动编写的所有剩余代码。

    诚然,这有点棘手。 @SuperBuilder 生成的代码相当复杂,你不想添加太多手动的东西,因为你想保持 Lombok 的优点:如果你在你的注释类中改变了一些东西,你不会想重写你所有的手动方法。所以这个解决方案试图以一点点性能/内存浪费为代价来保持大部分自动化。

    @SuperBuilder(builderMethodName = "having")
    public class BaseEntity {
        @Delegate
        private TheId id;
    
        private String longDescription;
    
        public static abstract class BaseEntityBuilder<C extends BaseEntity, B extends BaseEntityBuilder<C, B>> {
            private TheId.TheIdBuilder theIdBuilder = TheId.having();
            
            // Manually implement all delegations.
            public B name(String name) {
                theIdBuilder.name(name);
                // Instantiating every time you call the setter is not optimal, 
                // but better than manually writing the constructor.
                id = theIdBuilder.build();
                return self();
            }
            public B description(String description) {
                theIdBuilder.description(description);
                id = theIdBuilder.build();
                return self();
            }
            
            // Make this method invisible. 
            @SuppressWarnings("unused")
            private B id() {
                return self();
            }
        }
    }
    

    值得吗?这是一个品味问题,以及它在多大程度上提高了构建器在您的案例中的适用性/可用性/可读性。

    【讨论】:

    • 是的,感觉像这样的自定义实现不值得付出努力。我以为 Lombok 中有一些内置功能我没找到。
    【解决方案2】:

    由于您在 id 中使用了@Delegate 注解,那么您应该能够直接从 BaseEntity 类中设置/获取 TheId 字段。

    您可以阅读here 了解更多信息。

    【讨论】:

      猜你喜欢
      • 2020-07-18
      • 2011-09-07
      • 1970-01-01
      • 2011-04-02
      • 1970-01-01
      • 1970-01-01
      • 2010-09-19
      • 2013-08-30
      • 1970-01-01
      相关资源
      最近更新 更多