如何对Jakarta REST手动实例化的子资源进行约束验证?
解决Jakarta REST子资源的验证失效问题
问题核心在于:你手动实例化的SampleResource不受CDI容器管理,因此Jakarta Bean Validation的注解(如@NotNull)无法被自动触发校验。而根资源SamplesResource是@RequestScoped的容器管理Bean,所以它的方法校验能正常执行。
以下是三种可行的解决方案:
方案一:将子资源改为CDI管理Bean(推荐)
通过让容器负责子资源的实例化和依赖注入,自动触发验证逻辑。
修改子资源代码
将SampleResource标记为CDI作用域,去掉带参数的构造方法,改用@PathParam注入路径参数:
package fr.laboiteadodo.trysub; import jakarta.enterprise.context.RequestScoped; import jakarta.validation.constraints.NotNull; import jakarta.ws.rs.*; /** * 子资源 */ @RequestScoped public class SampleResource { @PathParam("code") private String code; // 保留无参构造方法,供容器实例化 public SampleResource() {} @GET public String getSample() { return code; } @POST public String update(@FormParam("code") @NotNull String code) { this.code = code; return code; } }
修改根资源的子资源方法
让容器负责创建子资源实例,返回子资源的Class类型即可:
@Path("{code}") public Class<SampleResource> getSample() { return SampleResource.class; }
方案二:手动触发验证(适配必须保留带参构造的场景)
如果业务需求要求保留带参数的构造方法,可手动注入Validator并主动校验参数。
修改子资源代码
添加Validator注入逻辑,并在方法内手动校验:
package fr.laboiteadodo.trysub; import jakarta.validation.ConstraintViolation; import jakarta.validation.Validator; import jakarta.validation.constraints.NotNull; import jakarta.ws.rs.*; import java.util.Set; /** * 子资源 */ public class SampleResource { private String code; private Validator validator; public SampleResource(String code) { this.code = code; } // 提供setter供根资源注入Validator public void setValidator(Validator validator) { this.validator = validator; } @GET public String getSample() { return code; } @POST public String update(@FormParam("code") @NotNull String code) { // 手动校验参数 Set<ConstraintViolation<SampleResource>> violations = validator.validateValue(SampleResource.class, "update", code); if (!violations.isEmpty()) { throw new jakarta.validation.ValidationException(violations.iterator().next().getMessage()); } this.code = code; return code; } }
修改根资源代码
注入Validator并传递给子资源实例:
package fr.laboiteadodo.trysub; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import jakarta.validation.Validator; import jakarta.validation.constraints.NotNull; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; /** * 根资源 */ @RequestScoped @Path("samples") public class SamplesResource { @Inject private Validator validator; @Path("{code}") public SampleResource getSample(@PathParam("code") String code) { SampleResource resource = new SampleResource(code); resource.setValidator(validator); return resource; } @POST @Produces(MediaType.TEXT_PLAIN) public String create(@FormParam("code") @NotNull String code) { return code; } }
方案三:使用CDI Producer创建子资源实例
通过Producer方法封装子资源的实例化逻辑,让容器管理实例生命周期并触发验证。
创建Producer类
package fr.laboiteadodo.trysub; import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.inject.Produces; import jakarta.ws.rs.PathParam; @RequestScoped public class SampleResourceProducer { @Produces @RequestScoped public SampleResource produceSampleResource(@PathParam("code") String code) { return new SampleResource(code); } }
修改根资源代码
注入Producer生成的子资源实例:
package fr.laboiteadodo.trysub; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import jakarta.validation.constraints.NotNull; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; /** * 根资源 */ @RequestScoped @Path("samples") public class SamplesResource { @Inject private SampleResource sampleResource; @Path("{code}") public SampleResource getSample() { return sampleResource; } @POST @Produces(MediaType.TEXT_PLAIN) public String create(@FormParam("code") @NotNull String code) { return code; } }
内容的提问来源于stack exchange,提问作者Calcimicium
相关产品推荐
相关产品推荐

