Skip to content

Commit

Permalink
HV-1155 Fall back to the HV class loader if no ExpressionFactory impl is
Browse files Browse the repository at this point in the history
found in the TCCL
  • Loading branch information
gsmet committed Nov 21, 2016
1 parent 55c091e commit c3e0700
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 1 deletion.
Expand Up @@ -6,13 +6,17 @@
*/
package org.hibernate.validator.messageinterpolation;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;

import javax.el.ExpressionFactory;

import org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTerm;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.internal.util.privilegedactions.GetClassLoader;
import org.hibernate.validator.internal.util.privilegedactions.SetContextClassLoader;
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;

/**
Expand Down Expand Up @@ -70,13 +74,45 @@ public String interpolate(Context context, Locale locale, String term) {
return expression.interpolate( context );
}

/**
* The javax.el FactoryFinder uses the TCCL to load the {@link ExpressionFactory} implementation so we need to be
* extra careful when initializing it.
*
* @return the {@link ExpressionFactory}
*/
private static ExpressionFactory buildExpressionFactory() {
// First, we try to load the instance from the TCCL.
try {
return ExpressionFactory.newInstance();
}
catch (Throwable e) {
// we ignore the error in this case as we will try the Hibernate Validator class loader.
}

// Then we try the Hibernate Validator class loader. In a fully-functional modular environment such as
// WildFly or Jigsaw, it is the way to go.
final ClassLoader originalContextClassLoader = run( GetClassLoader.fromContext() );

try {
run( SetContextClassLoader.action( ResourceBundleMessageInterpolator.class.getClassLoader() ) );
return ExpressionFactory.newInstance();
}
catch (Throwable e) {
// HV-793 - We fail eagerly in case we have no EL dependencies on the classpath
throw LOG.getUnableToInitializeELExpressionFactoryException( e );
}
finally {
run( SetContextClassLoader.action( originalContextClassLoader ) );
}
}

/**
* Runs the given privileged action, using a privileged block if required.
* <p>
* <b>NOTE:</b> This must never be changed into a publicly available method to avoid execution of arbitrary
* privileged actions within HV's protection domain.
*/
private static <T> T run(PrivilegedAction<T> action) {
return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run();
}
}
Expand Up @@ -108,6 +108,8 @@ public static void setLocaleToEnglish() {

@Test
public void canObtainValidatorFactoryAndPerformValidation() {
Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );

Set<ConstraintViolation<Customer>> constraintViolations = Validation.byDefaultProvider()
.providerResolver( new MyValidationProviderResolver() )
.configure()
Expand All @@ -116,11 +118,13 @@ public void canObtainValidatorFactoryAndPerformValidation() {
.validate( new Customer() );

assertEquals( 1, constraintViolations.size() );
assertEquals( "must be greater than or equal to 1", constraintViolations.iterator().next().getMessage() );
assertEquals( "must be greater than or equal to 2", constraintViolations.iterator().next().getMessage() );
}

@Test
public void canConfigureCustomConstraintValidatorFactoryViaValidationXml() {
Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );

ExampleConstraintValidatorFactory.invocationCounter.set( 0 );

HibernateValidatorConfiguration configuration = Validation.byProvider( HibernateValidator.class )
Expand All @@ -146,6 +150,8 @@ public void canConfigureCustomConstraintValidatorFactoryViaValidationXml() {

@Test
public void canConfigureConstraintViaXmlMapping() {
Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );

Set<ConstraintViolation<Customer>> constraintViolations = Validation.byProvider( HibernateValidator.class )
.providerResolver( new MyValidationProviderResolver() )
.configure()
Expand All @@ -160,6 +166,8 @@ public void canConfigureConstraintViaXmlMapping() {

@Test
public void canConfigureCustomConstraintViaXmlMapping() {
Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );

Set<ConstraintViolation<Order>> constraintViolations = Validation.byProvider( HibernateValidator.class )
.providerResolver( new MyValidationProviderResolver() )
.configure()
Expand All @@ -174,6 +182,8 @@ public void canConfigureCustomConstraintViaXmlMapping() {

@Test
public void canObtainValuesFromValidationMessages() {
Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );

Set<ConstraintViolation<RetailOrder>> constraintViolations = Validation.byProvider( HibernateValidator.class )
.providerResolver( new MyValidationProviderResolver() )
.configure()
Expand Down

0 comments on commit c3e0700

Please sign in to comment.