微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Jersey Bean 验证:无法初始化“jakarta.el.E​​xpressionFactory” 如果不需要删除 apache-el 的另一种选择

如何解决Jersey Bean 验证:无法初始化“jakarta.el.E​​xpressionFactory” 如果不需要删除 apache-el 的另一种选择

我已经使用 Jersey 实现了一个 REST 服务,并且想要使用 Bean Validation。当我为 Jersey 添加 bean 验证 maven 依赖项 (jersey-bean-validation) 时,webapp 由于错误而在启动时中断:

HV000183: Unable to initialize 'jakarta.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath,or use ParameterMessageInterpolator instead

我四处搜索,发现旧的解决方案提到包括缺少依赖项,例如这个问题:

javax.validation.ValidationException: HV000183: Unable to load 'javax.el.ExpressionFactory'

但是在我的情况下依赖项已经过时了。另外,在查看依赖树时:

[INFO] org.example:valtest:war:1.0-SNAPSHOT
[INFO] +- org.glassfish.jersey.containers:jersey-container-servlet:jar:3.0.2:compile
[INFO] |  +- org.glassfish.jersey.containers:jersey-container-servlet-core:jar:3.0.2:compile
[INFO] |  +- org.glassfish.jersey.core:jersey-common:jar:3.0.2:compile
[INFO] |  |  +- jakarta.annotation:jakarta.annotation-api:jar:2.0.0:compile
[INFO] |  |  \- org.glassfish.hk2:osgi-resource-locator:jar:1.0.3:compile
[INFO] |  +- org.glassfish.jersey.core:jersey-server:jar:3.0.2:compile
[INFO] |  |  \- org.glassfish.jersey.core:jersey-client:jar:3.0.2:compile
[INFO] |  \- jakarta.ws.rs:jakarta.ws.rs-api:jar:3.0.0:compile
[INFO] +- org.glassfish.jersey.inject:jersey-hk2:jar:3.0.2:compile
[INFO] |  +- org.glassfish.hk2:hk2-locator:jar:3.0.1:compile
[INFO] |  |  +- org.glassfish.hk2.external:aopalliance-repackaged:jar:3.0.1:compile
[INFO] |  |  +- org.glassfish.hk2:hk2-api:jar:3.0.1:compile
[INFO] |  |  \- org.glassfish.hk2:hk2-utils:jar:3.0.1:compile
[INFO] |  \- org.javassist:javassist:jar:3.25.0-GA:compile
[INFO] \- org.glassfish.jersey.ext:jersey-bean-validation:jar:3.0.2:compile
[INFO]    +- jakarta.inject:jakarta.inject-api:jar:2.0.0:compile
[INFO]    +- jakarta.validation:jakarta.validation-api:jar:3.0.0:compile
[INFO]    +- org.hibernate.validator:hibernate-validator:jar:7.0.0.Final:compile
[INFO]    |  +- org.jboss.logging:jboss-logging:jar:3.4.1.Final:compile
[INFO]    |  \- com.fasterxml:classmate:jar:1.5.1:compile
[INFO]    +- jakarta.el:jakarta.el-api:jar:4.0.0:compile
[INFO]    \- org.glassfish:jakarta.el:jar:4.0.0:compile

我可以在最底部看到 el-api 和 el 库已经作为 jersey-bean-validation 库的传递依赖项包含在内。

我在 ResourceBundleMessageInterpolator 中放置了一个断点来找出原因,当 ExpressionFactory 被实例化时,会抛出一个异常:

java.util.ServiceConfigurationError: jakarta.el.ExpressionFactory: org.apache.el.ExpressionFactoryImpl not a subtype

我不知道这是从哪里来的。我至少可以使用以下方法创建一个 ExpressionFactory:

ExpressionFactory.newInstance()

我创建了一个非常简单的示例项目,它使用与我在项目中使用的相同的 Jersey+Jetty 设置:https://www.dropbox.com/s/dcvief9dlqk648m/valtest.zip?dl=0 它可以使用 mvn jetty:run 运行,并且应该在 http://localhost:8080/test 上显示一条消息。

我错过了什么?

解决方法

tl;博士;

Jetty Maven 插件引入了相互冲突的依赖项。依赖处理 JSP。如果您的应用程序中不需要 JSP,我认为以下解决方案应该是安全的。你只需要排除坏的依赖

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>11.0.2</version>
    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>apache-jsp</artifactId>
            <version>11.0.2</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mortbay.jasper</groupId>
                    <artifactId>apache-el</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</plugin>

所以如何找到 ExpressionFactory 是通过 ServiceLoaderorg.glassfish:jakarta.el jar 没有通过 META-INF/services 找到所需的 ServiceLoader 文件。但是在 ServiceLoader 失败后,将尝试其他选项。所以最终,罐子的ExpressionFactoryImpl 被找到。但问题是 Jetty Maven 插件也引入了一个实现,确实META-INF/services 文件。这就是将要使用的实现。

经过一些调试,并进入the ServiceLoader code,发现类时遇到了这个错误:

"jakarta.el.ExpressionFactory: org.apache.el.ExpressionFactoryImpl not a subtype"

于是我新建了一个Maven项目,并添加了jetty-maven-plugin作为依赖。在搜索了所有 jar 之后,我找到了 o.a.e.ExpressionFactoryImpl 类。它是在 Jetty 引入的 apache-el jar 中。奇怪的是,该类实际上实现了 jakarta.el.ExpressionFactory。我认为问题可能在于它实现了旧的 javax 类,但事实并非如此。我不完全确定为什么这会导致错误。但是在解决这个问题之后,它开始起作用了。

如果不需要删除 apache-el 的另一种选择

在获得上述解决方案之前,我尝试过的一件事是尝试将 META-INF/services 文件手动添加到 org.glassfish:jakarta.el jar。我所做的是以下

cd ~/.m2/repository/org/glassfish/jakarta.el/4.0.0
mkdir -p META-INF/services
echo com.sun.el.ExpressionFactoryImpl > META-INF/services/jakarta.el.ExpressionFactory
jar uf jakarta.el-4.0.0.jar META-INF/services/jakarta.el.ExpressionFactory

# You may want to make a copy of the original dependency before you do this
# so you can easily revert back to the original if needed.

这也可能不是一个理想的解决方案,但它奏效了。

如果您需要 apache-el,您也可以尝试将其替换为 org.glassfish:jakarta.el,看看是否有效。我还没有尝试过,但我不确定 Jetty 是否会在不同的实现中遇到类似的问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。