Рубрики
Без рубрики

Ломбок и JPA: Что может пойти не так?

Lombok – отличный инструмент, который делает ваш Java-код лаконичным и чистым. Однако есть несколько вещей, которые следует учитывать… Помечен как java, jpa, гибернация, ломбок.

Lombok – отличный инструмент, который делает ваш Java-код лаконичным и чистым. Тем не менее, есть несколько вещей, которые следует учитывать при использовании его с JPA. В этой статье мы рассмотрим, как неправильное использование Lombok может снизить производительность приложений JPA или даже привести к их сбою, и как этого избежать, но при этом получить преимущества от использования Lombok.

Мы разрабатываем JPA Buddy – плагин для IntelliJ IDEA, предназначенный для упрощения использования JPA. Прежде чем написать для него хоть одну строчку кода, мы просмотрели массу проектов на GitHub, чтобы понять, как люди работают с JPA. Оказывается, многие из них используют Ломбок для своих сущностей.

Абсолютно нормально использовать Lombok в ваших проектах JPA, но у него есть некоторые предостережения. Анализируя проекты, мы видим, что люди снова и снова натыкаются на одни и те же ловушки. Вот почему мы ввели ряд проверок кода для Lombok в JPA Buddy. В этой статье показаны наиболее распространенные проблемы, с которыми вы можете столкнуться при использовании Lombok с объектами JPA.

Сломанные хэш-наборы (и хэш-карты)

Классы сущностей часто аннотируются @EqualsAndHashCode или @Data . В документации @EqualsAndHashCode говорится:

По умолчанию в нем будут использоваться все нестатические, непостоянные поля, но вы можете изменить, какие поля используются (и даже указать, что должны использоваться выходные данные различных методов), пометив элементы типа @EqualsAndHashCode. Включите или @Equals и хэш-код. Исключить .

Equals()/Хэш-код() реализация для объектов JPA является чувствительной темой. Естественно, сущности изменчивы. Даже идентификатор сущности часто генерируется базой данных, поэтому он изменяется после первого сохранения сущности. Это означает, что нет полей, на которые мы могли бы положиться для вычисления хэш-кода.

Например, давайте создадим тестовую сущность:

@Entity
@EqualsAndHashCode
public class TestEntity {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(nullable = false)
   private Long id;

}

И выполните следующий код:

TestEntity testEntity = new TestEntity();
Set set = new HashSet<>();

set.add(testEntity);
testEntityRepository.save(testEntity);

Assert.isTrue(set.contains(testEntity), "Entity not found in the set");

Утверждение в последней строке терпит неудачу, даже если объект добавлен в набор всего несколькими строками выше. Удаление @equalsи хэш-кода дает нам следующее:

public int hashCode() {
   final int PRIME = 59;
   int result = 1;
   final Object $id = this.getId();
   result = result * PRIME + ($id == null ? 43 : $id.hashCode());
   return result;
}

Как только идентификатор сгенерирован (при первом сохранении), хэш-код изменяется. Таким образом, хэш-набор ищет сущность в другом сегменте и не может ее найти. Это не было бы проблемой, если бы идентификатор был установлен во время создания объекта сущности (например, имеет идентификатор UUID, установленный приложением), но идентификаторы, сгенерированные БД, встречаются чаще.

Случайная загрузка Ленивых Атрибутов

Как упоминалось выше, @EqualsAndHashCode по умолчанию включает все поля объекта. То же самое верно и для @В строку :

Любое определение класса может быть аннотировано с помощью @toString чтобы позволить ломбоку сгенерировать реализацию метода toString() . По умолчанию в нем будет выведено имя вашего класса вместе с каждым полем по порядку, разделенное запятыми.

Эти методы вызывают equals()/Хэш-код()/toString() для каждого поля объекта. Это может иметь нежелательный побочный эффект для объектов JPA: случайная загрузка отложенных атрибутов.

Например, вызов hashCode() на ленивом @OneToMany может извлечь все содержащиеся в нем сущности. Это может легко снизить производительность приложения. Это также может привести к исключению LazyInitializationException, если это происходит вне транзакции.

Мы считаем @EqualsAndHashCode и @Data вообще не следует использовать для сущностей , поэтому JPA Buddy предупреждает разработчиков:

@toString все еще можно использовать, но все отложенные поля должны быть исключены. Это может быть достигнуто путем размещения @toString. Исключите в нужных полях или с помощью @toString(только явно включенный) для класса и @toString. Включить в не ленивые поля. У приятеля из JPA есть для этого специальная акция:

Отсутствует Конструктор Без Аргументов

Согласно спецификации JPA, все классы сущностей должны иметь открытый или защищенный конструктор без аргументов. Очевидно, что при использовании @AllArgsConstructor компилятор не создает конструктор по умолчанию, то же самое верно для @Builder :

Применение @Builder к классу похоже на то, как если бы вы добавили @AllArgsConstructor(доступ. ПОСЫЛКА) к классу и применил аннотацию @Builder к этому конструктору всех аргументов.

Поэтому обязательно всегда используйте их с @NoArgsConstructor или явным конструктором без аргументов:

Вывод

Ломбок делает ваш код более привлекательным, но, как и в случае с любым волшебным инструментом, важно понимать, как именно он работает и когда его использовать. Вы также можете полагаться на инструменты разработки для прогнозирования потенциальных проблем для вас. В противном случае вы можете случайно снизить производительность вашего приложения или даже что-то сломать.

При работе с JPA и Lombok помните об этих правилах:

  • Избегайте использования @equalsи хэш-кода и @Данные с объектами JPA;
  • Всегда исключайте ленивые атрибуты при использовании @В строку ;
  • Не забудьте добавить @NoArgsConstructor в объекты с помощью – @Builder или @AllArgsConstructor .

Или позвольте JPA Buddy запомнить их для вас: его проверки кода всегда к вашим услугам.

Оригинал: “https://dev.to/aleksey/lombok-and-jpa-what-may-go-wrong-1lcm”