【发布时间】:2023-02-03 08:58:00
【问题描述】:
背景
我有一个数据类
@Data
public class Data {
@lombok.NonNull
private String name;
}
控制器
@MessageMapping("/data")
public void handleData(@Validated Data data) throws Exception {
if (data.getName().compareTo("Alice") == 0) {
logger.info("Alice is here!");
}
}
和一个配置 jackson 以将布尔值转换为整数的 bean(True -> 1,False -> 0)
@Bean
ObjectMapper registerObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule("MyBoolSerializer");
module.addSerializer(Boolean.class, new MyBoolSerializer());
module.addDeserializer(Boolean.class, new MyBoolDeserializer());
module.addSerializer(boolean.class, new MyBoolSerializer());
module.addDeserializer(boolean.class, new MyBoolDeserializer());
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
return mapper;
}
当我在没有设置name参数的情况下向/data发出请求时,Jackson会将其设置为null。但是,我得到以下异常(展开)
org.springframework.messaging.converter.MessageConversionException:
Could not read JSON: Cannot construct instance of `com.example.myapp.entity.Data`
(no Creators, like default constructor, exist):
cannot deserialize from Object value (no delegate- or property-based Creator)
尝试修复
所以然后我将@NoArgsConstructor添加到Data。
@Data
@NoArgsConstructor // <<<<
public class Data {
@lombok.NonNull
private String name;
}
现在请求 /data 将导致 NullPointerException。参数未进行 null 检查,并且运行 if-statement。
我尝试用hibernate-validator的@NotNull注解Data中的name属性,结果是一样的:NPE。
问题
我对 @NonNull 和 @NotNull 注释的看法是它们有助于验证数据,这样我就不需要在控制器中手动验证它们(检查 null、检查范围内等)。但是,它似乎仅在默认构造函数不存在时才有效。这是有道理的,因为在默认构造函数中不执行空检查(没有数据要验证...)。
但是这与我遇到的异常相矛盾。
可能有帮助的信息
我启用了amqp,它有自己的MessageConverter bean,返回一个新的Jackson2JsonMessageConverter实例。
import org.springframework.amqp.support.converter.MessageConverter;
@Bean
MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
有什么想法吗?
顺便说一句,标题可能有点含糊或误导,但我真的不知道问题出在哪里。
--- 编辑 1: pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.7</version>
<relativePath />
<!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo2</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>18</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.4.7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-reactor-netty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
【问题讨论】:
-
lombok
Nonnull与验证NotNull有完全不同的方法/含义。此外,您正在使用@MessageMapping,因此这意味着一个 websocket 连接(如果它是一个控制器)。您需要@Payload和@Validated才能使用 JSR303 注释进行验证。你似乎缺少第一个。而且我强烈建议使用验证而不是龙目岛。 -
@M.Deinum 我刚刚拿走了 lombok
@Nonnull并替换为验证@NotNull。曾经有@Payload但有或没有它,仍然没有执行验证... -
您正在使用哪些注释,您的依赖项是否有
spring-boot-starter-validation?或者只是validation-api(如果是这样替换为启动器)。您还使用了哪个注释以及您使用的是哪个版本的 Spring Boot?请添加您的 pom.xml 或 build.gradle。 -
@M.Deinum 刚刚在问题中添加了
pom.xml。我有spring-boot-starter-validation。
标签: java spring spring-boot