Java Hibernate Validator需要一个或另一个

Ric*_*ard 4 java validation json hibernate

这是我上一个问题的延伸.我实施了Dennis R的答案并且正在使用hibernate-validator.有没有办法要求在json请求中指定一个或另一个字段,但不能同时指定两个字段?从我之前的帖子中,在Request类中,我希望用户传入id或代码,但不能同时传递.

我发现这个资源对我来说可能是正确的解决方案,但我不完全了解那里发生了什么,为什么这样做,坦率地说,看起来完全过于冗长.这是唯一的方法吗?

dam*_*ros 7

正如我之前评论过的,并且从这里开始跟随Nicko的回答,您可以使用以下代码实现您想要的效果:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
public @interface FieldMatch {

    String message() default "something is wrong!";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    /**
     * @return The first field
     */
    String first();

    /**
     * @return The second field
     */
    String second();

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        FieldMatch[] value();
    }

    public static class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object> {

        private String firstFieldName;
        private String secondFieldName;

        @Override
        public void initialize(FieldMatch fieldMatch) {
            firstFieldName = fieldMatch.first();
            secondFieldName = fieldMatch.second();
        }

        public boolean isValid(Object object, ConstraintValidatorContext constraintContext) {
            try {
                final Object firstObj = getProperty(object, firstFieldName);
                final Object secondObj = getProperty(object, secondFieldName);

                if(firstObj == null && secondObj == null || firstObj != null && secondObj != null) {
                    return false;
                }
            } catch (final Exception ignore) {
                // ignore
            }
            return true;
        }

        private Object getProperty(Object value, String fieldName) {
            Field[] fields = value.getClass().getDeclaredFields();
            for (Field field : fields) {
                if (field.getName().equals(fieldName)) {
                    field.setAccessible(true);
                    try {
                        return field.get(value);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

用法:

@FieldMatch.List({
        @FieldMatch(first = "name", second = "people"),
        @FieldMatch(first = "age", second = "abc")
})
public class Foo {

    private String name;
    private List<String> people;
    private int age;
    private Boolean abc; 
}
Run Code Online (Sandbox Code Playgroud)

唯一的区别是你不想检查内容是否相等,只是一个字段为空而另一个字段为空.

编辑:

要通过注释询问ExceptionHandler上的对象,只需将异常包装在自定义的对象周围,然后在抛出对象时传递该对象,即:

public class CustomException extends Exception {

    private String message;
    private Object model;

    public CustomException(String message, Object model) {
        super(message);
        this.model = model;
    }

    public Object getModel() {
        return model;
    }
}
Run Code Online (Sandbox Code Playgroud)

有了这个,你可以简单地得到它:

@ExceptionHandler(CustomException.class)
public ModelAndView handleCustomException(CustomException ex) {
    Object obj = ex.getModel();
    //do whatever you have to
}
Run Code Online (Sandbox Code Playgroud)