Существует ли реализация (или сторонняя реализация для), перекрестная полевая проверка в В спящем режиме Блок проверки допустимости 4.x? В противном случае, что самый чистый путь состоит в том, чтобы реализовать перекрестный полевой блок проверки допустимости?
Как пример, как можно использовать API для проверки двух свойств компонента, равны (такие как проверка полевых соответствий пароля, пароль проверяет поле).
В аннотациях я ожидал бы что-то как:
public class MyBean {
@Size(min=6, max=50)
private String pass;
@Equals(property="pass")
private String passVerify;
}
Насколько я понимаю, вы не можете использовать SVN-выключатель
(с или без - переместить
), чтобы переместить в новый репозиторий. Подумайте об этом: редакция головы вашего нового репозитория - это X, редакция вашего старого репозитория Y, так что должен сделать SVN с базовой ревизией Work Copy?
SVN Switch
говорит, что -Релютация
используется для:
Переписать рабочие метаданные URL-адреса копирования для отражения только синтаксическое изменение. Это используется при изменении корневых URL-адресов репозитория (например, изменение схемы или имена хоста), но ваша рабочая копия все еще отражает тот же каталог в том же репозитории.
Так как это не так, я боюсь, что вам придется выполнить новую проверку.
-121--2162736-Каждое ограничение поля следует обрабатывать отчетливым аннотацией валидатора, или другими словами, не предложена практика, чтобы иметь определенную проверку аннотации одного поля на других областях; Валидация по перекрестным полем должна быть сделана на уровне класса. Кроме того, JSR-303 раздел 2.2 Предпочтительный способ выражения множественных валидаций одного типа является через список аннотаций. Это позволяет указывать сообщение об ошибке.
Например, проверяя общую форму:
@FieldMatch.List({
@FieldMatch(first = "password", second = "confirmPassword", message = "The password fields must match"),
@FieldMatch(first = "email", second = "confirmEmail", message = "The email fields must match")
})
public class UserRegistrationForm {
@NotNull
@Size(min=8, max=25)
private String password;
@NotNull
@Size(min=8, max=25)
private String confirmPassword;
@NotNull
@Email
private String email;
@NotNull
@Email
private String confirmEmail;
}
Аннотация:
package constraints;
import constraints.impl.FieldMatchValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
/**
* Validation annotation to validate that 2 fields have the same value.
* An array of fields and their matching confirmation fields can be supplied.
*
* Example, compare 1 pair of fields:
* @FieldMatch(first = "password", second = "confirmPassword", message = "The password fields must match")
*
* Example, compare more than 1 pair of fields:
* @FieldMatch.List({
* @FieldMatch(first = "password", second = "confirmPassword", message = "The password fields must match"),
* @FieldMatch(first = "email", second = "confirmEmail", message = "The email fields must match")})
*/
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@Documented
public @interface FieldMatch
{
String message() default "{constraints.fieldmatch}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* @return The first field
*/
String first();
/**
* @return The second field
*/
String second();
/**
* Defines several <code>@FieldMatch</code> annotations on the same element
*
* @see FieldMatch
*/
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Documented
@interface List
{
FieldMatch[] value();
}
}
Валидатор:
package constraints.impl;
import constraints.FieldMatch;
import org.apache.commons.beanutils.BeanUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object>
{
private String firstFieldName;
private String secondFieldName;
@Override
public void initialize(final FieldMatch constraintAnnotation)
{
firstFieldName = constraintAnnotation.first();
secondFieldName = constraintAnnotation.second();
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context)
{
try
{
final Object firstObj = BeanUtils.getProperty(value, firstFieldName);
final Object secondObj = BeanUtils.getProperty(value, secondFieldName);
return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
}
catch (final Exception ignore)
{
// ignore
}
return true;
}
}
Я удивлен, это не доступно из коробки. Во всяком случае, вот возможное решение.
Я создал вариатор уровня класса, а не уровень поля, как описано в исходном вопросе.
Вот код аннотации:
package com.moa.podium.util.constraints;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = MatchesValidator.class)
@Documented
public @interface Matches {
String message() default "{com.moa.podium.util.constraints.matches}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String field();
String verifyField();
}
и сам валидатор:
package com.moa.podium.util.constraints;
import org.mvel2.MVEL;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class MatchesValidator implements ConstraintValidator<Matches, Object> {
private String field;
private String verifyField;
public void initialize(Matches constraintAnnotation) {
this.field = constraintAnnotation.field();
this.verifyField = constraintAnnotation.verifyField();
}
public boolean isValid(Object value, ConstraintValidatorContext context) {
Object fieldObj = MVEL.getProperty(field, value);
Object verifyFieldObj = MVEL.getProperty(verifyField, value);
boolean neitherSet = (fieldObj == null) && (verifyFieldObj == null);
if (neitherSet) {
return true;
}
boolean matches = (fieldObj != null) && fieldObj.equals(verifyFieldObj);
if (!matches) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("message")
.addNode(verifyField)
.addConstraintViolation();
}
return matches;
}
}
Обратите внимание, что я использовал MVL для проверки свойств проверки объекта. Это может быть заменено стандартным apis отражения или если это определенный класс, который вы проверяете, сами методы доступа.
Аннотация @matches может затем использоваться, используемая на босоре следующим образом:
@Matches(field="pass", verifyField="passRepeat")
public class AccountCreateForm {
@Size(min=6, max=50)
private String pass;
private String passRepeat;
...
}
Как отказ от ответственности, я написал это за последние 5 минут, поэтому я, наверное, еще не вытянул все ошибки. Я обновим ответ, если что-то пойдет не так.
Вы должны назвать это явно. В приведенном выше примере Bradhouse дал вам все шаги, чтобы написать пользовательское ограничение.
Добавьте этот код в классе вашего звонящего.
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
Set<ConstraintViolation<yourObjectClass>> constraintViolations = validator.validate(yourObject);
в вышеуказанном случае это было бы
Set<ConstraintViolation<AccountCreateForm>> constraintViolations = validator.validate(objAccountCreateForm);
Я предлагаю вам другое возможное решение. Возможно, менее элегантно, но проще!
public class MyBean {
@Size(min=6, max=50)
private String pass;
private String passVerify;
@AssertTrue(message="passVerify field should be equal than pass field")
private boolean isValid() {
return this.pass.equals(this.passVerify);
}
}
Метод ISVALID
автоматически вызывается валидатором.
Очень хорошее решение Bradhouse. Есть ли способ применить аннотацию @Matches к нескольким полям?
EDIT: Вот решение, которое я придумал, чтобы ответить на этот вопрос, я модифицировал Constraint, чтобы он принимал массив вместо одного значения:
@Matches(fields={"password", "email"}, verifyFields={"confirmPassword", "confirmEmail"})
public class UserRegistrationForm {
@NotNull
@Size(min=8, max=25)
private String password;
@NotNull
@Size(min=8, max=25)
private String confirmPassword;
@NotNull
@Email
private String email;
@NotNull
@Email
private String confirmEmail;
}
Код аннотации:
package springapp.util.constraints;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = MatchesValidator.class)
@Documented
public @interface Matches {
String message() default "{springapp.util.constraints.matches}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String[] fields();
String[] verifyFields();
}
А реализация:
package springapp.util.constraints;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.apache.commons.beanutils.BeanUtils;
public class MatchesValidator implements ConstraintValidator<Matches, Object> {
private String[] fields;
private String[] verifyFields;
public void initialize(Matches constraintAnnotation) {
fields = constraintAnnotation.fields();
verifyFields = constraintAnnotation.verifyFields();
}
public boolean isValid(Object value, ConstraintValidatorContext context) {
boolean matches = true;
for (int i=0; i<fields.length; i++) {
Object fieldObj, verifyFieldObj;
try {
fieldObj = BeanUtils.getProperty(value, fields[i]);
verifyFieldObj = BeanUtils.getProperty(value, verifyFields[i]);
} catch (Exception e) {
//ignore
continue;
}
boolean neitherSet = (fieldObj == null) && (verifyFieldObj == null);
if (neitherSet) {
continue;
}
boolean tempMatches = (fieldObj != null) && fieldObj.equals(verifyFieldObj);
if (!tempMatches) {
addConstraintViolation(context, fields[i]+ " fields do not match", verifyFields[i]);
}
matches = matches?tempMatches:matches;
}
return matches;
}
private void addConstraintViolation(ConstraintValidatorContext context, String message, String field) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message).addNode(field).addConstraintViolation();
}
}
Я попробовал пример Альбертховена (hibernate-validator 4.0.2.GA) и получаю ValidationException: "Аннотированные методы должны следовать соглашению об именовании JavaBeans. match() не следует." тоже. После того как я переименовал метод из "match" в "isValid", он работает.
public class Password {
private String password;
private String retypedPassword;
public Password(String password, String retypedPassword) {
super();
this.password = password;
this.retypedPassword = retypedPassword;
}
@AssertTrue(message="password should match retyped password")
private boolean isValid(){
if (password == null) {
return retypedPassword == null;
} else {
return password.equals(retypedPassword);
}
}
public String getPassword() {
return password;
}
public String getRetypedPassword() {
return retypedPassword;
}
}