Ivan Ivan - 4 months ago 17
Java Question

El implementation is not found for hibernate-validator in osgi-container

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.

Answer

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.

Comments