Deploying OmniFaces 3.1 on Tomcat 8 without BV throws java.lang.NoClassDefFoundError: javax/validation/ConstraintViolation

Deploying OmniFaces 3.1 on Tomcat 8 without BV throws java.lang.NoClassDefFoundError: javax/validation/ConstraintViolation

我是第一次尝试安装 OmniFaces 3.1。将依赖项添加到我的 pom 文件后,启动 Tomcat 服务器时会发生 NoClassDefFoundError。我还没有进行任何其他 (web.xml, faces-config.xml) 配置更改;只添加了依赖。

显然,异常的发生是由于在处理 Omnifaces class 注释期间产生的 JSR303 依赖性。然而;在 OmniFaces 展示页面上,我读到:

All OmniFaces versions have an optional dependency on JSR303 Bean Validation which is only required when you start to actually use o:validateBean or JsfLabelMessageInterpolator.

可选作为关键字。

这是堆栈跟踪:

java.lang.NoClassDefFoundError: javax/validation/ConstraintViolation
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.getDeclaredMethods(Class.java:1975)
    at com.sun.faces.util.Util.classHasAnnotations(Util.java:1145)
    at com.sun.faces.application.ApplicationInstanceFactoryMetadataMap.onPut(ApplicationInstanceFactoryMetadataMap.java:76)
    at com.sun.faces.application.ApplicationInstanceFactoryMetadataMap.onPut(ApplicationInstanceFactoryMetadataMap.java:43)
    at com.sun.faces.util.MetadataWrapperMap.put(MetadataWrapperMap.java:99)
    at com.sun.faces.config.processor.AbstractConfigProcessor.loadClass(AbstractConfigProcessor.java:425)
    at com.sun.faces.config.processor.FaceletTaglibConfigProcessor.processHandlerClass(FaceletTaglibConfigProcessor.java:446)
    at com.sun.faces.config.processor.FaceletTaglibConfigProcessor.processTags(FaceletTaglibConfigProcessor.java:393)
    at com.sun.faces.config.processor.FaceletTaglibConfigProcessor.processTagLibrary(FaceletTaglibConfigProcessor.java:327)
    at com.sun.faces.config.processor.FaceletTaglibConfigProcessor.process(FaceletTaglibConfigProcessor.java:271)
    at com.sun.faces.config.ConfigManager.initialize(ConfigManager.java:445)
    at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:237)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4577)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5041)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1427)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1417)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:943)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:839)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1427)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1417)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:943)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:258)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:422)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:770)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:682)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:353)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:493)
Caused by: java.lang.ClassNotFoundException: javax.validation.ConstraintViolation
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1275)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1104)
    ... 44 more

这在 2.x 中有效,但确实如描述的那样从 3.0 开始就崩溃了。

根本问题是,从 JSF 2.3 开始,JSF 2.3 兼容库中的标记处理程序也会在 webapp 启动期间扫描注释。这将隐式加载标记处理程序 class 在 <o:validateBean> 后面,即使它没有在 webapp 的任何地方使用。

我已经按照 issue 467 通过将 bean 验证操作重构到静态上下文中来为 3.2-SNAPSHOT 修复它,这样它就不会在加载标记处理程序 class 时加载。