alidator could be found for constraint 'javax.validation.constraints.NotEmpty' validating type 'java.lang.Object'. Check configuration for 'hello.<return value>'
需要强调的是:若标注在方法上是验证返回值的,这个时候方法体是已经执行了的,这个和ConstraintDeclarationException
不一样~
对这两个注解依照官方文档做如下简要说明。@NotEmpty
只能标注在如下类型
- CharSequence
- Collection
- Map
Array
注意:""它是空的,但是" "就不是了
@NotBlank
只能使用在CharSequence
上,它是Bean Validation 2.0新增的注解~
3、接口和实现类上都有注解,以谁为准?
这个问题有个隐含条件:只有校验方法返回值时才有这种可能性。
public interface HelloService {
@NotEmpty String hello(@NotNull @Min(10) Integer id, @NotNull String name);
}
@Slf4j
@Service
@Validated(Default.class)
public class HelloServiceImpl implements HelloService {
@Override
public @NotNull String hello(Integer id, String name) {
return "";
}
}
运行案例,helloService.hello(18, "fsx");
打印如下:
javax.validation.ConstraintViolationException: hello.<return value>: 不能为空
...
到这里,可能有小伙伴就会早早下结论:当同时存在时,以接口的约束为准。
那么,我只把返回值稍稍修改,你再看一下呢???
@Override
public @NotNull String hello(Integer id, String name) {
return null; // 返回值改为null
}
再运行:
javax.validation.ConstraintViolationException: hello.<return value>: 不能为空, hello.<return value>: 不能为null
...
透过打印的信息,结论就自然不必我多。但是有个道理此处可说明:大胆猜测,小心求证
4、如何校验级联属性
?
在实际开发中,其实大多数情况下我们方法入参是个对象(甚至对象里面有对象),而不是单单平铺的参数,因此就介绍一个级联属性校验的例子:
@Getter
@Setter
@ToString
public class Person {
@NotNull
private String name;
@NotNull
@Positive
private Integer age;
@Valid // 让InnerChild的属性也参与校验
@NotNull
private InnerChild child;
@Getter
@Setter
@ToString
public static class InnerChild {
@NotNull
private String name;
@NotNull
@Positive
private Integer age;
}
}
public interface HelloService {
String cascade(@NotNull @Valid Person father, @NotNull Person mother);
}
@Slf4j
@Service
@Validated(Default.class)
public class HelloServiceImpl implements HelloService {
@Override
public String cascade(Person father, Person mother) {
return "hello cascade...";
}
}
运行测试用例:
@Test
public void test1() {
helloService.cascade(null, null);
}
输出如下:
cascade.father: 不能为null, cascade.mother: 不能为null
此处说明一点:若你father
前面没加@NotNull
,那打印的消息只有:cascade.mother: 不能为null
我把测试用例改造如下,你继续感受一把:
@Test
public void test1() {
Person father = new Person();
father.setName("fsx");
Person.InnerChild innerChild = new Person.InnerChild();
innerChild.setAge(-1);
father.setChild(innerChild);
helloService.cascade(father, new Person());
}
错误消息如下(请小伙伴仔细观察和分析缘由):
cascade.father.age: 不能为null, cascade.father.child.name: 不能为null, cascade.father.child.age: 必须是正数
思考:为何mother
的相关属性以及子属性为何全都没有校验呢?
5、循环依赖问题
上面说了Spring对@Validated
的处理和对@Aysnc
的代理逻辑是差不多的,有了之前的经验,很容易想到它也存在着如题的问题:比如HelloService
的A方法想调用本类的B方法,但是很显然我是希望B方法的方法校验是能生效的,因此其中一个做法就是注入自己,使用自己的代理对象来调用:
public interface HelloService {
Object hello(@NotNull @Min(10) Integer id, @NotNull String name);
String cascade(@NotNull @Valid Person father, @NotNull Person mother);
}
@Slf4j
@Service
@Validated(Default.class)
public class HelloServiceImpl implements HelloService {
@Autowired
private HelloService helloService;
@Override
public Object hello(@NotNull @Min(10) Integer id, @NotNull String name) {
helloService.cascade(null, null); // 调用本类方法
return null;
}
@Override
pub