在 osgi-container 中找不到 hibernate-validator 的 El 实现

Posted

技术标签:

【中文标题】在 osgi-container 中找不到 hibernate-validator 的 El 实现【英文标题】:El implementation is not found for hibernate-validator in osgi-container 【发布时间】:2015-06-23 01:26:24 【问题描述】:

我尝试在 osgi 容器中运行 Hibernate 验证器。

<dependency>
    <groupId>javax.el</groupId>
    <artifactId>javax.el-api</artifactId>
    <version>2.2.4</version>
</dependency>
<dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>javax.el</artifactId>
    <version>2.2.4</version>
</dependency>

<dependency>
    <groupId>org.apache.servicemix.bundles</groupId>
    <artifactId>org.apache.servicemix.bundles.hibernate-validator</artifactId>
    <version>5.0.2.Final_1</version>
</dependency>

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.7</version>
</dependency>

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.8.1</version>
</dependency>


public class HibernateValidationProviderResolver implements ValidationProviderResolver 
    @Override
    public List<ValidationProvider<?>> getValidationProviders() 
        List<ValidationProvider<?>> list = new ArrayList<>(1);
        list.add(new HibernateValidator());
        return list;
    



Configuration<?> configuration = Validation.byDefaultProvider().providerResolver(
    new HibernateValidationProviderResolver()
).configure();

ValidatorFactory validatorFactory = configuration.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Set<ConstraintViolation<Group>> constraintViolations = validator.validate(group);


public class Group 
    @NotNull
    @Size(min=2)
    private String title;

尝试运行,Equinox控制台就可以了:

10      RESOLVED    org.glassfish.web.javax.el_2.2.4
39      RESOLVED    org.apache.servicemix.bundles.hibernate-validator_5.0.2.Final_1
47      RESOLVED    javax.validation.api_1.1.0.Final
49      RESOLVED    javax.el-api_2.2.4

如果我通过 title = null 传递 Group 类实例,则验证没问题,且 constraintViolations 包含一个违规“非空”。 如果我使用 title = "A" 传递 Group 类实例(一个字符与最小长度 = 2),那么它会引发异常

Caused by: javax.el.ELException: Provider com.sun.el.ExpressionFactoryImpl not found
Caused by: java.lang.ClassNotFoundException: com.sun.el.ExpressionFactoryImpl

它 100% 是由 osgi 引起的,但是我应该如何在 osgi 中设置 hibernate-validator?我能找到的所有文章都描述了 HibernateValidationProviderResolver 的创建,仅此而已。

更新 1

Maven: javax.el:javax.el-api:2.2.4

Export-Package: javax.el;version="2.2.4"
Import-Package: javax.el;version="2.2.4"

Maven: org.glassfish.web:javax.el:2.2.4 MANIFEST.MF

Export-Package: com.sun.el;uses:="javax.el";version="2.2.4"
Private-Package: com.sun.el.lang;version="2.2.4",com.sun.el.parser;version="2.2.4",com.sun.el.util;version="2.2.4"
Import-Package: com.sun.el;version="2.2.4",javax.el;version="2.2"

Maven: org.apache.servicemix.bundles:org.apache.servicemix.bundles.hibernate-validator:5.0.2.Final_1

Implementation-Version: 5.0.2.Final
Import-Package: javax.el,javax.persistence;resolution:=optional, ...

Export-Package: org.hibernate.validator.internal.engine.messageinterpola
tion.el;uses:="javax.el,javax.validation,org.hibernate.validator.intern
al.engine.messageinterpolation";version="5.0.2.Final",org.hibernate.val
idator.internal.engine.messageinterpolation;uses:="javax.validation.met
adata,org.hibernate.validator.internal.engine.messageinterpolation.el,j
avax.el,javax.validation,org.hibernate.validator.internal.util.logging"
;version="5.0.2.Final", ...

在 el-api 和 el-impl 和 el-impl 的导出中用于在 hibernate bundle 中导入的任何版本,2.2.4 和 el-impl 将 el-api 导入为 2.2,而不是 2.2.4。所有捆绑包都已解析。

更新 2

决定 1

我对@hwellmann 想法的实现。 @hwellmann,对吗?

