如何访问注释 属性 中描述的字段
How to access a field which is described in annotation property
是否可以访问一个字段值,其中字段名称在注释中描述,该注释在 class 中注释另一个字段。
例如:
@Entity
public class User {
@NotBlank
private String password;
@Match(field = "password")
private String passwordConfirmation;
}
注解:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@Documented
public @interface Match {
String message() default "{}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String field();
}
现在,是否可以从 ConstraintValidator 实现中的 class 用户访问字段密码 class?
编辑:
我写了这样的东西:
public class MatchValidator implements ConstraintValidator<Match, Object> {
private String mainField;
private String secondField;
private Class clazz;
@Override
public void initialize(final Match match) {
clazz = User.class;
final Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Match.class)) {
mainField = field.getName();
}
}
secondField = match.field();
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext constraintValidatorContext) {
try {
Object o; //Now how to get the User entity instance?
final Object firstObj = BeanUtils.getProperty(o, mainField);
final Object secondObj = BeanUtils.getProperty(o, secondField);
return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
} catch (final Exception ignore) {
ignore.printStackTrace();
}
return true;
}
}
现在的问题是如何获取用户对象实例并比较字段值?
你要么需要写一个class level constraint in which you get the full User instance passed into the isValid call or you can use something like @ScriptAssert.
目前无法将根 bean 实例作为 "normal" 字段验证的一部分进行访问。有一个 BVAL 问题 - BVAL-237 - 讨论添加此功能,但到目前为止它还不是 Bean 验证规范的一部分。
请注意,atm 无法访问根 bean 是有充分理由的。对于 validateValue 情况,依赖于可访问根 bean 的约束将失败。
@Hardy 然后求小费。最后写了一些符合(或多或少)预期结果的代码。
我会贴在这里,也许会帮助某人解决他的问题。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Match {
String field();
String message() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MatchValidator.class)
@Documented
public @interface EnableMatchConstraint {
String message() default "Fields must match!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class MatchValidator implements ConstraintValidator<EnableMatchConstraint, Object> {
@Override
public void initialize(final EnableMatchConstraint constraint) {}
@Override
public boolean isValid(final Object o, final ConstraintValidatorContext context) {
boolean result = true;
try {
String mainField, secondField, message;
Object firstObj, secondObj;
final Class<?> clazz = o.getClass();
final Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Match.class)) {
mainField = field.getName();
secondField = field.getAnnotation(Match.class).field();
message = field.getAnnotation(Match.class).message();
if (message == null || "".equals(message))
message = "Fields " + mainField + " and " + secondField + " must match!";
firstObj = BeanUtils.getProperty(o, mainField);
secondObj = BeanUtils.getProperty(o, secondField);
result = firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
if (!result) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message).addPropertyNode(mainField).addConstraintViolation();
break;
}
}
}
} catch (final Exception e) {
// ignore
//e.printStackTrace();
}
return result;
}
}
以及如何使用它...?像这样:
@Entity
@EnableMatchConstraint
public class User {
@NotBlank
private String password;
@Match(field = "password")
private String passwordConfirmation;
}
Hack around...Hack 因为这些内部 Hibernate 实现在迁移到 Java 模块时将无法工作。
@Override
public boolean isValid(final Serializable value, final ConstraintValidatorContext context) {
var context = (ConstraintValidatorContextImpl) context;
//no-inspection unchecked
var descriptor = (ConstraintDescriptorImpl<Exists>) context.getConstraintDescriptor();
var existsAnnotation = descriptor.getAnnotationDescriptor().getAnnotation();
// Removed b/c irrelevant
}
是否可以访问一个字段值,其中字段名称在注释中描述,该注释在 class 中注释另一个字段。
例如:
@Entity
public class User {
@NotBlank
private String password;
@Match(field = "password")
private String passwordConfirmation;
}
注解:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@Documented
public @interface Match {
String message() default "{}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String field();
}
现在,是否可以从 ConstraintValidator 实现中的 class 用户访问字段密码 class?
编辑:
我写了这样的东西:
public class MatchValidator implements ConstraintValidator<Match, Object> {
private String mainField;
private String secondField;
private Class clazz;
@Override
public void initialize(final Match match) {
clazz = User.class;
final Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Match.class)) {
mainField = field.getName();
}
}
secondField = match.field();
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext constraintValidatorContext) {
try {
Object o; //Now how to get the User entity instance?
final Object firstObj = BeanUtils.getProperty(o, mainField);
final Object secondObj = BeanUtils.getProperty(o, secondField);
return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
} catch (final Exception ignore) {
ignore.printStackTrace();
}
return true;
}
}
现在的问题是如何获取用户对象实例并比较字段值?
你要么需要写一个class level constraint in which you get the full User instance passed into the isValid call or you can use something like @ScriptAssert.
目前无法将根 bean 实例作为 "normal" 字段验证的一部分进行访问。有一个 BVAL 问题 - BVAL-237 - 讨论添加此功能,但到目前为止它还不是 Bean 验证规范的一部分。
请注意,atm 无法访问根 bean 是有充分理由的。对于 validateValue 情况,依赖于可访问根 bean 的约束将失败。
@Hardy 然后求小费。最后写了一些符合(或多或少)预期结果的代码。
我会贴在这里,也许会帮助某人解决他的问题。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Match {
String field();
String message() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MatchValidator.class)
@Documented
public @interface EnableMatchConstraint {
String message() default "Fields must match!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class MatchValidator implements ConstraintValidator<EnableMatchConstraint, Object> {
@Override
public void initialize(final EnableMatchConstraint constraint) {}
@Override
public boolean isValid(final Object o, final ConstraintValidatorContext context) {
boolean result = true;
try {
String mainField, secondField, message;
Object firstObj, secondObj;
final Class<?> clazz = o.getClass();
final Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Match.class)) {
mainField = field.getName();
secondField = field.getAnnotation(Match.class).field();
message = field.getAnnotation(Match.class).message();
if (message == null || "".equals(message))
message = "Fields " + mainField + " and " + secondField + " must match!";
firstObj = BeanUtils.getProperty(o, mainField);
secondObj = BeanUtils.getProperty(o, secondField);
result = firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
if (!result) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message).addPropertyNode(mainField).addConstraintViolation();
break;
}
}
}
} catch (final Exception e) {
// ignore
//e.printStackTrace();
}
return result;
}
}
以及如何使用它...?像这样:
@Entity
@EnableMatchConstraint
public class User {
@NotBlank
private String password;
@Match(field = "password")
private String passwordConfirmation;
}
Hack around...Hack 因为这些内部 Hibernate 实现在迁移到 Java 模块时将无法工作。
@Override
public boolean isValid(final Serializable value, final ConstraintValidatorContext context) {
var context = (ConstraintValidatorContextImpl) context;
//no-inspection unchecked
var descriptor = (ConstraintDescriptorImpl<Exists>) context.getConstraintDescriptor();
var existsAnnotation = descriptor.getAnnotationDescriptor().getAnnotation();
// Removed b/c irrelevant
}