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 .InvocationTargetException ;
10
+ import java .lang .reflect .Method ;
8
11
import java .util .Collections ;
9
12
import java .util .Locale ;
10
13
import java .util .Set ;
22
25
import org .hibernate .validator .spi .messageinterpolation .LocaleResolver ;
23
26
import org .hibernate .validator .spi .resourceloading .ResourceBundleLocator ;
24
27
25
- import com .sun .el .ExpressionFactoryImpl ;
26
-
27
28
/**
28
29
* Resource bundle backed message interpolator.
29
30
*
@@ -195,7 +196,10 @@ private static ExpressionFactory buildExpressionFactory() {
195
196
196
197
// Finally we try the CL of the EL implementation itself. This is necessary for OSGi now that the
197
198
// implementation is separated from the API.
198
- SetContextClassLoader .action ( ExpressionFactoryImpl .class .getClassLoader () );
199
+ // Instead of running this:
200
+ // SetContextClassLoader.action( ExpressionFactoryImpl.class.getClassLoader() );
201
+ // we do some reflection "magic" to not have a dependency on an implementation of the expression language:
202
+ SetContextClassLoader .action ( classLoaderForExpressionFactory ( originalContextClassLoader ) );
199
203
if ( canLoadExpressionFactory () ) {
200
204
ExpressionFactory expressionFactory = ELManager .getExpressionFactory ();
201
205
LOG .debug ( "Loaded expression factory via com.sun.el classloader" );
@@ -213,6 +217,41 @@ private static ExpressionFactory buildExpressionFactory() {
213
217
throw LOG .getUnableToInitializeELExpressionFactoryException ( null );
214
218
}
215
219
220
+ /*
221
+ * In an OSGi environment we won't have access to the classloader that is capable to instantiate the EL factory from the get-go.
222
+ * Instead, we have to use the classloader that loaded some class from the EL implementation, e.g. ExpressionFactoryImpl.
223
+ * To get that classloader we list all the OSGi bundles through the OSGi BundleContext and go bundle by bundle to find the one
224
+ * that is able to load the ExpressionFactoryImpl class.
225
+ *
226
+ * 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!
227
+ */
228
+ private static ClassLoader classLoaderForExpressionFactory (ClassLoader cl ) throws Exception {
229
+ try {
230
+ Class <?> fu = cl .loadClass ( "org.osgi.framework.FrameworkUtil" );
231
+ Method getBundle = fu .getMethod ( "getBundle" , Class .class );
232
+ Object currentBundle = getBundle .invoke ( null , ResourceBundleMessageInterpolator .class );
233
+ if ( currentBundle != null ) {
234
+ Object context = cl .loadClass ( "org.osgi.framework.Bundle" ).getMethod ( "getBundleContext" ).invoke ( currentBundle );
235
+ Object bundles = cl .loadClass ( "org.osgi.framework.BundleContext" ).getMethod ( "getBundles" ).invoke ( context );
236
+ Method loadClass = cl .loadClass ( "org.osgi.framework.Bundle" ).getMethod ( "loadClass" , String .class );
237
+ int n = Array .getLength ( bundles );
238
+ for ( int i = 0 ; i < n ; i ++ ) {
239
+ try {
240
+ Object bundle = Array .get ( bundles , i );
241
+ return ( (Class <?>) loadClass .invoke ( bundle , "com.sun.el.ExpressionFactoryImpl" ) ).getClassLoader ();
242
+ }
243
+ catch (Exception e ) {
244
+ //
245
+ }
246
+ }
247
+ }
248
+ }
249
+ catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e ) {
250
+ throw e ;
251
+ }
252
+ return null ;
253
+ }
254
+
216
255
/**
217
256
* Instead of testing the different class loaders via {@link ELManager}, we directly access the
218
257
* {@link ExpressionFactory}. This avoids issues with loading the {@code ELUtil} class (used by {@code ELManager})
0 commit comments