Для перевірки кількох властивостей слід використовувати обмеження на рівні класу. З
Bean Validation Sneak Peek, частина II: користувацькі обмеження :
### Обмеження на рівні класу
Деякі з вас висловлювали занепокоєння щодо можливості застосовувати обмеження, що охоплює кілька властивостей, або виражати обмеження, які залежать від кількох властивостей. Класичний приклад - перевірка адреси. Адреси мають складні правила:
- назва вулиці є дещо стандартною і, безумовно, повинна мати обмеження довжини
- структура поштового індексу повністю залежить від країни
- місто часто можна співвіднести з поштовим індексом і зробити певну перевірку помилок (за умови, що доступна служба перевірки)
- через ці взаємозалежності просте обмеження на рівні власності відповідає законопроекту
Рішення, запропоноване специфікацією Bean Validation, є подвійним:
- він пропонує можливість змусити набір обмежень застосовуватися перед іншим набором обмежень за допомогою груп та послідовностей груп. Ця тема буде розглянута в наступному записі в блозі
- це дозволяє визначити обмеження рівня класу
Обмеження рівня класу - це регулярні обмеження (дует анотацій / реалізації), які застосовуються до класу, а не до властивості. Інакше сказано, обмеження рівня класу отримують екземпляр об'єкта (а не значення властивості) у isValid
.
@AddressAnnotation
public class Address {
@NotNull @Max(50) private String street1;
@Max(50) private String street2;
@Max(10) @NotNull private String zipCode;
@Max(20) @NotNull String city;
@NotNull private Country country;
...
}
@Constraint(validatedBy = MultiCountryAddressValidator.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AddressAnnotation {
String message() default "{error.address}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
public class MultiCountryAddressValidator implements ConstraintValidator<AddressAnnotation, Address> {
public void initialize(AddressAnnotation constraintAnnotation) {
// initialize the zipcode/city/country correlation service
}
/**
* Validate zipcode and city depending on the country
*/
public boolean isValid(Address object, ConstraintValidatorContext context) {
if (!(object instanceof Address)) {
throw new IllegalArgumentException("@Address only applies to Address");
}
Address address = (Address) object;
Country country = address.getCountry();
if (country.getISO2() == "FR") {
// check address.getZipCode() structure for France (5 numbers)
// check zipcode and city correlation (calling an external service?)
return isValid;
} else if (country.getISO2() == "GR") {
// check address.getZipCode() structure for Greece
// no zipcode / city correlation available at the moment
return isValid;
}
// ...
}
}
Розширені правила перевірки адрес залишились поза об'єктом адреси та реалізовані
MultiCountryAddressValidator
. Отримуючи доступ до екземпляра об’єкта, обмеження рівня класу мають велику гнучкість і можуть перевірити кілька корельованих властивостей. Зверніть увагу, що впорядкування тут не подається з рівняння, ми повернемось до нього у наступному дописі.
Експертна група обговорила різні підходи до підтримки властивостей: ми вважаємо, що підхід обмеження на рівні класу забезпечує достатню простоту та гнучкість у порівнянні з іншими підходами на рівні властивостей, що включають залежності. Ваш відгук вітається.