HHH-7387 - Integrate Draft 6 of the JPA 2.1 spec : CDI via reflection

This commit is contained in:
Steve Ebersole 2012-08-24 20:32:45 -05:00
parent a9c28bf28f
commit 63a2f0d7dc
4 changed files with 227 additions and 7 deletions

View File

@ -42,6 +42,10 @@ public class BeanManagerListenerFactory implements ListenerFactory {
private final BeanManager beanManager;
private final Map<Class,BeanMetaData> listeners = new ConcurrentHashMap<Class, BeanMetaData>();
public static BeanManagerListenerFactory fromBeanManagerReference(Object beanManagerReference) {
return new BeanManagerListenerFactory( ( BeanManager ) beanManagerReference );
}
public BeanManagerListenerFactory(BeanManager beanManager) {
this.beanManager = beanManager;
}

View File

@ -23,7 +23,8 @@
*/
package org.hibernate.jpa.event.spi;
import javax.enterprise.inject.spi.BeanManager;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
@ -187,10 +188,10 @@ public class JpaIntegrator implements Integrator {
// handle JPA "entity listener classes"...
this.callbackRegistry = new CallbackRegistryImpl();
final BeanManager beanManager = (BeanManager) configuration.getProperties().get( AvailableSettings.CDI_BEAN_MANAGER );
this.jpaListenerFactory = beanManager == null
final Object beanManagerRef = configuration.getProperties().get( AvailableSettings.CDI_BEAN_MANAGER );
this.jpaListenerFactory = beanManagerRef == null
? new StandardListenerFactory()
: new BeanManagerListenerFactory( beanManager );
: buildBeanManagerListenerFactory( beanManagerRef );
this.callbackProcessor = new LegacyCallbackProcessor( jpaListenerFactory, configuration.getReflectionManager() );
Iterator classes = configuration.getClassMappings();
@ -213,6 +214,34 @@ public class JpaIntegrator implements Integrator {
}
}
private ListenerFactory buildBeanManagerListenerFactory(Object beanManagerRef) {
try {
// specifically using our classloader here...
final Class beanManagerListenerFactoryClass = getClass().getClassLoader()
.loadClass( "org.hibernate.jpa.event.internal.jpa.BeanManagerListenerFactory" );
final Method beanManagerListenerFactoryBuilderMethod = beanManagerListenerFactoryClass.getMethod(
"fromBeanManagerReference",
Object.class
);
try {
return (ListenerFactory) beanManagerListenerFactoryBuilderMethod.invoke( null, beanManagerRef );
}
catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
catch (ReflectiveOperationException e) {
throw new HibernateException( "Could not access BeanManagerListenerFactory class to handle CDI extensions", e );
}
catch (RuntimeException e) {
throw e;
}
catch (Throwable e) {
throw new HibernateException( "Problem calling BeanManagerListenerFactory class to handle CDI extensions", e );
}
}
@Override
public void integrate(
MetadataImplementor metadata,
@ -288,10 +317,10 @@ public class JpaIntegrator implements Integrator {
// handle JPA "entity listener classes"...
this.callbackRegistry = new CallbackRegistryImpl();
final BeanManager beanManager = (BeanManager) sessionFactory.getProperties().get( AvailableSettings.CDI_BEAN_MANAGER );
this.jpaListenerFactory = beanManager == null
final Object beanManagerRef = sessionFactory.getProperties().get( AvailableSettings.CDI_BEAN_MANAGER );
this.jpaListenerFactory = beanManagerRef == null
? new StandardListenerFactory()
: new BeanManagerListenerFactory( beanManager );
: buildBeanManagerListenerFactory( beanManagerRef );
this.callbackProcessor = new CallbackProcessorImpl( jpaListenerFactory, metadata, serviceRegistry );
for ( EntityBinding binding : metadata.getEntityBindings() ) {

View File

@ -0,0 +1,138 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.test.cdi;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import org.hibernate.bytecode.spi.ByteCodeHelper;
import org.junit.Rule;
import org.junit.Test;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.hibernate.testing.junit4.ClassLoadingIsolater;
import static org.junit.Assert.fail;
/**
* Test JPA bootstrapping when CDI is not available for classloading.
*
* @author Steve Ebersole
*/
public class NoCdiAvailableTest extends BaseUnitTestCase {
public static final String[] EXCLUDED_PACKAGES = new String[] {
"javax.enterprise.inject.",
"javax.enterprise.context."
};
private static class CdiClassLoadException extends RuntimeException {
private CdiClassLoadException(String message) {
super( message );
}
}
@Rule public ClassLoadingIsolater isolater = new ClassLoadingIsolater(
new ClassLoadingIsolater.IsolatedClassLoaderProvider() {
@Override
public ClassLoader buildIsolatedClassLoader() {
return new ClassLoader(NoCdiAvailableTest.class.getClassLoader()) {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
for ( String excludedPackage : EXCLUDED_PACKAGES ) {
if ( name.startsWith( excludedPackage ) ) {
throw new CdiClassLoadException( "CDI classes [" + name + "] excluded from load" );
}
}
Class c = findLoadedClass( name );
if ( c != null ) {
return c;
}
final String resourceName = name.replace( '.', '/' ) + ".class";
final URL resource = getResource( resourceName );
if ( resource == null ) {
throw new ClassNotFoundException( name + " not found" );
}
if ( !"file".equals( resource.getProtocol() ) ) {
return getParent().loadClass( name );
}
InputStream is = this.getResourceAsStream( name.replace( '.', '/' ) + ".class" );
if ( is == null ) {
throw new ClassNotFoundException( name + " not found" );
}
try {
byte[] bytecode = ByteCodeHelper.readByteCode( is );
return defineClass( name, bytecode, 0, bytecode.length );
}
catch( Throwable t ) {
throw new ClassNotFoundException( "Error reading class file for " + name, t );
}
}
};
}
@Override
public void releaseIsolatedClassLoader(ClassLoader isolatedClassLoader) {
// nothing to do
}
}
);
@Test
public void testJpaBootstrapWithoutCdiAvailable() throws Exception {
Class delegateClass = Thread.currentThread().getContextClassLoader().loadClass(
"org.hibernate.jpa.test.cdi.NoCdiAvailableTestDelegate"
);
Method mainMethod = delegateClass.getMethod( "passingNoBeanManager" );
mainMethod.invoke( null );
}
@Test
public void testJpaBootstrapWithoutCdiAvailablePassingCdi() throws Throwable {
Class delegateClass = Thread.currentThread().getContextClassLoader().loadClass(
"org.hibernate.jpa.test.cdi.NoCdiAvailableTestDelegate"
);
Method mainMethod = delegateClass.getMethod( "passingBeanManager" );
try {
mainMethod.invoke( null );
fail( "Expecting failure from missing CDI classes" );
}
catch (InvocationTargetException e) {
try {
throw e.getTargetException();
}
catch (CdiClassLoadException expected) {
}
// catch (ClassCastException expectedAlt) {
// }
}
}
}

View File

@ -0,0 +1,49 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.test.cdi;
import java.util.Collections;
import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.hibernate.jpa.test.PersistenceUnitInfoAdapter;
/**
* @author Steve Ebersole
*/
public class NoCdiAvailableTestDelegate {
public static void passingNoBeanManager() {
new HibernatePersistenceProvider().createContainerEntityManagerFactory(
new PersistenceUnitInfoAdapter(),
Collections.emptyMap()
);
}
public static void passingBeanManager() {
new HibernatePersistenceProvider().createContainerEntityManagerFactory(
new PersistenceUnitInfoAdapter(),
Collections.singletonMap( AvailableSettings.CDI_BEAN_MANAGER, new Object() )
);
}
}