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

Iva*_*van 6 java osgi hibernate hibernate-validator apache-servicemix

我尝试在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;
}
Run Code Online (Sandbox Code Playgroud)

尝试运行,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
Run Code Online (Sandbox Code Playgroud)

如果我传递Group类实例title = null,那么验证就可以了,而constraintViolations包含一个违规"not null".如果我传递Group类实例title = "A"(一个字符对最小长度= 2),那么它会抛出异常

Caused by: javax.el.ELException: Provider com.sun.el.ExpressionFactoryImpl not found
Caused by: java.lang.ClassNotFoundException: com.sun.el.ExpressionFactoryImpl
Run Code Online (Sandbox Code Playgroud)

它是由osgi引起的100%,但我应该如何在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", ...
Run Code Online (Sandbox Code Playgroud)

在hibernate bundle中导入的任何版本,在el-api和el-impl和el-impl导出中的2.2.4导入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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

决定2

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

public class Group {
    @NotNull
    @Size(min=2, message="field.too_short")
    private String title;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下似乎没有启动hibernate插值器,因此ExpressionFactoryImpl不会从TCCL中检索(之前我们读过min = 2的值,现在我们没有).如果对我们没问题,这个决定是最简单的.我将进一步研究这个领域并在那里分享我的观察.

Har*_*ann 1

完整的堆栈跟踪可能比异常消息提供更多的见解。

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

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