#java #spring #lombok
Вопрос:
есть ли способ выставить свойства, определенные в @EmbeddedId
to @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
в тестах, поэтому я хотел бы иметь их, как указано выше.
Ответ №1:
Не существует автоматического способа вставки делегатов в @(Super)Builder
. Однако, если ваш класс делегата ( TheId
в данном случае) не содержит слишком много полей, вы можете вручную добавить соответствующие методы установки в класс builder. Просто добавьте правильный заголовок класса builder, поместите в него свой код, и 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();
}
}
}
Стоит ли оно того? Это вопрос вкуса и насколько это улучшает применимость / удобство использования / читаемость конструктора в вашем случае.
Комментарии:
1. Да, такое ощущение, что подобная пользовательская реализация не стоит затраченных усилий. Я думал, что в Lombok есть какая-то встроенная функция, которую я не смог найти.
Ответ №2:
Поскольку вы использовали аннотацию @Delegate в id, вы должны иметь возможность устанавливать / получать поля ID непосредственно из класса BaseEntity.
Подробнее об этом можно прочитать здесь.