如何编写(类型级别注释)自定义注释以允许选择验证(许多属性中的一个必须不为空)?
答案 0 :(得分:4)
即使这个“问题”非常广泛,我也会给出答案,因为我在这里有完整的代码:
@Target(ElementType.TYPE)
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = ChoiceValidator.class)
public @interface Choice {
String[] value();
boolean multiple() default false;
String message() default "{com.stackoverflow.validation.Choice.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
这是一个使用bean属性访问的验证器:
public class ChoiceValidator implements ConstraintValidator<Choice, Object> {
private String[] properties;
private boolean allowMultiple;
@Override
public void initialize(Choice constraintAnnotation) {
if (constraintAnnotation.value().length < 2) {
throw new IllegalArgumentException("at least two properties needed to make a choice");
}
properties = constraintAnnotation.value();
allowMultiple = constraintAnnotation.multiple();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
try {
BeanInfo info = getBeanInfo(value.getClass());
long notNull = Stream.of(properties)
.map(property -> Stream.of(info.getPropertyDescriptors())
.filter(desr -> desr.getName().equals(property))
.findAny()
.orElse(null)
)
.map(prop -> getProperty(prop, value))
.filter(Objects::nonNull)
.count();
return allowMultiple ? notNull != 0 : notNull == 1;
} catch (IntrospectionException noBean) {
return false;
}
}
private Object getProperty(PropertyDescriptor prop, Object bean) {
try {
return prop.getReadMethod() == null ? null : prop.getReadMethod().invoke(bean);
} catch (ReflectiveOperationException noAccess) {
return null;
}
}
}
典型用法可能如下所示( lombok 注释生成getter和setter):
@Data
@Choice({"one", "two"})
class OneOf {
private String one;
private String two;
private String whatever;
}
@Data
@Choice(value = {"one", "two"}, multiple = true)
class AnyOf {
private String one;
private String two;
}
但要澄清一下:Stackoverflow是一个QA社区,供开发人员交流知识。它不是一个问“你可以免费为我编码吗?”的地方。所有有价值的贡献者至少先尝试解决问题,然后再提出详细的问题。回答问题的人会利用他们的业余时间而不需要付钱。请通过询问具体问题并展示自己未来的努力来表示尊重。