Skip to content

Commit e7e96fc

Browse files
committed
HV-2020 Use OSGi framework utils to get a classloader
and do not rely on a dependency to expressly
1 parent 1793bef commit e7e96fc

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed

engine/pom.xml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,6 @@
7474
<scope>provided</scope>
7575
<optional>true</optional>
7676
</dependency>
77-
<dependency>
78-
<groupId>org.glassfish.expressly</groupId>
79-
<artifactId>expressly</artifactId>
80-
<scope>provided</scope>
81-
<optional>true</optional>
82-
</dependency>
8377
<dependency>
8478
<groupId>org.jboss.logging</groupId>
8579
<artifactId>jboss-logging-annotations</artifactId>
@@ -125,6 +119,11 @@
125119
<!--
126120
Test dependencies
127121
-->
122+
<dependency>
123+
<groupId>org.glassfish.expressly</groupId>
124+
<artifactId>expressly</artifactId>
125+
<scope>test</scope>
126+
</dependency>
128127
<dependency>
129128
<groupId>org.testng</groupId>
130129
<artifactId>testng</artifactId>

engine/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package org.hibernate.validator.messageinterpolation;
66

77
import java.lang.invoke.MethodHandles;
8+
import java.lang.reflect.Array;
9+
import java.lang.reflect.Method;
810
import java.util.Collections;
911
import java.util.Locale;
1012
import java.util.Set;
@@ -22,8 +24,6 @@
2224
import org.hibernate.validator.spi.messageinterpolation.LocaleResolver;
2325
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;
2426

25-
import com.sun.el.ExpressionFactoryImpl;
26-
2727
/**
2828
* Resource bundle backed message interpolator.
2929
*
@@ -195,7 +195,10 @@ private static ExpressionFactory buildExpressionFactory() {
195195

196196
// Finally we try the CL of the EL implementation itself. This is necessary for OSGi now that the
197197
// implementation is separated from the API.
198-
SetContextClassLoader.action( ExpressionFactoryImpl.class.getClassLoader() );
198+
// Instead of running this:
199+
// SetContextClassLoader.action( ExpressionFactoryImpl.class.getClassLoader() );
200+
// we do some reflection "magic" to not have a dependency on an implementation of the expression language:
201+
SetContextClassLoader.action( classLoaderForExpressionFactory( originalContextClassLoader ) );
199202
if ( canLoadExpressionFactory() ) {
200203
ExpressionFactory expressionFactory = ELManager.getExpressionFactory();
201204
LOG.debug( "Loaded expression factory via com.sun.el classloader" );
@@ -213,6 +216,36 @@ private static ExpressionFactory buildExpressionFactory() {
213216
throw LOG.getUnableToInitializeELExpressionFactoryException( null );
214217
}
215218

219+
/*
220+
* In an OSGi environment we won't have access to the classloader that is capable to instantiate the EL factory from the get-go.
221+
* Instead, we have to use the classloader that loaded some class from the EL implementation, e.g. ExpressionFactoryImpl.
222+
* To get that classloader we list all the OSGi bundles through the OSGi BundleContext and go bundle by bundle to find the one
223+
* that is able to load the ExpressionFactoryImpl class.
224+
*
225+
* We rely on reflection here as we do not have a dependency on OSGi in the engine module, and we do not want to add it!
226+
*/
227+
private static ClassLoader classLoaderForExpressionFactory(ClassLoader cl) throws Exception {
228+
Class<?> fu = cl.loadClass( "org.osgi.framework.FrameworkUtil" );
229+
Method getBundle = fu.getMethod( "getBundle", Class.class );
230+
Object currentBundle = getBundle.invoke( null, ResourceBundleMessageInterpolator.class );
231+
if ( currentBundle != null ) {
232+
Object context = cl.loadClass( "org.osgi.framework.Bundle" ).getMethod( "getBundleContext" ).invoke( currentBundle );
233+
Object bundles = cl.loadClass( "org.osgi.framework.BundleContext" ).getMethod( "getBundles" ).invoke( context );
234+
Method loadClass = cl.loadClass( "org.osgi.framework.Bundle" ).getMethod( "loadClass", String.class );
235+
int n = Array.getLength( bundles );
236+
for ( int i = 0; i < n; i++ ) {
237+
try {
238+
Object bundle = Array.get( bundles, i );
239+
return ( (Class<?>) loadClass.invoke( bundle, "com.sun.el.ExpressionFactoryImpl" ) ).getClassLoader();
240+
}
241+
catch (Exception e) {
242+
//
243+
}
244+
}
245+
}
246+
return null;
247+
}
248+
216249
/**
217250
* Instead of testing the different class loaders via {@link ELManager}, we directly access the
218251
* {@link ExpressionFactory}. This avoids issues with loading the {@code ELUtil} class (used by {@code ELManager})

0 commit comments

Comments
 (0)