5
5
package org .hibernate .validator .messageinterpolation ;
6
6
7
7
import java .lang .invoke .MethodHandles ;
8
+ import java .lang .reflect .Array ;
9
+ import java .lang .reflect .Method ;
8
10
import java .util .Collections ;
9
11
import java .util .Locale ;
10
12
import java .util .Set ;
22
24
import org .hibernate .validator .spi .messageinterpolation .LocaleResolver ;
23
25
import org .hibernate .validator .spi .resourceloading .ResourceBundleLocator ;
24
26
25
- import com .sun .el .ExpressionFactoryImpl ;
26
-
27
27
/**
28
28
* Resource bundle backed message interpolator.
29
29
*
@@ -195,7 +195,10 @@ private static ExpressionFactory buildExpressionFactory() {
195
195
196
196
// Finally we try the CL of the EL implementation itself. This is necessary for OSGi now that the
197
197
// 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 ) );
199
202
if ( canLoadExpressionFactory () ) {
200
203
ExpressionFactory expressionFactory = ELManager .getExpressionFactory ();
201
204
LOG .debug ( "Loaded expression factory via com.sun.el classloader" );
@@ -213,6 +216,36 @@ private static ExpressionFactory buildExpressionFactory() {
213
216
throw LOG .getUnableToInitializeELExpressionFactoryException ( null );
214
217
}
215
218
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
+
216
249
/**
217
250
* Instead of testing the different class loaders via {@link ELManager}, we directly access the
218
251
* {@link ExpressionFactory}. This avoids issues with loading the {@code ELUtil} class (used by {@code ELManager})
0 commit comments