/* * Hibernate Validator, declare and validate application constraints * * License: Apache License, Version 2.0 * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>. */ package org.hibernate.validator.osgi.integrationtest; import static org.junit.Assert.assertEquals; import static org.ops4j.pax.exam.CoreOptions.maven; import static org.ops4j.pax.exam.CoreOptions.options; import static org.ops4j.pax.exam.CoreOptions.when; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.debugConfiguration; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.features; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder; import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel; import java.io.File; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Set; import javax.el.ELManager; import javax.el.ExpressionFactory; import javax.money.spi.Bootstrap; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.ValidationProviderResolver; import javax.validation.Validator; import javax.validation.spi.ValidationProvider; import org.hibernate.validator.HibernateValidator; import org.hibernate.validator.HibernateValidatorConfiguration; import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator; import org.javamoney.moneta.Money; import org.javamoney.moneta.spi.MonetaryConfig; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.ops4j.pax.exam.Configuration; import org.ops4j.pax.exam.Option; import org.ops4j.pax.exam.junit.PaxExam; import org.ops4j.pax.exam.karaf.options.LogLevelOption; import org.ops4j.pax.exam.options.MavenUrlReference; import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; import org.ops4j.pax.exam.spi.reactors.PerClass; import com.example.Customer; import com.example.CustomerDecimalMin; import com.example.ExampleConstraintValidatorFactory; import com.example.Order; import com.example.RetailOrder; import com.example.money.ExternalClassLoaderJavaxMoneyServiceProvider; import com.example.money.JavaxMoneyOrder; /** * Integration test for Bean Validation and Hibernate Validator under OSGi. * <p> * Note that the example classes used by this test are located in the {@code com.example} package to avoid that they are * handled as parts of Hibernate Validator during class loading. * * @author Gunnar Morling */ @RunWith(PaxExam.class) @ExamReactorStrategy(PerClass.class) public class OsgiIntegrationTest { private static final boolean DEBUG = false; @Configuration public Option[] config() { MavenUrlReference hibernateValidatorFeature = maven() .groupId( "org.hibernate.validator" ) .artifactId( "hibernate-validator-osgi-karaf-features" ) .classifier( "features" ) .type( "xml" ) .versionAsInProject(); return options( when( DEBUG ).useOptions( debugConfiguration( "5005", true ) ), karafDistributionConfiguration() .frameworkUrl( maven() .groupId( "org.apache.karaf" ) .artifactId( "apache-karaf" ) .type( "tar.gz" ) .versionAsInProject() ) .unpackDirectory( new File( "target/exam" ) ) .useDeployFolder( false ), configureConsole() .ignoreLocalConsole() .ignoreRemoteShell(), when( DEBUG ).useOptions( keepRuntimeFolder() ), logLevel( LogLevelOption.LogLevel.INFO ), // avoiding additional boot features; specifically "enterprise" which already comes with a HV feature // "system" is the absolute minimum, but enough for our purposes editConfigurationFilePut( "etc/org.apache.karaf.features.cfg", "featuresBoot", "system" ), features( hibernateValidatorFeature, "hibernate-validator" ) ); } @BeforeClass public static void setLocaleToEnglish() { Locale.setDefault( Locale.ENGLISH ); } @Test public void canObtainValidatorFactoryAndPerformValidationWithExpressionFactoryFromTccl() { ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); Set<ConstraintViolation<Customer>> constraintViolations = Validation.byDefaultProvider() .providerResolver( new MyValidationProviderResolver() ) .configure() .buildValidatorFactory() .getValidator() .validate( new Customer() ); assertEquals( 1, constraintViolations.size() ); assertEquals( "must be greater than or equal to 2", constraintViolations.iterator().next().getMessage() ); } finally { Thread.currentThread().setContextClassLoader( originalClassLoader ); } } @Test public void canObtainValidatorFactoryAndPerformValidationWithExpressionFactoryFromExternalClassLoader() { Set<ConstraintViolation<Customer>> constraintViolations = Validation.byProvider( HibernateValidator.class ) .configure() .externalClassLoader( getClass().getClassLoader() ) .buildValidatorFactory() .getValidator() .validate( new Customer() ); assertEquals( 1, constraintViolations.size() ); assertEquals( "must be greater than or equal to 2", constraintViolations.iterator().next().getMessage() ); } @Test public void canConfigureCustomConstraintValidatorFactoryViaValidationXml() { ExampleConstraintValidatorFactory.invocationCounter.set( 0 ); HibernateValidatorConfiguration configuration = Validation.byProvider( HibernateValidator.class ) .configure() .externalClassLoader( getClass().getClassLoader() ); String constraintValidatorFactoryClassName = configuration.getBootstrapConfiguration() .getConstraintValidatorFactoryClassName(); assertEquals( "META-INF/validation.xml could not be read", ExampleConstraintValidatorFactory.class.getName(), constraintValidatorFactoryClassName ); configuration.buildValidatorFactory() .getValidator() .validate( new Customer() ); assertEquals( 1, ExampleConstraintValidatorFactory.invocationCounter.get() ); } @Test public void canConfigureConstraintViaXmlMapping() { Set<ConstraintViolation<Customer>> constraintViolations = Validation.byProvider( HibernateValidator.class ) .configure() .externalClassLoader( getClass().getClassLoader() ) .buildValidatorFactory() .getValidator() .validate( new Customer() ); assertEquals( 1, constraintViolations.size() ); assertEquals( "must be greater than or equal to 2", constraintViolations.iterator().next().getMessage() ); } @Test public void canConfigureCustomConstraintViaXmlMapping() { Set<ConstraintViolation<Order>> constraintViolations = Validation.byProvider( HibernateValidator.class ) .configure() .externalClassLoader( getClass().getClassLoader() ) .buildValidatorFactory() .getValidator() .validate( new Order() ); assertEquals( 1, constraintViolations.size() ); assertEquals( "Invalid", constraintViolations.iterator().next().getMessage() ); } @Test public void canObtainValuesFromValidationMessages() { Set<ConstraintViolation<RetailOrder>> constraintViolations = Validation.byProvider( HibernateValidator.class ) .configure() .externalClassLoader( getClass().getClassLoader() ) .buildValidatorFactory() .getValidator() .validate( new RetailOrder() ); assertEquals( 1, constraintViolations.size() ); assertEquals( "Not a valid retail order name", constraintViolations.iterator().next().getMessage() ); } @Test public void canUseExpressionLanguageInConstraintMessageWithExternallyConfiguredExpressionFactory() { ExpressionFactory expressionFactory = buildExpressionFactory(); Set<ConstraintViolation<CustomerDecimalMin>> constraintViolations = Validation.byProvider( HibernateValidator.class ) .configure() .externalClassLoader( getClass().getClassLoader() ) .messageInterpolator( new ResourceBundleMessageInterpolator( new PlatformResourceBundleLocator( ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES ), true, expressionFactory ) ) .buildValidatorFactory() .getValidator() .validate( new CustomerDecimalMin() ); assertEquals( 1, constraintViolations.size() ); assertEquals( "must be greater than or equal to 1.00", constraintViolations.iterator().next().getMessage() ); } @Test public void canUseJavaxMoneyConstraints() { Bootstrap.init( new ExternalClassLoaderJavaxMoneyServiceProvider( MonetaryConfig.class.getClassLoader() ) ); Validator validator = Validation.byProvider( HibernateValidator.class ) .configure() .externalClassLoader( getClass().getClassLoader() ) .buildValidatorFactory() .getValidator(); Set<ConstraintViolation<JavaxMoneyOrder>> constraintViolations = validator.validate( new JavaxMoneyOrder( "Order 1", Money.of( 0, "EUR" ) ) ); assertEquals( 1, constraintViolations.size() ); assertEquals( "must be greater than or equal to 100", constraintViolations.iterator().next().getMessage() ); constraintViolations = validator.validate( new JavaxMoneyOrder( "Order 1", Money.of( 120, "USD" ) ) ); assertEquals( 1, constraintViolations.size() ); assertEquals( "invalid currency (must be one of [EUR])", constraintViolations.iterator().next().getMessage() ); } private ExpressionFactory buildExpressionFactory() { ClassLoader oldTccl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); try { return ELManager.getExpressionFactory(); } finally { Thread.currentThread().setContextClassLoader( oldTccl ); } } public static class MyValidationProviderResolver implements ValidationProviderResolver { @Override public List<ValidationProvider<?>> getValidationProviders() { return Collections.<ValidationProvider<?>>singletonList( new HibernateValidator() ); } } }