HHH-9665 Changing the EntityManagerFactoryImpl#unwrap method

- Introducing HibernateEntityManagerFactory to host public EntityManagerFactory extension points
- Letting EntityManagerFactoryImpl#getEntityTypeByName return EntityType instead of EntityTypeImpl
- Updating tests to use unwrap to HibernateEntityManagerFactory instead of a cast to EntityManagerFactoryImpl
This commit is contained in:
Hardy Ferentschik 2015-03-18 12:50:58 +01:00 committed by Steve Ebersole
parent 329e85b0b0
commit a2c3c74251
13 changed files with 214 additions and 48 deletions

View File

@ -24,10 +24,12 @@
package org.hibernate.jpa;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManagerFactory;
import javax.persistence.metamodel.EntityType;
import org.hibernate.SessionFactory;
import org.hibernate.jpa.internal.metamodel.EntityTypeImpl;
import org.hibernate.engine.spi.SessionFactoryImplementor;
/**
* Contract giving access to the underlying {@link org.hibernate.SessionFactory} from an {@link javax.persistence.EntityManagerFactory}
@ -40,15 +42,32 @@ public interface HibernateEntityManagerFactory extends EntityManagerFactory, Ser
*
* @return The underlying Hibernate SessionFactory
*/
public SessionFactory getSessionFactory();
SessionFactoryImplementor getSessionFactory();
/**
* Retrieve the EntityTypeImpl by name. Use of the Hibernate O/RM notion the "entity name" allows support
* for non-strictly-JPA models to be used in JPA APIs
* Find all {@code EntityGraph}s associated with a given entity type.
*
* @param entityName The entity name
* @param entityClass the entity type for which to find all {@code EntityGraph}s.
*
* @return The EntityTypeImpl
* @return A list of {@code EntityGraph} instances associated with the given entity type. The empty list is
* returned in case there are not entity graphs.
*/
public EntityTypeImpl getEntityTypeByName(String entityName);
<T> List<EntityGraph<? super T>> findEntityGraphsByType(Class<T> entityClass);
/**
* Returns the name of the factory. The name is either can be specified via the property <i>hibernate.ejb.entitymanager_factory_name</i>.
* If the property is not set the persistence unit name is used. If persistence unit name is not available, a unique
* name will be generated.
*
* @return the name of the factory.
*/
String getEntityManagerFactoryName();
/**
* Find an entity type by name
*
* @param entityName entity name
* @return the {@code EntityType} for the specified name
*/
EntityType getEntityTypeByName(String entityName);
}

View File

