Skip to content

Commit

Permalink
HV-2020 Use OSGi framework utils to get a classloader
Browse files Browse the repository at this point in the history
and do not rely on a dependency to expressly
  • Loading branch information
marko-bekhta committed Nov 14, 2024
1 parent 00ee634 commit 38a8466
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 9 deletions.
11 changes: 5 additions & 6 deletions engine/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,6 @@
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.glassfish.expressly</groupId>
<artifactId>expressly</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging-annotations</artifactId>
Expand Down Expand Up @@ -125,6 +119,11 @@
<!--
Test dependencies
-->
<dependency>
<groupId>org.glassfish.expressly</groupId>
<artifactId>expressly</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
package org.hibernate.validator.messageinterpolation;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
Expand All @@ -22,8 +24,6 @@
import org.hibernate.validator.spi.messageinterpolation.LocaleResolver;
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;

import com.sun.el.ExpressionFactoryImpl;

/**
* Resource bundle backed message interpolator.
*
Expand Down Expand Up @@ -195,7 +195,10 @@ private static ExpressionFactory buildExpressionFactory() {

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

/*
* In an OSGi environment we won't have access to the classloader that is capable to instantiate the EL factory from the get-go.
* Instead, we have to use the classloader that loaded some class from the EL implementation, e.g. ExpressionFactoryImpl.
* To get that classloader we list all the OSGi bundles through the OSGi BundleContext and go bundle by bundle to find the one
* that is able to load the ExpressionFactoryImpl class.
*
* 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!
*/
private static ClassLoader classLoaderForExpressionFactory(ClassLoader cl) throws Exception {
Class<?> fu = cl.loadClass( "org.osgi.framework.FrameworkUtil" );
Method getBundle = fu.getMethod( "getBundle", Class.class );
Object currentBundle = getBundle.invoke( null, ResourceBundleMessageInterpolator.class );
if ( currentBundle != null ) {
Object context = cl.loadClass( "org.osgi.framework.Bundle" ).getMethod( "getBundleContext" ).invoke( currentBundle );
Object bundles = cl.loadClass( "org.osgi.framework.BundleContext" ).getMethod( "getBundles" ).invoke( context );
Method loadClass = cl.loadClass( "org.osgi.framework.Bundle" ).getMethod( "loadClass", String.class );
int n = Array.getLength( bundles );
for ( int i = 0; i < n; i++ ) {
try {
Object bundle = Array.get( bundles, i );
return ( (Class<?>) loadClass.invoke( bundle, "com.sun.el.ExpressionFactoryImpl" ) ).getClassLoader();
}
catch (Exception e) {
//
}
}
}
return null;
}

/**
* Instead of testing the different class loaders via {@link ELManager}, we directly access the
* {@link ExpressionFactory}. This avoids issues with loading the {@code ELUtil} class (used by {@code ELManager})
Expand Down

0 comments on commit 38a8466

Please sign in to comment.