在 Apache TomEE 8.0.10 上使用 CDI 时,Jax-RS 资源上的 Bean 验证停止工作
我在让 bean 验证与以下仅由这三个 java 文件和 pom.xml 组成的最小化项目一起使用时遇到了麻烦。我正在使用 Apache TomEE 8.0.10。
LoginMessage.java
package org.example;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.validation.constraints.NotBlank;
@Getter
@Setter
@ToString
public class LoginMessage {
@NotBlank
private String username;
@NotBlank
private String password;
}
SessionService.java
package org.example;
import lombok.extern.java.Log;
import javax.enterprise.context.RequestScoped;
@Log
@RequestScoped
public class SessionService {
public void login(final LoginMessage loginMessage) {
log.info(loginMessage.toString());
}
}
SessionController.java
package org.example;
import lombok.extern.java.Log;
import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
@Log
@Path("/session")
public class SessionController {
@Inject
private SessionService sessionService;
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void postLoginMessage(@Valid final LoginMessage loginMessage) {
sessionService.login(loginMessage);
}
}
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<groupId>org.example</groupId>
<artifactId>beanval</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>
</project>
如果你发布一个空的 JSON 对象,它会忽略 SessionController#postLoginMessage() 中的 @Valid
注解,并直接输出包含 toString() 内容的日志消息通过 SessionService#login() 方法登录 LoginMessage 对象。
POST http://localhost:8080/beanval-1.0-SNAPSHOT/session
Content-Type: application/json
{
}
13-Mar-2022 01:30:39.700 INFORMATION [http-nio-8080-exec-6] SessionService.login LoginMessage(username=null, password=null)
如果您从 SessionService 中删除或注释掉 @RequestScoped 注释,并在重新启动 TomEE 后发布空 JSON 对象,则 Bean 验证将正常工作并记录日志:
13-Mar-2022 01:52:51.594 WARNUNG [http-nio-8080-exec-6] org.apache.cxf.jaxrs.validation.ValidationExceptionMapper.toResponse Value (null) of SessionController.postLoginMessage.arg0.password: must not be blank
13-Mar-2022 01:52:51.595 WARNUNG [http-nio-8080-exec-6] org.apache.cxf.jaxrs.validation.ValidationExceptionMapper.toResponse Value (null) of SessionController.postLoginMessage.arg0.username: must not be blank
我想将 CDI 与 Bean-Validation 结合使用JAX-RS 资源。 我做错了什么?
提前致谢。
I'm having troubles getting bean validation to work with the following minimalised project consisting only of this three java files plus pom.xml. I'm using Apache TomEE 8.0.10.
LoginMessage.java
package org.example;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.validation.constraints.NotBlank;
@Getter
@Setter
@ToString
public class LoginMessage {
@NotBlank
private String username;
@NotBlank
private String password;
}
SessionService.java
package org.example;
import lombok.extern.java.Log;
import javax.enterprise.context.RequestScoped;
@Log
@RequestScoped
public class SessionService {
public void login(final LoginMessage loginMessage) {
log.info(loginMessage.toString());
}
}
SessionController.java
package org.example;
import lombok.extern.java.Log;
import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
@Log
@Path("/session")
public class SessionController {
@Inject
private SessionService sessionService;
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void postLoginMessage(@Valid final LoginMessage loginMessage) {
sessionService.login(loginMessage);
}
}
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<groupId>org.example</groupId>
<artifactId>beanval</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>
</project>
If you post an empty JSON object it ignores the @Valid
annotation in SessionController#postLoginMessage() and directly outputs the log message containing the toString() content of the LoginMessage object through SessionService#login() method.
POST http://localhost:8080/beanval-1.0-SNAPSHOT/session
Content-Type: application/json
{
}
13-Mar-2022 01:30:39.700 INFORMATION [http-nio-8080-exec-6] SessionService.login LoginMessage(username=null, password=null)
If you remove or comment out the @RequestScoped
annotation from SessionService and post the empty JSON-Object after restart of TomEE then bean validation works and logs:
13-Mar-2022 01:52:51.594 WARNUNG [http-nio-8080-exec-6] org.apache.cxf.jaxrs.validation.ValidationExceptionMapper.toResponse Value (null) of SessionController.postLoginMessage.arg0.password: must not be blank
13-Mar-2022 01:52:51.595 WARNUNG [http-nio-8080-exec-6] org.apache.cxf.jaxrs.validation.ValidationExceptionMapper.toResponse Value (null) of SessionController.postLoginMessage.arg0.username: must not be blank
I would like to use CDI in combination with Bean-Validation in JAX-RS Resource.
What am I doing wrong?
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这似乎是 OpenWebBeans 或 TomEE 中的错误。因此,首先发生的是 bean 的实际实例由 JAX-RS 管理,其次,bean 由 CDI 容器管理。在第二种情况下,需要有某种拦截器来调用 Bean Validation 框架。
我会在邮件列表上开始讨论,并在 JIRA 中打开一个错误。如果您可以创建一个重现问题的示例项目,它将极大地帮助开发人员解决问题。
作为解决方法,您可以
@Inject private Validator validator
,如果返回任何约束违规,抛出 new ConstraintViolationException(constraintViolations);
。This appears to be a bug in OpenWebBeans or TomEE. So what's happening is the first the actual instance of the bean is managed by JAX-RS, and the second, the bean is managed by the CDI container. In the second case, there needs to be some sort of interceptor the invokes the Bean Validation framework.
I would start a discussion on the mailing list and open a bug on in the JIRA. If you can create a sample project that reproduces the problem it helps the devs out tremendously.
As a workaround, you can
@Inject private Validator validator
and if there are any constraint violations returned,throw new ConstraintViolationException(constraintViolations);
.毕竟,为了找到某种解决方案,我将停止在控制器层使用 bean 验证。它在服务层工作,因此我可以继续开发我的网络应用程序。
解决方案是在 SessionService#login() 方法中使用
@Valid
注释,并将其从 SessionController#postLoginMessage() 方法中删除。如果这确实是 TomEE 中的一个错误,替代方案也可以是使用另一个应用程序服务器,直到它被修复。
After all to come up to some kind of a solution I will stop using bean validation at controller layer. It works at service layer and so I can continue to work on my web app.
The solution is using the
@Valid
annotation in SessionService#login() method and remove it from SessionController#postLoginMessage() method.If it is really a bug in TomEE the alternative could also be to use another application server until it is fixed.