7

I try to run Hibernate validator in osgi container.

<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;
}

Try to run, equinox console is okay:

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

If I pass Group class instance with title = null, then validation is okay and constraintViolations contains one violation "not null". If I pass Group class instance with title = "A" (one character against minimal length = 2), then it throws an exception

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

It 100% caused by osgi, but how I should setup hibernate-validator in osgi? All articles what I can found describes creating of HibernateValidationProviderResolver and that's all.

UPDATE 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", ...

Any version for import in hibernate bundle, 2.2.4 in export of el-api and el-impl and el-impl imports el-api as 2.2, not a 2.2.4. All bundles are resolved.

Update 2

Decision 1

my implementation of @hwellmann's idea. @hwellmann, is it correct?

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);
    }
}

It works but looks strange. And change TCCL on each validation processing looks as some overhead.

Decision 2

The error has gone when I add my own message attribute to each validation annotation, for example for Group:

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

It seems in this case hibernate interpolator is not started so ExpressionFactoryImpl is not retrieved from TCCL (previously we read min=2 value, now we don't). If it is okay for us, this decision is simplest. I will investigate this area futhermore and share my observations there.

рüффп
  • 4,475
  • 34
  • 62
  • 99
Ivan
  • 465
  • 5
  • 19
  • how's the import/export packages for the hibernate validation bundle? Might very well be that the validation bundle doesn't import the right package, or the el-bundle doesn't export those as expected. – Achim Nierbeck Apr 17 '15 at 07:04
  • @AchimNierbeck, thank you for your attention! I have updated the post. Now I'll try to change versions (el-api and el-impl) and implementations of el-api. May be it helps... – Ivan Apr 17 '15 at 07:48

3 Answers3

4

There is a related issue in JBoss Fuse: https://access.redhat.com/solutions/1479723

They recommend a downgrade to 4.3.1.Final:

<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-validator</artifactId>
   <version>4.3.1.Final</version>
</dependency>
Paweł Prażak
  • 2,819
  • 1
  • 23
  • 39
  • Pawel, it looks interesting. I have not discovered this link by search. Thank you for this answer. – Ivan Aug 03 '16 at 06:24
1

The full stack trace might give some more insight than just the exception messages.

My guess is that you're seeing the results of a failed service lookup via META-INF/service/javax.el.ExpressionFactory. The bundle that's doing the lookup apparently can't see com.sun.el.

Importing this package into your application bundle and setting the thread context classloader to your bundle classloader might help.

Harald Wellmann
  • 11,788
  • 2
  • 36
  • 56
  • yep, you are right, changing of TCCL fix the issue. Please, look at my implementation in Update 2, it is my first time when I change TCCL in osgi, is it correct implementation? Should I do it on each validation (on the controller validation stage)? And of course, I think, I can accept your answer, thank you! – Ivan Apr 21 '15 at 15:21
0

I had a similar issue with Hibernate 5.2.5 and Jetty 9.x. Basically, it looked like Hibernate didn't check if there was already an EL implementation on the classpath and tried to use javax.el-api instead of Jetty 9's apache-el. An upgrade to Hibernate 5.2.10 solved the issue for me. No conflicting el-api on the classpath any more.

user1050755
  • 9,463
  • 3
  • 35
  • 51