Использование ломбоков @Data и @Builder для сущности

Я использую следующее:

@Entity
@Data
@Builder
@NoArgsConstructor(force = true)
public class User {
    private String id;
    private String firstName;
    private String lastName;
}

чего я хочу добиться: для использования JPA мне нужен POJO с noArgConstructor, геттерами/сеттерами и equals/hashCode/toString.

Для создания экземпляра (например, в тестах) я хочу использовать User.builder().build();

Проблема: он не компилируется, похоже, проблема с NoArgConstructor и RequiredFieldsConstructor:

Error:(15, 1) java: constructor User in class x.y.z.User cannot be applied to given types;
required: no arguments
found:    java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String
reason: actual and formal argument lists differ in length

Обновление: ошибка возникает, когда я пытаюсь создать новый объект через new... работает builder().

Что мне не хватает? Нельзя ли одновременно использовать @Data, @Entity и @Builder?


person Jan Galinski    schedule 09.11.2016    source источник
comment
Будет ли это работать, если вы сами определите пустой конструктор без аргументов?   -  person Ian McLaird    schedule 10.11.2016
comment
К сожалению, тогда я получаю мгновенную ошибку: компилятор уже существует   -  person Jan Galinski    schedule 10.11.2016
comment
Вы пытались добавить RequiredArgsConstructor и NoArgsConstructor?   -  person Roel Spilker    schedule 14.11.2016
comment
Спасибо @RoelSpilker, использование обеих аннотаций сработало ... но \@Data не дает мне полей родительских классов в построителе, поэтому этот подход совершенно бесполезен для моего случая. Я перестану беспокоиться об этом и продолжу работу с пользовательскими сборщиками.   -  person Jan Galinski    schedule 22.11.2016


Ответы (4)


попробуйте этот код с версией ломбока 1.16.18 поверх:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class User {
    private String id;
    private String firstName;
    private String lastName;
}
person 장재훈    schedule 12.01.2018
comment
Это правильный пример, но, как правило, вы не можете использовать @Data для любого @Entity! Equals, hashCode и toString могут конфликтовать со спецификацией JPA или с отложенной загрузкой. - person Lubo; 22.10.2019
comment
Да, я согласен с вами. Так что лучше добавить @Getter, @Setter вместо @Data. - person 장재훈; 10.08.2020

Помните, что объекты данных не являются сущностями! Проще говоря, есть проблема с hashcode/equals (когда он учитывает поля id), а также с методом toString с ленивой загрузкой частей сущности. Для справки вы можете прочитать статью Влада Михалчеаса.

Вам следует:

  • исключить поля id из hashcode/equals
  • исключить поля ассоциации, которые не управляются в данном объекте, из хэш-кода/равно
  • исключить все лениво загруженные поля из метода toString
  • исключить поля, которые могут вызывать циклические ссылки из метода toString

Обязательно прочитайте хоть что-нибудь на тему того, как JPA выполняет "грязную проверку", прежде чем быть уверенным, что ваш рукописный или сгенерированный метод equals/hashcode в порядке.

person Lubo    schedule 22.10.2019

Я отвечу на свой вопрос, обобщив комментарии.

Прежде всего, благодаря @RoelSpilker, вы можете использовать Builder и Data вместе в одном Pojo, если вы явно предоставляете конструкторы AllArgs- и NoArgs-:

 @RequiredArgsConstructor
 @NoArgsConstructor
 @Data
 @Builder
 public class Person {...}

Но: билдер, созданный для этого класса, не будет знать никаких унаследованных полей. Для моего варианта использования (с некоторыми AbstractEntities) это делает решение бесполезным, и пока я буду придерживаться ручных помощников/построителей.

person Jan Galinski    schedule 22.11.2016
comment
В вашем ответе не упоминается, что класс является объектом JPA, но в вопросе прямо говорится об объекте. Если это так, вы не должны использовать @Data и @Entity вместе. Lombok сгенерирует для вас hashCode() и equals(), используя все поля, включая id, чего следует избегать. Или хотя бы относиться бережно. - person wst; 14.03.2017
comment
Lombok теперь обновлен, попробуйте аннотацию @SuperBuilder как для родительского, так и для дочернего класса. - person vikingsteve; 07.02.2019

В документации Ломбока написано: Person.builder().name("Адам Сэвидж").city("Сан-Франциско").job("Разрушители мифов").job("Освобожденная реакция").build();

Используете ли вы этот синтаксис для своих целей? Судя по вашему описанию это не так, а можете объяснить выдаваемую вами ошибку?

person Xendar    schedule 09.11.2016
comment
Я не получаю ошибку, когда использую конструктор, я получаю ошибку, когда использую конструктор по умолчанию (что я должен делать, поскольку это сущность). Обновлю вопрос. - person Jan Galinski; 10.11.2016