1616 */
1717package org .apache .camel .component .bean .validator ;
1818
19- import java .util .Collections ;
20- import java .util .Locale ;
21-
22- import jakarta .el .ExpressionFactory ;
2319import jakarta .validation .ConstraintValidatorFactory ;
2420import jakarta .validation .MessageInterpolator ;
2521import jakarta .validation .TraversableResolver ;
3127import org .apache .camel .support .CamelContextHelper ;
3228import org .hibernate .validator .HibernateValidator ;
3329import org .hibernate .validator .HibernateValidatorConfiguration ;
34- import org .hibernate .validator .messageinterpolation .ResourceBundleMessageInterpolator ;
35- import org .hibernate .validator .spi .messageinterpolation .LocaleResolver ;
30+ import org .hibernate .validator .messageinterpolation .ParameterMessageInterpolator ;
3631
3732/**
3833 * OSGi-aware override of the upstream ValidatorFactories.
3934 *
4035 * In OSGi, Hibernate Validator 9.x's {@code ResourceBundleMessageInterpolator}
4136 * tries to discover the Jakarta EL {@code ExpressionFactory} via
4237 * {@code ServiceLoader} / TCCL. This fails in OSGi because no single
43- * bundle classloader can find the Expressly SPI descriptor
44- * ({@code META-INF/services/jakarta.el.ExpressionFactory}) .
38+ * bundle classloader can resolve the Expressly SPI descriptor across
39+ * bundle boundaries .
4540 *
46- * This override directly instantiates the Expressly {@code ExpressionFactory}
47- * (resolved via HV's {@code DynamicImport-Package}) and injects it into a
48- * {@code ResourceBundleMessageInterpolator}, completely bypassing the
49- * ServiceLoader discovery that does not work across OSGi bundles .
41+ * This override uses {@code ParameterMessageInterpolator} as the default
42+ * message interpolator when no custom one is provided, bypassing the EL
43+ * dependency entirely. This is the approach recommended by Hibernate
44+ * Validator for environments where EL is not available .
5045 */
5146public final class ValidatorFactories {
5247
@@ -82,25 +77,14 @@ public static ValidatorFactory buildValidatorFactory(
8277 .configure ()
8378 .externalClassLoader (hvCl );
8479
85- // If no custom MessageInterpolator was provided, create one with
86- // a directly-instantiated ExpressionFactory to bypass the broken
87- // ServiceLoader discovery in OSGi .
80+ // In OSGi, EL-based message interpolation does not work because
81+ // ServiceLoader cannot discover ExpressionFactory across bundles.
82+ // Use ParameterMessageInterpolator as the default fallback .
8883 if (messageInterpolator == null ) {
89- ExpressionFactory ef = createExpressionFactory (hvCl );
90- if (ef != null ) {
91- // Must use the 7-param constructor — the 3-param
92- // (ResourceBundleLocator, boolean, ExpressionFactory)
93- // constructor has a bug in HV 9.1.0 that ignores the
94- // ExpressionFactory parameter and calls buildExpressionFactory().
95- messageInterpolator = new ResourceBundleMessageInterpolator (
96- null , Collections .emptySet (), Locale .getDefault (),
97- createDefaultLocaleResolver (hvCl ), true , false , ef );
98- }
84+ messageInterpolator = new ParameterMessageInterpolator ();
9985 }
86+ hvConfig .messageInterpolator (messageInterpolator );
10087
101- if (messageInterpolator != null ) {
102- hvConfig .messageInterpolator (messageInterpolator );
103- }
10488 if (traversableResolver != null ) {
10589 hvConfig .traversableResolver (traversableResolver );
10690 }
@@ -113,31 +97,4 @@ public static ValidatorFactory buildValidatorFactory(
11397
11498 return hvConfig .buildValidatorFactory ();
11599 }
116-
117- /**
118- * Directly instantiate the Expressly ExpressionFactory via HV's
119- * DynamicImport-Package wiring, bypassing ServiceLoader entirely.
120- */
121- private static ExpressionFactory createExpressionFactory (ClassLoader hvCl ) {
122- try {
123- Class <?> implClass = hvCl .loadClass ("org.glassfish.expressly.ExpressionFactoryImpl" );
124- return (ExpressionFactory ) implClass .getDeclaredConstructor ().newInstance ();
125- } catch (Exception e ) {
126- return null ;
127- }
128- }
129-
130- /**
131- * Create the HV DefaultLocaleResolver via reflection to avoid importing
132- * the internal package which is not exported by the HV bundle.
133- */
134- private static LocaleResolver createDefaultLocaleResolver (ClassLoader hvCl ) {
135- try {
136- Class <?> clazz = hvCl .loadClass (
137- "org.hibernate.validator.internal.engine.messageinterpolation.DefaultLocaleResolver" );
138- return (LocaleResolver ) clazz .getDeclaredConstructor ().newInstance ();
139- } catch (Exception e ) {
140- return null ;
141- }
142- }
143100}
0 commit comments