Bean Validation 的 Jersey Extension 是否支持 Bean Validation 2.0 (JSR 380)
Does Jersey Extension for Bean Validation supports Bean Validation 2.0 (JSR 380)
我正在使用 WebSphere Liberty 19.0.0.2,其中 webProfile-8.0 功能支持 jaxrs-2.1 和 beanValidation-2.0. 为了更好地支持 MutiPart 流,我使用 Jersey 作为 JAX-RS 实现而不是 liberty 的默认 Apache CXF。
有关相关组件版本控制的更多上下文信息
Bean Validation 1.1 (JSR 349), Bean Validation 2.0 (JSR 380)
我想使用 bean 验证 2.0 功能来验证我的 REST 资源 class 中的 request/response/params,为此我需要使用 Jersey 的扩展来进行 bean 验证. https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/bean-validation.html
如您所见,link(如果您向下滚动)最新版本的扩展 (2.30.1) 也参考了 JSR-349,即 bean 验证 1.1。
来自以下 gradle 依赖项的 jar 的 MENIFEST 也提到了 JSR-349
compile group: 'org.glassfish.jersey.ext', name: 'jersey-bean-validation', version: '2.30'
令人惊讶的是 Bean Validation 2.0 (JSR 380) 没有 Jersey 扩展。
当我自由地使用上述依赖项时,bean 验证有效,但由于我的资源中使用了 bean 验证注释,我在服务器启动时遇到以下错误 class。
[3/5/20 18:11:28:597 EST] 00000020 id=00000000 org.glassfish.jersey.model.Parameter 2 Unable to get the com.sun.proxy.$Proxy70 annotation value property
java.lang.NoSuchMethodException: javax.validation.constraints.NotNull.value()
at java.lang.Class.getMethod(Class.java:1786)
at org.glassfish.jersey.model.Parameter.getValue(Parameter.java:453)
at org.glassfish.jersey.model.Parameter.create(Parameter.java:270)
at org.glassfish.jersey.model.Parameter.createList(Parameter.java:400)
at org.glassfish.jersey.model.Parameter.createList(Parameter.java:383)
at org.glassfish.jersey.server.model.Parameter.create(Parameter.java:137)
at org.glassfish.jersey.server.model.Invocable.<init>(Invocable.java:215)
at org.glassfish.jersey.server.model.Invocable.create(Invocable.java:161)
at org.glassfish.jersey.server.model.ResourceMethod$Builder.createInvocable(ResourceMethod.java:541)
at org.glassfish.jersey.server.model.ResourceMethod$Builder.build(ResourceMethod.java:522)
at org.glassfish.jersey.server.model.Resource$Builder.processMethodBuilders(Resource.java:647)
at org.glassfish.jersey.server.model.Resource$Builder.buildResourceData(Resource.java:583)
at org.glassfish.jersey.server.model.Resource$Builder.build(Resource.java:639)
at org.glassfish.jersey.server.model.Resource.from(Resource.java:782)
at org.glassfish.jersey.server.ResourceBagConfigurator.init(ResourceBagConfigurator.java:55)
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:331)
at org.glassfish.jersey.server.ApplicationHandler.lambda$initialize(ApplicationHandler.java:293)
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.processWithException(Errors.java:232)
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:292)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:259)
at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:311)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:154)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:347)
at javax.servlet.GenericServlet.init(GenericServlet.java:244)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.init(ServletWrapper.java:291)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.loadOnStartupCheck(ServletWrapper.java:1373)
at com.ibm.ws.webcontainer.webapp.WebApp.doLoadOnStartupActions(WebApp.java:1157)
at com.ibm.ws.webcontainer.webapp.WebApp.commonInitializationFinally(WebApp.java:1125)
at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:1023)
at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:6619)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApp(DynamicVirtualHost.java:467)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApplication(DynamicVirtualHost.java:462)
at com.ibm.ws.webcontainer.osgi.WebContainer.startWebApplication(WebContainer.java:1152)
at com.ibm.ws.webcontainer.osgi.WebContainer.access[=11=]0(WebContainer.java:111)
at com.ibm.ws.webcontainer.osgi.WebContainer.run(WebContainer.java:957)
at com.ibm.ws.threading.internal.ExecutorServiceImpl$RunnableWrapper.run(ExecutorServiceImpl.java:239)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
[3/5/20 18:11:28:598 EST] 00000020 id=00000000 org.glassfish.jersey.model.Parameter 2 Unable to get the com.sun.proxy.$Proxy29 annotation value property
java.lang.NoSuchMethodException: javax.validation.Valid.value()
at java.lang.Class.getMethod(Class.java:1786)
at org.glassfish.jersey.model.Parameter.getValue(Parameter.java:453)
at org.glassfish.jersey.model.Parameter.create(Parameter.java:270)
at org.glassfish.jersey.model.Parameter.createList(Parameter.java:400)
at org.glassfish.jersey.model.Parameter.createList(Parameter.java:383)
at org.glassfish.jersey.server.model.Parameter.create(Parameter.java:137)
at org.glassfish.jersey.server.model.Invocable.<init>(Invocable.java:215)
at org.glassfish.jersey.server.model.Invocable.create(Invocable.java:161)
at org.glassfish.jersey.server.model.ResourceMethod$Builder.createInvocable(ResourceMethod.java:541)
at org.glassfish.jersey.server.model.ResourceMethod$Builder.build(ResourceMethod.java:522)
at org.glassfish.jersey.server.model.Resource$Builder.processMethodBuilders(Resource.java:647)
这些错误令人担忧并且没有信心使用它。非常感谢任何建议或帮助。
更新 03/06/2020
以下是来自 server.xml
的功能管理器部分
<featureManager>
<!--NOTE: Following are standard features and should not be removed-->
<feature>servlet-4.0</feature>
<feature>jndi-1.0</feature>
<feature>requestTiming-1.0</feature>
<feature>monitor-1.0</feature>
<feature>localConnector-1.0</feature>
<feature>restConnector-2.0</feature>
<feature>ssl-1.0</feature>
<!-- Do not add enabled webProfile-8.0 because we want to disable default
REST implementation (Apache-CXF) provided by Liberty. We want to use Jersey
as our REST implementation because it better support multi-part streaming, -->
<!-- <feature>webProfile-8.0</feature> -->
<feature>jsp-2.3</feature>
<feature>cdi-2.0</feature>
<feature>managedBeans-1.0</feature>
<feature>jdbc-4.2</feature>
<feature>beanValidation-2.0</feature>
<!-- We need javaMail feature for logback email appender to work -->
<feature>javaMail-1.6</feature>
</featureManager>
这是我扩展 jersey 的 ResourceConfig 的其余应用程序配置 class
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
@ApplicationPath("/rest")
public class RestApplicationConfig extends ResourceConfig {
public RestApplicationConfig() {
super();
configureResourcesAndFeatures();
}
private void configureResourcesAndFeatures() {
packages(RestApplicationConfig.class.getPackage().getName());
register(MultiPartFeature.class);
property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
}
}
我提到了使用 jersey-bean-validation 2.30 版,但我了解到 Jersey 2.27 是最新版本,它是 JAVA JAX-RS 2.1 API 的 EE 实现。从 2.28 开始,其 JAX-RS 2.1 的 Jakarta EE 实现。所以我真的很想使用版本 2.27 并使 bean 验证 2.0 与它一起工作,因为我使用的自由版本还没有达到 jakarta ee。
所有问题的原因是 jersey-bean-validation jar 中打包的不正确的 META-INF 信息以及不正确的 gradle 依赖项。
如果转到 https://mvnrepository.com/artifact/org.glassfish.jersey.ext/jersey-bean-validation/2.27 url 并向下滚动,如果您看到它包含 validation-api 1.1.0.Final 和 hibernate-validator 5.1.3.Final 用于 Bean 验证 1.1 (JSR 349)。
您必须排除上述不正确的传递依赖项,并包括 Bean Validation 2.0 (JSR 380) 的正确版本,即 Hibernate Validator 6.0 (6.0.18.Final)
如果您的容器已经提供了 bean 验证的实现,则不需要包含 hibernate 验证器 jar。在我的例子中,自由启用 beanValidation beanValidation-2.0 它提供了 bean 验证实现。
// Jersey 2.27 is latest version which is JAVA EE implementation of JAX-RS 2.1 API. Starting 2.28 its Jakarta EE implementation of JAX-RS 2.1
compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.27'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.27'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-multipart', version: '2.27'
compile (group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '2.27') {
exclude group: 'javax.inject', module: 'javax.inject'
}
compile (group: 'org.glassfish.jersey.ext', name: 'jersey-bean-validation', version: '2.27') {
exclude group: 'javax.el', module: 'javax.el-api'
exclude group: 'org.hibernate'
}
configurations.compile {
exclude group: 'javax.validation', module: 'validation-api'
exclude group: 'javax.annotation', module: 'javax.annotation-api'
}
在编译配置级别排除了 2 个 jar,因为它们作为传递依赖项来自多个地方。
这解决了所有问题,bean 验证工作得很好。
我正在使用 WebSphere Liberty 19.0.0.2,其中 webProfile-8.0 功能支持 jaxrs-2.1 和 beanValidation-2.0. 为了更好地支持 MutiPart 流,我使用 Jersey 作为 JAX-RS 实现而不是 liberty 的默认 Apache CXF。
有关相关组件版本控制的更多上下文信息
Bean Validation 1.1 (JSR 349), Bean Validation 2.0 (JSR 380)
我想使用 bean 验证 2.0 功能来验证我的 REST 资源 class 中的 request/response/params,为此我需要使用 Jersey 的扩展来进行 bean 验证. https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/bean-validation.html
如您所见,link(如果您向下滚动)最新版本的扩展 (2.30.1) 也参考了 JSR-349,即 bean 验证 1.1。
来自以下 gradle 依赖项的 jar 的 MENIFEST 也提到了 JSR-349
compile group: 'org.glassfish.jersey.ext', name: 'jersey-bean-validation', version: '2.30'
令人惊讶的是 Bean Validation 2.0 (JSR 380) 没有 Jersey 扩展。
当我自由地使用上述依赖项时,bean 验证有效,但由于我的资源中使用了 bean 验证注释,我在服务器启动时遇到以下错误 class。
[3/5/20 18:11:28:597 EST] 00000020 id=00000000 org.glassfish.jersey.model.Parameter 2 Unable to get the com.sun.proxy.$Proxy70 annotation value property
java.lang.NoSuchMethodException: javax.validation.constraints.NotNull.value()
at java.lang.Class.getMethod(Class.java:1786)
at org.glassfish.jersey.model.Parameter.getValue(Parameter.java:453)
at org.glassfish.jersey.model.Parameter.create(Parameter.java:270)
at org.glassfish.jersey.model.Parameter.createList(Parameter.java:400)
at org.glassfish.jersey.model.Parameter.createList(Parameter.java:383)
at org.glassfish.jersey.server.model.Parameter.create(Parameter.java:137)
at org.glassfish.jersey.server.model.Invocable.<init>(Invocable.java:215)
at org.glassfish.jersey.server.model.Invocable.create(Invocable.java:161)
at org.glassfish.jersey.server.model.ResourceMethod$Builder.createInvocable(ResourceMethod.java:541)
at org.glassfish.jersey.server.model.ResourceMethod$Builder.build(ResourceMethod.java:522)
at org.glassfish.jersey.server.model.Resource$Builder.processMethodBuilders(Resource.java:647)
at org.glassfish.jersey.server.model.Resource$Builder.buildResourceData(Resource.java:583)
at org.glassfish.jersey.server.model.Resource$Builder.build(Resource.java:639)
at org.glassfish.jersey.server.model.Resource.from(Resource.java:782)
at org.glassfish.jersey.server.ResourceBagConfigurator.init(ResourceBagConfigurator.java:55)
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:331)
at org.glassfish.jersey.server.ApplicationHandler.lambda$initialize(ApplicationHandler.java:293)
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.processWithException(Errors.java:232)
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:292)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:259)
at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:311)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:154)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:347)
at javax.servlet.GenericServlet.init(GenericServlet.java:244)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.init(ServletWrapper.java:291)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.loadOnStartupCheck(ServletWrapper.java:1373)
at com.ibm.ws.webcontainer.webapp.WebApp.doLoadOnStartupActions(WebApp.java:1157)
at com.ibm.ws.webcontainer.webapp.WebApp.commonInitializationFinally(WebApp.java:1125)
at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:1023)
at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:6619)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApp(DynamicVirtualHost.java:467)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApplication(DynamicVirtualHost.java:462)
at com.ibm.ws.webcontainer.osgi.WebContainer.startWebApplication(WebContainer.java:1152)
at com.ibm.ws.webcontainer.osgi.WebContainer.access[=11=]0(WebContainer.java:111)
at com.ibm.ws.webcontainer.osgi.WebContainer.run(WebContainer.java:957)
at com.ibm.ws.threading.internal.ExecutorServiceImpl$RunnableWrapper.run(ExecutorServiceImpl.java:239)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
[3/5/20 18:11:28:598 EST] 00000020 id=00000000 org.glassfish.jersey.model.Parameter 2 Unable to get the com.sun.proxy.$Proxy29 annotation value property
java.lang.NoSuchMethodException: javax.validation.Valid.value()
at java.lang.Class.getMethod(Class.java:1786)
at org.glassfish.jersey.model.Parameter.getValue(Parameter.java:453)
at org.glassfish.jersey.model.Parameter.create(Parameter.java:270)
at org.glassfish.jersey.model.Parameter.createList(Parameter.java:400)
at org.glassfish.jersey.model.Parameter.createList(Parameter.java:383)
at org.glassfish.jersey.server.model.Parameter.create(Parameter.java:137)
at org.glassfish.jersey.server.model.Invocable.<init>(Invocable.java:215)
at org.glassfish.jersey.server.model.Invocable.create(Invocable.java:161)
at org.glassfish.jersey.server.model.ResourceMethod$Builder.createInvocable(ResourceMethod.java:541)
at org.glassfish.jersey.server.model.ResourceMethod$Builder.build(ResourceMethod.java:522)
at org.glassfish.jersey.server.model.Resource$Builder.processMethodBuilders(Resource.java:647)
这些错误令人担忧并且没有信心使用它。非常感谢任何建议或帮助。
更新 03/06/2020 以下是来自 server.xml
的功能管理器部分<featureManager>
<!--NOTE: Following are standard features and should not be removed-->
<feature>servlet-4.0</feature>
<feature>jndi-1.0</feature>
<feature>requestTiming-1.0</feature>
<feature>monitor-1.0</feature>
<feature>localConnector-1.0</feature>
<feature>restConnector-2.0</feature>
<feature>ssl-1.0</feature>
<!-- Do not add enabled webProfile-8.0 because we want to disable default
REST implementation (Apache-CXF) provided by Liberty. We want to use Jersey
as our REST implementation because it better support multi-part streaming, -->
<!-- <feature>webProfile-8.0</feature> -->
<feature>jsp-2.3</feature>
<feature>cdi-2.0</feature>
<feature>managedBeans-1.0</feature>
<feature>jdbc-4.2</feature>
<feature>beanValidation-2.0</feature>
<!-- We need javaMail feature for logback email appender to work -->
<feature>javaMail-1.6</feature>
</featureManager>
这是我扩展 jersey 的 ResourceConfig 的其余应用程序配置 class
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
@ApplicationPath("/rest")
public class RestApplicationConfig extends ResourceConfig {
public RestApplicationConfig() {
super();
configureResourcesAndFeatures();
}
private void configureResourcesAndFeatures() {
packages(RestApplicationConfig.class.getPackage().getName());
register(MultiPartFeature.class);
property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
}
}
我提到了使用 jersey-bean-validation 2.30 版,但我了解到 Jersey 2.27 是最新版本,它是 JAVA JAX-RS 2.1 API 的 EE 实现。从 2.28 开始,其 JAX-RS 2.1 的 Jakarta EE 实现。所以我真的很想使用版本 2.27 并使 bean 验证 2.0 与它一起工作,因为我使用的自由版本还没有达到 jakarta ee。
所有问题的原因是 jersey-bean-validation jar 中打包的不正确的 META-INF 信息以及不正确的 gradle 依赖项。
如果转到 https://mvnrepository.com/artifact/org.glassfish.jersey.ext/jersey-bean-validation/2.27 url 并向下滚动,如果您看到它包含 validation-api 1.1.0.Final 和 hibernate-validator 5.1.3.Final 用于 Bean 验证 1.1 (JSR 349)。
您必须排除上述不正确的传递依赖项,并包括 Bean Validation 2.0 (JSR 380) 的正确版本,即 Hibernate Validator 6.0 (6.0.18.Final)
如果您的容器已经提供了 bean 验证的实现,则不需要包含 hibernate 验证器 jar。在我的例子中,自由启用 beanValidation beanValidation-2.0 它提供了 bean 验证实现。
// Jersey 2.27 is latest version which is JAVA EE implementation of JAX-RS 2.1 API. Starting 2.28 its Jakarta EE implementation of JAX-RS 2.1
compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.27'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.27'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-multipart', version: '2.27'
compile (group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '2.27') {
exclude group: 'javax.inject', module: 'javax.inject'
}
compile (group: 'org.glassfish.jersey.ext', name: 'jersey-bean-validation', version: '2.27') {
exclude group: 'javax.el', module: 'javax.el-api'
exclude group: 'org.hibernate'
}
configurations.compile {
exclude group: 'javax.validation', module: 'validation-api'
exclude group: 'javax.annotation', module: 'javax.annotation-api'
}
在编译配置级别排除了 2 个 jar,因为它们作为传递依赖项来自多个地方。
这解决了所有问题,bean 验证工作得很好。