Lombok - 将@EmbeddedId 字段公开给@SuperBuilder
Lombok - expose @EmbeddedId fields to @SuperBuilder
有没有办法将 @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();
整个概念背后的原因:
同名列存在于多个视图中,因此为所有视图设置一个基础 class 是合乎逻辑的。尽管实体本身是不可变的(基于数据库视图),但我想在测试中使用 builder
这就是为什么我希望它们像上面那样。
既然您在 id 中使用了 @Delegate 注释,那么您应该能够 set/get TheId 字段直接来自 BaseEntity Class.
您可以阅读 here 更多相关信息。
没有自动将委托插入 @(Super)Builder
的方法。
但是,如果您的委托人 class(在本例中为 TheId
)不包含太多字段,您可以手动将相应的 setter 方法添加到构建器 class。只需添加正确的构建器 class header,将您的代码放入其中,Lombok 将添加您未手动编写的所有剩余代码。
诚然,这有点棘手。 @SuperBuilder
生成的代码非常复杂,您不想添加太多手动内容,因为您想保留 Lombok 的优点:如果您在注释 class 中更改某些内容,您就不会不想重写您所有的手动方法。所以这个解决方案试图以一点点 performance/memory 浪费为代价来保持大部分自动化。
@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();
}
}
}
值得吗?这是一个品味问题,以及它在多大程度上提高了你的情况下构建器的 applicability/usability/readability。
有没有办法将 @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();
整个概念背后的原因:
同名列存在于多个视图中,因此为所有视图设置一个基础 class 是合乎逻辑的。尽管实体本身是不可变的(基于数据库视图),但我想在测试中使用 builder
这就是为什么我希望它们像上面那样。
既然您在 id 中使用了 @Delegate 注释,那么您应该能够 set/get TheId 字段直接来自 BaseEntity Class.
您可以阅读 here 更多相关信息。
没有自动将委托插入 @(Super)Builder
的方法。
但是,如果您的委托人 class(在本例中为 TheId
)不包含太多字段,您可以手动将相应的 setter 方法添加到构建器 class。只需添加正确的构建器 class header,将您的代码放入其中,Lombok 将添加您未手动编写的所有剩余代码。
诚然,这有点棘手。 @SuperBuilder
生成的代码非常复杂,您不想添加太多手动内容,因为您想保留 Lombok 的优点:如果您在注释 class 中更改某些内容,您就不会不想重写您所有的手动方法。所以这个解决方案试图以一点点 performance/memory 浪费为代价来保持大部分自动化。
@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();
}
}
}
值得吗?这是一个品味问题,以及它在多大程度上提高了你的情况下构建器的 applicability/usability/readability。