lombok@NonNull 注解无法对 SpringMVC 封装请求的对象的 Field 进行非空校验

1
If put on a parameter, lombok will insert a null-check at the start of the method / constructor's body, throwing a {@code NullPointerException} with the parameter's name as message. <br> If put on a field, any generated method assigning a value to this field will also produce these null-checks.

可见 @NonNull 注解用于标注Field时,并非是直接校验所标注字段不能为空,而是对赋值该字段的方法加 null 校验。

如该对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data
@AllArgsConstructor
public class ReqIn {
 
    @NonNull
    private Byte name;
 
    private String id;
 
    public ReqIn(){
        System.out.println("无参构造");
    }
 
}

 编译生成 .class 文件如下

  可见,对 setName() 和 @AllArgsConstructor 注解生成的全参数构造器,均对 name 入参做非 null 校验。

  但当 @Controller 内 @RequestMapping 注解的接口,若以 ReqIn 作为封装的请求对象,则接口调用时若没有传 name 字段,则会发现接口接收到的入参里,虽然字段被标注了 @NonNull,但 name 确实为 null。

  原因简单总述为:SpringMVC对参数解析和封装对象时,对于有无参构造器的对象,会使用无参构造器初始化,随后对传入的 Field 进行赋值,对没有传的 Field 则会忽略。因此,虽然带有 name 参数的构造器和 setName()均对 name 做了 null 校验,但实际上根本没有被调用。 

  A)初始化被封装对象

  

 

  详述:

  1、SpringMVC对参数解析和封装对象时

    如果目标对象仅有一个 Constructor,则会调用该 Constructor 封装对象;

    如果对象有多于一个 Constructor,则会取无参构造器来封装对象,本例中无参构造器为手动生成,使用 @NoArgsConstructor 同样效果。

    如果对象没有指定构造器,这种情况在有 @NonNull 注解时不存在,因为 @NonNull 注解会对指定了该注解的 Field 生成 Constructor,参数与被注解字段数量一致。

 

   2、如果被 @NonNull 注解的字段为 String,则注解不会生效。

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data
@AllArgsConstructor
public class ReqIn {
 
    @NonNull
    private String name;
 
    @NonNull
    private String id;
 
    public ReqIn(){
        System.out.println("无参构造");
    }
}<br><br>@RequestMapping("/req")<br>@Controller<br>public class ReqInController {<br><br><br>    @GetMapping("/testAnnotation")<br>    public String testAnnotation(ReqIn reqIn){<br>        System.out.println(reqIn);<br>        return "index";<br>    }<br>}<br>

    2.1、如果请求时,带有 name 字段,则 name 字段会被设置为空字符串

  

1
请求:<br>http://localhost:1234/req/testAnnotation?id=133&name=

  

1
2
输出:<br>无参构造
ReqIn(name=, id=133)

    2.2、如果请求时,不带有 name 字段,则 name 字段会被设置为 null

1
请求:<br>http://localhost:1234/req/testAnnotation?id=133

  

1
2
输出:<br>无参构造
ReqIn(name=null, id=133)

  可见,对于 String 字段,在 SpringMVC 封装对象时,@NonNull 注解无法阻止字段被设置为null。

  原因在于,调用无参构造器之后,由于没有传入 name,封装对象的 parameterTypes 仅有 id,进而没有调用过 setName()方法,@NonNull 注解对 name 字段自然无法约束非 null。

结论

  要使 @NonNull 注解对于指定 Field 生效,则需要

  1、被封装对象没有无参构造器

  2、如果被注解 Field 是 String 类型,则如果该参数为空时,不要作为请求的 key-value 对的 key 传到后端接口。

 

posted @   wanghuanyeah  阅读(686)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!
点击右上角即可分享
微信分享提示