Jersey @Valid注解注入ConstraintValidatorFactory时遇空指针异常
Jersey @Valid注解校验JSON请求体时触发NullPointerException问题解决
问题场景
开发Java Jersey应用时,使用@Valid注解校验JSON请求体,持续收到500内部服务器错误,触发NullPointerException。
环境配置
JSON请求体示例
{"firstName": "f"}
Jersey应用配置(JerseyConfig.java)
package com.api.customer; import com.api.customer.Exception.ExceptionHandler; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ServerProperties; import javax.ws.rs.ApplicationPath; @ApplicationPath("/api/v1.0") public class JerseyConfig extends ResourceConfig { public JerseyConfig() { packages("com.api.customer"); register(ExceptionHandler.class); property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true); } }
控制器(CustomerController.java)
package com.api.customer.Http.Controller; import com.api.customer.Entity.Welcome; import com.api.customer.Http.Request.UserRequest; import com.api.customer.Http.Responses.WelcomeResponse; import com.api.customer.Services.CustomerService; import javax.inject.Inject; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.validation.Valid; @Path("/customer") public class CustomerController { private final WelcomeResponse welcomeResponse; private final CustomerService customerService; @Inject public CustomerController( WelcomeResponse welcomeResponse, CustomerService customerService ) { this.welcomeResponse = welcomeResponse; this.customerService = customerService; } @POST @Produces("application/json") @Consumes(MediaType.APPLICATION_JSON) public Welcome create(@Valid UserRequest userRequest) { String firstName = userRequest.getFirstName(); this.customerService.createCustomer(); return welcomeResponse.getWelcomeResponse(); } }
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> <groupId>com.api.customer</groupId> <artifactId>CustomerApi</artifactId> <version>1.0-SNAPSHOT</version> <name>CustomerApi</name> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> <junit.version>5.9.2</junit.version> <jersey.version>2.34</jersey.version> <junit.version>5.9.2</junit.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet-core</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-jackson</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.inject</groupId> <artifactId>jersey-hk2</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>org.jboss.weld.se</groupId> <artifactId>weld-se-core</artifactId> <version>3.1.9.Final</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.42.0.1</version> </dependency> <dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-bean-validation</artifactId> <version>${jersey.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> </plugin> </plugins> </build> </project>
错误堆栈信息
SEVERE [http-nio-8084-exec-3] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [com.api.customer.JerseyConfig] in context with path [] threw exception [java.lang.NullPointerException] with root cause java.lang.NullPointerException at org.glassfish.jersey.server.validation.internal.InjectingConstraintValidatorFactory.getInstance(InjectingConstraintValidatorFactory.java:37) at org.hibernate.validator.internal.engine.constraintvalidation.ClassBasedValidatorDescriptor.newInstance(ClassBasedValidatorDescriptor.java:75) at org.hibernate.validator.internal.engine.constraintvalidation.AbstractConstraintValidatorManagerImpl.createAndInitializeValidator(AbstractConstraintValidatorManagerImpl.java:89) at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManagerImpl.getInitializedValidator(ConstraintValidatorManagerImpl.java:117) at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getInitializedConstraintValidator(ConstraintTree.java:152) at org.hibernate.validator.internal.engine.constraintvalidation.SimpleConstraintTree.validateConstraints(SimpleConstraintTree.java:54) at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:75) at org.hibernate.validator.internal.metadata.core.MetaConstraint.doValidateConstraint(MetaConstraint.java:130) at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:123) at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:555) at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidatorImpl.java:518) at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:488) at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:450) at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:400) at org.hibernate.validator.internal.engine.ValidatorImpl.validateCascadedAnnotatedObjectForCurrentGroup(ValidatorImpl.java:629) at org.hibernate.validator.internal.engine.ValidatorImpl.validateCascadedConstraints(ValidatorImpl.java:590) at org.hibernate.validator.internal.engine.ValidatorImpl.validateParametersInContext(ValidatorImpl.java:880) at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:283) at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:235) at org.glassfish.jersey.server.validation.internal.DefaultConfiguredValidator.onValidate(DefaultConfiguredValidator.java:154) at org.glassfish.jersey.server.validation.internal.ValidationInterceptorExecutor.proceed(ValidationInterceptorExecutor.java:90) at org.glassfish.jersey.server.validation.internal.DefaultConfiguredValidator.validateResourceAndInputParams(DefaultConfiguredValidator.java:122) at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:114) at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:219) at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:79) at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:475) at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:397) at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:81) at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:255) at org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) at org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) at org.glassfish.jersey.internal.Errors.process(Errors.java:292) at org.glassfish.jersey.internal.Errors.process(Errors.java:274) at org.glassfish.jersey.internal.Errors.process(Errors.java:244) at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:265) at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:234) at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:680) at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:394) at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:346) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:366) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:319) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:205)
已尝试的排查步骤
- 验证JSON请求体格式与控制器参数绑定配置
- 检查Jersey应用类路径扫描与异常处理器注册
- 排查pom.xml中的依赖版本冲突
原因分析
从堆栈跟踪看,NullPointerException发生在InjectingConstraintValidatorFactory.getInstance()方法中,该类依赖HK2的ServiceLocator来实例化约束校验器。问题根源是同时引入了HK2(Jersey默认DI容器)和Weld SE(CDI实现),两者的DI机制冲突,导致Jersey的Bean Validation组件无法正确获取ServiceLocator实例,进而触发空指针。
解决方案
方案1:移除Weld SE依赖(推荐)
Jersey 2.x默认使用HK2作为依赖注入容器,无需额外引入Weld SE。直接从pom.xml中删除以下依赖:
<dependency> <groupId>org.jboss.weld.se</groupId> <artifactId>weld-se-core</artifactId> <version>3.1.9.Final</version> </dependency>
删除后重新执行mvn clean package,部署更新后的WAR包到Tomcat即可。
方案2:配置Jersey使用Weld作为DI提供者(不推荐,复杂度高)
如果业务必须使用Weld,需要添加Jersey的Weld集成依赖,并修改Jersey配置类注册Weld组件,但该配置在Tomcat环境中需要额外处理,步骤繁琐,仅在必要时考虑。
补充验证
确保jersey-bean-validation依赖版本与Jersey主版本(2.34)一致,该依赖已正确引入,无需额外调整。
内容的提问来源于stack exchange,提问作者Narayan Ghimire
相关产品推荐
相关产品推荐

