····int adjust = 0; if (now.get(DAY_OF_YEAR) — birth.get(DAY_OF_YEAR) < 0) {

······adjust = -1;

····}

····customer.setAge(now.get(YEAR) — birth.get(YEAR) + adjust);

··}

}

Листинг 6.40. Слушатель, используемый для валидации атрибутов сущности Customer

public class DataValidationListener {

··@PrePersist

··@PreUpdate

··private void validate(Customer customer) {

····if (customer.getFirstName() == null || "".equals(customer.getFirstName()))

······throw new IllegalArgumentException("Неверное имя");

····if (customer.getLastName() == null || "".equals(customer.getLastName()))

······throw new IllegalArgumentException("Неверная фамилия");

··}

}

К классу-слушателю применяются только простые правила. Первое правило состоит в том, что класс должен располагать конструктором public без аргументов. Второе правило заключается в том, что подписи методов обратного вызова немного отличаются от тех, что приведены в листинге 6.38. Когда вы вызываете метод обратного вызова в слушателе, этому методу необходимо иметь доступ к состоянию сущности (например, к firstName и lastName сущности Customer, которые необходимо подвергнуть валидации). Методы должны располагать параметром, имеющим тип, который совместим с типом сущности, поскольку сущность, связанная с соответствующим событием, передается в обратный вызов. Метод обратного вызова, определенный в сущности, будет иметь такую подпись без параметров:

void <МЕТОД>();

Методы обратного вызова, определенные для слушателя сущности, могут иметь подписи двух разных типов. Если метод будет использоваться в нескольких сущностях, то у него должен быть аргумент Object:

void <МЕТОД>(Object anyEntity)

Если он предназначен только для одной сущности или ее подклассов (при наследовании), то параметр может иметь тип сущности:

void <МЕТОД>(Customer customerOrSubclasses)

Для обозначения того, что эти два слушателя будут уведомляться о событиях жизненного цикла сущности Customer, вам необходимо использовать аннотацию @EntityListeners (листинг 6.41). Она может принимать в качестве параметра один слушатель сущности либо массив слушателей. Если будет определено несколько слушателей и произойдет событие жизненного цикла, то поставщик постоянства произведет итерацию по каждому слушателю в том порядке, в котором они указаны, и вызовет метод обратного вызова, передав ссылку на сущность, к которой относится соответствующее событие. Затем он вызовет методы обратного вызова в самой сущности (при наличии таковых).

Листинг 6.41. Сущность Customer, для которой определяется два слушателя

@EntityListeners({DataValidationListener.class, AgeCalculationListener.class})

@Entity

public class Customer {

··@Id @GeneratedValue

··private Long id;

··private String firstName;

··private String lastName;

··private String email;

··private String phoneNumber;

··@Temporal(TemporalType.DATE)

··private Date dateOfBirth;

··@Transient

··private Integer age;

··@Temporal(TemporalType.TIMESTAMP)

··private Date creationDate;

··// Конструкторы, геттеры, сеттеры

}

Результат выполнения этого кода будет точно таким же, что и кода из листинга 6.38. Сущность Customer валидирует свои данные перед вставкой или обновлением с использованием метода DataValidationListener.validate() и вычислит значение своего age с помощью метода слушателя AgeCalculationListener.calculateAge().

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

• Могут генерироваться только непроверяемые исключения. Это приводит к тому, что остальные слушатели и методы обратного вызова не вызываются, а транзакция подвергается откату (при наличии таковой).

Перейти на страницу:

Похожие книги