diff --git a/engine/pom.xml b/engine/pom.xml
index ccd16e6d46..4a6b79ff55 100644
--- a/engine/pom.xml
+++ b/engine/pom.xml
@@ -52,11 +52,6 @@
-
- org.glassfish
- jakarta.el
- provided
-
org.jboss.logging
jboss-logging-processor
@@ -79,6 +74,11 @@
+
+ jakarta.el
+ jakarta.el-api
+ true
+
jakarta.persistence
jakarta.persistence-api
@@ -115,6 +115,11 @@
+
+ org.glassfish
+ jakarta.el
+ test
+
org.testng
testng
diff --git a/engine/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java b/engine/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java
index b7164aa1a8..9bf4cbba49 100644
--- a/engine/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java
+++ b/engine/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java
@@ -7,6 +7,9 @@
package org.hibernate.validator.messageinterpolation;
import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
@@ -24,8 +27,6 @@
import org.hibernate.validator.spi.messageinterpolation.LocaleResolver;
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;
-import com.sun.el.ExpressionFactoryImpl;
-
import jakarta.el.ELManager;
import jakarta.el.ExpressionFactory;
@@ -200,7 +201,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.
- run( SetContextClassLoader.action( ExpressionFactoryImpl.class.getClassLoader() ) );
+ // Instead of running this:
+ // run( SetContextClassLoader.action( ExpressionFactoryImpl.class.getClassLoader() ) );
+ // we do some reflection "magic" to not have a dependency on an implementation of the expression language:
+ run( SetContextClassLoader.action( classLoaderForExpressionFactory( originalContextClassLoader ) ) );
if ( canLoadExpressionFactory() ) {
ExpressionFactory expressionFactory = ELManager.getExpressionFactory();
LOG.debug( "Loaded expression factory via com.sun.el classloader" );
@@ -218,6 +222,33 @@ private static ExpressionFactory buildExpressionFactory() {
throw LOG.getUnableToInitializeELExpressionFactoryException( null );
}
+ private static ClassLoader classLoaderForExpressionFactory(ClassLoader cl) throws Exception {
+ try {
+ 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) {
+ //
+ }
+ }
+ }
+ }
+ catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ throw 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})
diff --git a/pom.xml b/pom.xml
index 01bebc13a4..03df29830e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -390,6 +390,11 @@
jakarta.el
${version.org.glassfish.jakarta.el}
+
+ jakarta.el
+ jakarta.el-api
+ ${version.jakarta.el-api}
+
com.fasterxml
classmate