public void createGroup(Group group) 
    ClassLoader prevClassLoader = Thread.currentThread().getContextClassLoader();

    try 
        ClassLoader[] classLoaders = new ClassLoader[] 
            prevClassLoader,
            ExpressionFactoryImpl.class.getClassLoader()
        ;

        // build composite classloader

        Thread.currentThread().setContextClassLoader(compositeClassLoader);

        Set<ConstraintViolation<Group>> constraintViolations = validator.validate(group);

     finally 
        Thread.currentThread().setContextClassLoader(prevClassLoader);
    

它有效,但看起来很奇怪。并且在每个验证处理上更改 TCCL 看起来有些开销。

决定 2

当我将自己的消息属性添加到每个验证注释时,错误已经消失,例如对于组:

public class Group 
    @NotNull
    @Size(min=2, message="field.too_short")
    private String title;

在这种情况下,似乎没有启动休眠插值器,因此没有从 TCCL 检索到 ExpressionFactoryImpl(以前我们读取 min=2 值,现在我们不读取)。如果对我们来说没问题,这个决定是最简单的。 我将进一步调查这个领域并在那里分享我的观察结果。

【问题讨论】:

hibernate 验证包的导入/导出包如何?很可能是验证包没有导入正确的包,或者 el-bundle 没有按预期导出这些包。 @AchimNierbeck,感谢您的关注!我已经更新了帖子。现在我将尝试更改 el-api 的版本(el-api 和 el-impl)和实现。可能有帮助... 【参考方案1】:

完整的堆栈跟踪可能会提供比异常消息更深入的信息。

我的猜测是,您看到的是通过 META-INF/service/javax.el.ExpressionFactory 查找服务失败的结果。进行查找的包显然看不到 com.sun.el

将此包导入您的应用程序包并将线程上下文类加载器设置为您的包类加载器可能会有所帮助。

【讨论】:

是的,你是对的,改变 TCCL 解决了这个问题。请看一下我在更新 2 中的实现,这是我第一次在 osgi 中更改 TCCL,它是正确的实现吗?我应该在每次验证时(在控制器验证阶段)都这样做吗?当然,我想,我可以接受你的回答,谢谢!【参考方案2】:

JBoss Fuse 中有一个相关问题: https://access.redhat.com/solutions/1479723

他们建议降级到4.3.1.Final

<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-validator</artifactId>
   <version>4.3.1.Final</version>
</dependency>

【讨论】:

Pawel,看起来很有趣。我没有通过搜索发现这个链接。谢谢你的回答。【参考方案3】:

我在使用 Hibernate 5.2.5 和 Jetty 9.x 时遇到了类似的问题。基本上,Hibernate 似乎没有检查类路径上是否已经存在 EL 实现,而是尝试使用 javax.el-api 而不是 Jetty 9 的 apache-el。升级到 Hibernate 5.2.10 为我解决了这个问题。类路径上不再有冲突的 el-api。

【讨论】:

【参考方案4】:

背景

我使用休眠验证器版本 5.4.3.Final。

从5.3.1.Final开始,它提到ExpressionFactoryImpl是一个硬性要求。

5.3.1.Final 中存在 OSGi 问题,问题是 模块化环境中的 ClassLoader 问题。它已在 5.3.3.Final 中修复。票号是HV-1155

修复

根据以上信息, 无需使用Update 2 -> Decision 1。 我发现您可以简单地将 OP 发布的代码从

Configuration<?> configuration = Validation.byDefaultProvider().providerResolver(
    new HibernateValidationProviderResolver()
).configure();

Configuration<?> configuration = Validation.byProvider(HibernateValidator.class).providerResolver(
    new HibernateValidationProviderResolver()
).externalClassLoader(getClass().getClassLoader()).configure();

11.15. Customizing class-loading 提到了这个技巧。

另外,如果你使用的是上面6.0.0.CR3版本的hibernate验证器,你不需要应用上面的技巧。HV-1426涵盖了它。

【讨论】:

以上是关于在 osgi-container 中找不到 hibernate-validator 的 El 实现的主要内容,如果未能解决你的问题,请参考以下文章

为啥在集合中找不到 Mysql 存储过程参数?

为啥使用注解在 ItemProcessor 中找不到 jobParameters?

在字谜程序中找不到错误

在android中找不到确切的当前位置

在 android 中找不到 FirebaseInitProvider

在运行时配置中找不到env:13