Having “fun” with JSR-303 Beans Validation and OSGi + Spring DM
Most Java standards are implemented using an api jar and an concrete implementation jar. The API constists maninly of interfaces but a class that looks up the default implementation. This lookup normally happens by trying to load a specific resource bundle which is located in the implementation jar. This can lead to “interesting” classloader problems when used with OSGi and Spring DM specifically
In the case of Beans Validation (using the Hibernate Validator 4.0 reference implementation) we have a javax.validation and org.hibernate.validator artifact. Both jars are no valid OSGi bundles so you have to wrap them to add valid Import-Packages and Export-Packages directives to the appropiate MANIFEST.MF files. To make the configuration file contained in the implementation bundle visible to the api bundle you have to configure the implementation as OSGi Fragment by specifying a *Fragment-Host: javax.validation* in its manifest.
Depending on the classloader used to find the configuration resource it either works or not. Using Spring Dynamic Modules this means that it does not work if you try to aquire a ValidatorFactory while the Spring OSGi extender is loading your Spring application context. It works however when aquired from within the Activator of the using bundle. This is no bug in Spring DM but rather an inherent problem in the default implementation lookup of the Beans Validation API. Spring extender loads the application context of a bundle with the BundleClassLoader set as current thread classloader. This classloader restricts loading of resource bundles to the current bundle.
To solve this problem, create a third bundle and put implement the following class:
public final class ValidatorFactoryBean { /** * Custom provider resolver is needed since the default provider resolver * relies on current thread context loader and doesn't find the default * META-INF/services/.... configuration file * */ private static class HibernateValidationProviderResolver implements ValidationProviderResolver { @Override public List getValidationProviders() { List providers = new ArrayList(1); providers.add(new HibernateValidationProvider()); return providers; } } private final static ValidatorFactory instance; static { ProviderSpecificBootstrap validationBootStrap = Validation.byProvider(HibernateValidatorConfiguration.class); validationBootStrap.providerResolver(new HibernateValidationProviderResolver()); instance = validationBootStrap.configure().buildValidatorFactory(); } public final static ValidatorFactory getInstance() { return instance; } }
Additionally put the following spring config in META-INF/spring/beans.xml:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"> <bean id="validatorFactory" class="de.ivu.combitour.commoninfrastructure.validation.ValidatorFactoryBean" factory-method="getInstance"/> <osgi:service ref="validatorFactory" interface="javax.validation.ValidatorFactory"/> </beans>
Note however that this file should be split in two files if you follow Springsource’s advice. This separated the osgi specific part from the pure spring configuration.
What this snipet does is to provide an OSGi service called “validatorFactory” and to use hibernate validator as default implementation.