Рассмотрим подход, основанный на аннотациях. Это будет производить меньше кода (кажется) и почти всегда легче понять.
Введите новую аннотацию:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Validators {
String[] values();
}
Примените эту аннотацию к каждому объекту и встраиваемому объекту, который нуждается в проверке, например ::
@MappedSuperclass
@EntityListeners( { ValidatorListener.class })
@Validators({Type.PERSIST, Type.UPDATE})
public abstract class MyEntity extends BaseEntity implements Serializable, Validateable {
// other stuff
@Validators(Type.PERSIST)
@Embedded
public Address getAddress() {
return address;
}
}
Конечно, каждая сущность и встраиваемый объект должны по-прежнему реализовывать интерфейс Validateable, который становится проще:
public interface Validateable {
void validate(Type type);
}
Тогда проверка логики становится проще:
- проверить, помечена ли сущность
@Validators
;
- если нет, переходите к итерации по встроенным элементам;
- проверить, реализует ли сущность
Validateable
;
- если нет, то итерация по встроенным элементам (возможно, выдача предупреждения для объекта: «Объект, помеченный
Validators
, но не реализующий Validatable
интерфейс»)
- если оба да, то запустить
validate
, если соответствующий тип соответствует слушателю;
- перебирать внедренные элементы с той же логикой, что и выше.
Этот подход позволяет отделить объявление проверки сущностей и их встраиваемых элементов (аннотаций) от логики проверки (классы Java - сущности и встраиваемые классы). Например, иногда встраиваемый объект может реализовывать Validateable
, но проверка не требуется. Кажется, что слушатель также становится проще.
Но если вы не отделили декларации валидации от логики валидации, тогда ваше решение вполне удовлетворительно и, возможно, проще.