@ -35,7 +35,7 @@ import javax.persistence.metamodel.Attribute;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.GraphNodeImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.spi.HibernateEntityManagerFactoryAware;
import org.jboss.logging.Logger;
@ -47,12 +47,12 @@ import org.jboss.logging.Logger;
public abstract class AbstractGraphNode<T> implements GraphNodeImplementor, HibernateEntityManagerFactoryAware {
private static final Logger log = Logger.getLogger( AbstractGraphNode.class );
private final HibernateEntityManagerFactory entityManagerFactory;
private final EntityManagerFactoryImpl entityManagerFactory;
private final boolean mutable;
private Map<String, AttributeNodeImplementor<?>> attributeNodeMap;
protected AbstractGraphNode(HibernateEntityManagerFactory entityManagerFactory, boolean mutable) {
protected AbstractGraphNode(EntityManagerFactoryImpl entityManagerFactory, boolean mutable) {
this.entityManagerFactory = entityManagerFactory;
this.mutable = mutable;
}
@ -80,7 +80,7 @@ public abstract class AbstractGraphNode<T> implements GraphNodeImplementor, Hibe
}
@Override
public HibernateEntityManagerFactory getFactory() {
public EntityManagerFactoryImpl getFactory() {
return entityManagerFactory;
}

View File

@ -36,6 +36,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.internal.metamodel.Helper;
import org.hibernate.jpa.internal.metamodel.PluralAttributeImpl;
import org.hibernate.jpa.spi.HibernateEntityManagerFactoryAware;
@ -51,13 +52,13 @@ import org.hibernate.type.Type;
* @author Steve Ebersole
*/
public class AttributeNodeImpl<T> implements AttributeNode<T>, AttributeNodeImplementor<T>, HibernateEntityManagerFactoryAware {
private final HibernateEntityManagerFactory entityManagerFactory;
private final EntityManagerFactoryImpl entityManagerFactory;
private final Attribute<?,T> attribute;
private Map<Class, Subgraph> subgraphMap;
private Map<Class, Subgraph> keySubgraphMap;
public <X> AttributeNodeImpl(HibernateEntityManagerFactory entityManagerFactory, Attribute<X,T> attribute) {
public <X> AttributeNodeImpl(EntityManagerFactoryImpl entityManagerFactory, Attribute<X,T> attribute) {
this.entityManagerFactory = entityManagerFactory;
this.attribute = attribute;
}
@ -66,7 +67,7 @@ public class AttributeNodeImpl<T> implements AttributeNode<T>, AttributeNodeImpl
* Intended only for use from {@link #makeImmutableCopy()}
*/
private AttributeNodeImpl(
HibernateEntityManagerFactory entityManagerFactory,
EntityManagerFactoryImpl entityManagerFactory,
Attribute<?,T> attribute,
Map<Class, Subgraph> subgraphMap,
Map<Class, Subgraph> keySubgraphMap) {

View File

@ -33,7 +33,7 @@ import javax.persistence.metamodel.IdentifiableType;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.graph.spi.GraphNodeImplementor;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
/**
* The Hibernate implementation of the JPA EntityGraph contract.
@ -44,7 +44,7 @@ public class EntityGraphImpl<T> extends AbstractGraphNode<T> implements EntityGr
private final String name;
private final EntityType<T> entityType;
public EntityGraphImpl(String name, EntityType<T> entityType, HibernateEntityManagerFactory entityManagerFactory) {
public EntityGraphImpl(String name, EntityType<T> entityType, EntityManagerFactoryImpl entityManagerFactory) {
super( entityManagerFactory, true );
this.name = name;
this.entityType = entityType;

View File

@ -30,7 +30,7 @@ import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.ManagedType;
import org.hibernate.graph.spi.GraphNodeImplementor;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
/**
* @author Steve Ebersole
@ -40,7 +40,7 @@ public class SubgraphImpl<T> extends AbstractGraphNode<T> implements Subgraph<T>
private final Class<T> subclass;
public SubgraphImpl(
HibernateEntityManagerFactory entityManagerFactory,
EntityManagerFactoryImpl entityManagerFactory,
ManagedType managedType,
Class<T> subclass) {
super( entityManagerFactory, true );

View File

@ -66,6 +66,7 @@ import org.hibernate.engine.spi.NamedSQLQueryDefinitionBuilder;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.UUIDGenerator;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jpa.AvailableSettings;
@ -474,17 +475,29 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> cls) {
if ( SessionFactory.class.isAssignableFrom( cls ) ) {
return ( T ) sessionFactory;
public <T> T unwrap(Class<T> type) {
if ( type.isAssignableFrom( SessionFactory.class ) ) {
return type.cast( sessionFactory);
}
if ( SessionFactoryImplementor.class.isAssignableFrom( cls ) ) {
return ( T ) sessionFactory;
if ( type.isAssignableFrom( SessionFactoryImplementor.class ) ) {
return type.cast( sessionFactory );
}
if ( EntityManager.class.isAssignableFrom( cls ) ) {
return ( T ) this;
if ( type.isAssignableFrom( SessionFactoryImpl.class ) ) {
return type.cast( sessionFactory );
}
throw new PersistenceException( "Hibernate cannot unwrap EntityManagerFactory as " + cls.getName() );
if ( type.isAssignableFrom( HibernateEntityManagerFactory.class ) ) {
return type.cast( this );
}
if ( type.isAssignableFrom( EntityManagerFactoryImpl.class ) ) {
return type.cast( this );
}
throw new PersistenceException( "Hibernate cannot unwrap EntityManagerFactory as '" + type.getName() + "'" );
}
@Override
@ -505,6 +518,7 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
return entityGraphs.get( name );
}
@Override
@SuppressWarnings("unchecked")
public <T> List<EntityGraph<? super T>> findEntityGraphsByType(Class<T> entityClass) {
final EntityType<T> entityType = getMetamodel().entity( entityClass );
@ -532,7 +546,7 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
}
@Override
public EntityTypeImpl getEntityTypeByName(String entityName) {
public EntityType getEntityTypeByName(String entityName) {
final EntityTypeImpl entityType = metamodel.getEntityTypeByName( entityName );
if ( entityType == null ) {
throw new IllegalArgumentException( "[" + entityName + "] did not refer to EntityType" );
@ -540,6 +554,7 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
return entityType;
}
@Override
public String getEntityManagerFactoryName() {
return entityManagerFactoryName;
}
@ -616,7 +631,6 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
return getNamedEntityManagerFactory(entityManagerFactoryName);
}
private static class HibernatePersistenceUnitUtil implements PersistenceUnitUtil, Serializable {
private final HibernateEntityManagerFactory emf;
private transient PersistenceUtilHelper.MetadataCache cache;

View File

@ -24,7 +24,6 @@
package org.hibernate.jpa.test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.SharedCacheMode;
import javax.persistence.ValidationMode;
import javax.persistence.spi.PersistenceUnitTransactionType;
@ -41,7 +40,7 @@ import org.jboss.logging.Logger;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.hibernate.jpa.boot.spi.Bootstrap;
@ -68,7 +67,7 @@ public abstract class BaseEntityManagerFunctionalTestCase extends BaseUnitTestCa
private static final Dialect dialect = Dialect.getDialect();
private StandardServiceRegistryImpl serviceRegistry;
private EntityManagerFactoryImpl entityManagerFactory;
private HibernateEntityManagerFactory entityManagerFactory;
private EntityManager em;
private ArrayList<EntityManager> isolatedEms = new ArrayList<EntityManager>();
@ -77,7 +76,7 @@ public abstract class BaseEntityManagerFunctionalTestCase extends BaseUnitTestCa
return dialect;
}
protected EntityManagerFactory entityManagerFactory() {
protected HibernateEntityManagerFactory entityManagerFactory() {
return entityManagerFactory;
}
@ -90,10 +89,10 @@ public abstract class BaseEntityManagerFunctionalTestCase extends BaseUnitTestCa
public void buildEntityManagerFactory() throws Exception {
log.trace( "Building EntityManagerFactory" );
entityManagerFactory = (EntityManagerFactoryImpl) Bootstrap.getEntityManagerFactoryBuilder(
entityManagerFactory = Bootstrap.getEntityManagerFactoryBuilder(
buildPersistenceUnitDescriptor(),
buildSettings()
).build();
).build().unwrap( HibernateEntityManagerFactory.class );
serviceRegistry = (StandardServiceRegistryImpl) entityManagerFactory.getSessionFactory()
.getServiceRegistry()

View File

@ -0,0 +1,135 @@
//$Id$
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, 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;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceException;
import org.junit.Before;
import org.junit.Test;
import org.hibernate.SessionFactory;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.internal.EntityManagerImpl;
import org.hibernate.testing.TestForIssue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
/**
* Test various unwrap scenarios for {@code EntityManagerFactory}.
*/
@TestForIssue(jiraKey = "HHH-9665")
public class EntityManagerFactoryUnwrapTest extends BaseEntityManagerFunctionalTestCase {
private EntityManagerFactory entityManagerFactory;
@Override
public Class[] getAnnotatedClasses() {
return new Class[] { };
}
@Before
public void setUp() {
entityManagerFactory = entityManagerFactory();
}
@Test
public void testEntityManagerCanBeUnwrappedToSessionFactory() {
SessionFactory sessionFactory = entityManagerFactory.unwrap( SessionFactory.class );
assertNotNull( "Unwrapping to API class SessionFactory should be ok", sessionFactory );
}
@Test
public void testEntityManagerCanBeUnwrappedToSessionFactoryImplementor() {
SessionFactoryImplementor sessionFactoryImplementor = entityManagerFactory.unwrap( SessionFactoryImplementor.class );
assertNotNull( "Unwrapping to SPI class SessionFactoryImplementor should be ok", sessionFactoryImplementor );
}
@Test
public void testEntityManagerCanBeUnwrappedToDeprecatedHibernateEntityManagerFactory() {
HibernateEntityManagerFactory hibernateEntityManagerFactory = entityManagerFactory.unwrap(
HibernateEntityManagerFactory.class
);
assertNotNull(
"Unwrapping to SPI class HibernateEntityManagerFactory should be ok",
hibernateEntityManagerFactory
);
}
@Test
public void testEntityManagerCanBeUnwrappedToHibernateEntityManagerFactory() {
org.hibernate.jpa.HibernateEntityManagerFactory hibernateEntityManagerFactory = entityManagerFactory.unwrap( org.hibernate.jpa.HibernateEntityManagerFactory.class );
assertNotNull(
"Unwrapping to SPI class HibernateEntityManagerFactory should be ok",
hibernateEntityManagerFactory
);
}
@Test
public void testEntityManagerCanBeUnwrappedToObject() {
Object object = entityManagerFactory.unwrap( Object.class );
assertNotNull( "Unwrapping to public super type Object should work", object );
}
@Test
public void testEntityManagerCanBeUnwrappedToSessionFactoryImpl() {
SessionFactoryImpl sessionFactory = entityManagerFactory.unwrap( SessionFactoryImpl.class );
assertNotNull(
"Unwrapping to SessionFactoryImpl should be ok",
sessionFactory
);
}
@Test
public void testEntityManagerCanBeUnwrappedToEntityManagerFactoryImpl() {
try {
entityManagerFactory.unwrap( EntityManagerFactoryImpl.class );
fail( "It should not be possible to unwrap to an internal type." );
}
catch ( PersistenceException e ) {
// ignore
}
EntityManagerFactoryImpl entityManager = entityManagerFactory.unwrap( EntityManagerFactoryImpl.class );
assertNotNull(
"Unwrapping to EntityManagerFactoryImpl should be ok",
entityManager
);
}
@Test
public void testEntityManagerCannotBeUnwrappedToUnrelatedType() {
try {
entityManagerFactory.unwrap( EntityManagerImpl.class );
fail( "It should not be possible to unwrap to unrelated type." );
}
catch ( PersistenceException e ) {
// ignore
}
}
}

View File

@ -115,7 +115,7 @@ public class MergeTest extends BaseEntityManagerFunctionalTestCase {
}
private void assertUpdateCount(int count) {
int updates = ( int ) ( (EntityManagerFactoryImpl) entityManagerFactory() ).getSessionFactory()
int updates = ( int ) entityManagerFactory().getSessionFactory()
.getStatistics()
.getEntityUpdateCount();
Assert.assertEquals( count, updates );

View File

@ -55,7 +55,6 @@ import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.junit.After;
@ -114,10 +113,10 @@ public class DateTimeParameterTest extends BaseUnitTestCase {
@Before
public void startUp() {
// create the EMF
entityManagerFactory = (EntityManagerFactoryImpl) Bootstrap.getEntityManagerFactoryBuilder(
entityManagerFactory = Bootstrap.getEntityManagerFactoryBuilder(
buildPersistenceUnitDescriptor(),
buildSettingsMap()
).build();
).build().unwrap( HibernateEntityManagerFactory.class );
// create the procedures
createTestData( entityManagerFactory );

View File

@ -44,7 +44,6 @@ import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.junit.After;
@ -272,10 +271,10 @@ public class JpaTckUsageTest extends BaseUnitTestCase {
@Before
public void startUp() {
// create the EMF
entityManagerFactory = (EntityManagerFactoryImpl) Bootstrap.getEntityManagerFactoryBuilder(
entityManagerFactory = Bootstrap.getEntityManagerFactoryBuilder(
buildPersistenceUnitDescriptor(),
buildSettingsMap()
).build();
).build().unwrap( HibernateEntityManagerFactory.class );
// create the procedures
createTestUser( entityManagerFactory );

View File

@ -42,10 +42,10 @@ import org.hibernate.envers.boot.internal.EnversIntegrator;
import org.hibernate.envers.configuration.EnversSettings;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.test.PersistenceUnitDescriptorAdapter;
import org.hibernate.testing.AfterClassOnce;
@ -66,7 +66,7 @@ public abstract class BaseEnversJPAFunctionalTestCase extends AbstractEnversTest
private EntityManagerFactoryBuilderImpl entityManagerFactoryBuilder;
private StandardServiceRegistryImpl serviceRegistry;
private EntityManagerFactoryImpl entityManagerFactory;
private HibernateEntityManagerFactory entityManagerFactory;
private EntityManager em;
private AuditReader auditReader;
@ -97,7 +97,7 @@ public abstract class BaseEnversJPAFunctionalTestCase extends AbstractEnversTest
buildPersistenceUnitDescriptor(),
buildSettings()
);
entityManagerFactory = (EntityManagerFactoryImpl) entityManagerFactoryBuilder.build();
entityManagerFactory = entityManagerFactoryBuilder.build().unwrap( HibernateEntityManagerFactory.class );
serviceRegistry = (StandardServiceRegistryImpl) entityManagerFactory.getSessionFactory()
.getServiceRegistry()

View File

@ -38,9 +38,9 @@ import org.hibernate.envers.configuration.EnversSettings;
import org.hibernate.envers.boot.internal.EnversIntegrator;
import org.hibernate.envers.test.AbstractEnversTest;
import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.test.PersistenceUnitDescriptorAdapter;
import org.hibernate.testing.AfterClassOnce;
@ -56,7 +56,7 @@ public abstract class AbstractEntityManagerTest extends AbstractEnversTest {
private EntityManagerFactoryBuilderImpl entityManagerFactoryBuilder;
private StandardServiceRegistryImpl serviceRegistry;
private EntityManagerFactoryImpl emf;
private HibernateEntityManagerFactory emf;
private EntityManager entityManager;
private AuditReader auditReader;
private boolean audited;
@ -117,7 +117,7 @@ public abstract class AbstractEntityManagerTest extends AbstractEnversTest {
configurationProperties
);
emf = (EntityManagerFactoryImpl) entityManagerFactoryBuilder.build();
emf = entityManagerFactoryBuilder.build().unwrap( HibernateEntityManagerFactory.class );
serviceRegistry = (StandardServiceRegistryImpl) emf.getSessionFactory()
.getServiceRegistry()