HHH-7018 EntityManagerFactory should be serializable even if it references nonserializable objects and also changed the HHH-6897 fix to use a UUID for emf name
This commit is contained in:
parent
edda5ec7f4
commit
608c2fadc8
|
@ -23,6 +23,16 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.ejb;
|
package org.hibernate.ejb;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.persistence.CacheRetrieveMode;
|
import javax.persistence.CacheRetrieveMode;
|
||||||
import javax.persistence.CacheStoreMode;
|
import javax.persistence.CacheStoreMode;
|
||||||
import javax.persistence.EntityExistsException;
|
import javax.persistence.EntityExistsException;
|
||||||
|
@ -53,16 +63,6 @@ import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||||
import javax.transaction.Status;
|
import javax.transaction.Status;
|
||||||
import javax.transaction.SystemException;
|
import javax.transaction.SystemException;
|
||||||
import javax.transaction.TransactionManager;
|
import javax.transaction.TransactionManager;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
|
@ -124,6 +124,7 @@ import org.jboss.logging.Logger;
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public abstract class AbstractEntityManagerImpl implements HibernateEntityManagerImplementor, Serializable {
|
public abstract class AbstractEntityManagerImpl implements HibernateEntityManagerImplementor, Serializable {
|
||||||
|
private static final long serialVersionUID = 78818181L;
|
||||||
|
|
||||||
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
|
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
|
||||||
AbstractEntityManagerImpl.class.getName());
|
AbstractEntityManagerImpl.class.getName());
|
||||||
|
@ -139,7 +140,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
entityManagerSpecificProperties.add( QueryHints.SPEC_HINT_TIMEOUT );
|
entityManagerSpecificProperties.add( QueryHints.SPEC_HINT_TIMEOUT );
|
||||||
}
|
}
|
||||||
|
|
||||||
private transient EntityManagerFactoryImpl entityManagerFactory;
|
private EntityManagerFactoryImpl entityManagerFactory;
|
||||||
protected transient TransactionImpl tx = new TransactionImpl( this );
|
protected transient TransactionImpl tx = new TransactionImpl( this );
|
||||||
protected PersistenceContextType persistenceContextType;
|
protected PersistenceContextType persistenceContextType;
|
||||||
private PersistenceUnitTransactionType transactionType;
|
private PersistenceUnitTransactionType transactionType;
|
||||||
|
@ -1238,12 +1239,10 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
|
|
||||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||||
oos.defaultWriteObject();
|
oos.defaultWriteObject();
|
||||||
entityManagerFactory.serialize(oos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||||
ois.defaultReadObject();
|
ois.defaultReadObject();
|
||||||
entityManagerFactory = (EntityManagerFactoryImpl)EntityManagerFactoryImpl.deserialize(ois);
|
|
||||||
tx = new TransactionImpl( this );
|
tx = new TransactionImpl( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ package org.hibernate.ejb;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InvalidObjectException;
|
import java.io.InvalidObjectException;
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -31,6 +30,7 @@ import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.persistence.Cache;
|
import javax.persistence.Cache;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
@ -49,6 +49,8 @@ import org.hibernate.ejb.internal.EntityManagerFactoryRegistry;
|
||||||
import org.hibernate.ejb.metamodel.MetamodelImpl;
|
import org.hibernate.ejb.metamodel.MetamodelImpl;
|
||||||
import org.hibernate.ejb.util.PersistenceUtilHelper;
|
import org.hibernate.ejb.util.PersistenceUtilHelper;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.id.IdentifierGenerator;
|
||||||
|
import org.hibernate.id.UUIDGenerator;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.metadata.ClassMetadata;
|
import org.hibernate.metadata.ClassMetadata;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
@ -61,17 +63,19 @@ import org.hibernate.service.ServiceRegistry;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
||||||
private final SessionFactory sessionFactory;
|
private static final long serialVersionUID = 5423543L;
|
||||||
private final PersistenceUnitTransactionType transactionType;
|
private static final IdentifierGenerator UUID_GENERATOR = UUIDGenerator.buildSessionFactoryUniqueIdentifierGenerator();
|
||||||
private final boolean discardOnClose;
|
private final transient SessionFactory sessionFactory;
|
||||||
private final Class sessionInterceptorClass;
|
private final transient PersistenceUnitTransactionType transactionType;
|
||||||
private final CriteriaBuilderImpl criteriaBuilder;
|
private final transient boolean discardOnClose;
|
||||||
private final Metamodel metamodel;
|
private final transient Class sessionInterceptorClass;
|
||||||
private final HibernatePersistenceUnitUtil util;
|
private final transient CriteriaBuilderImpl criteriaBuilder;
|
||||||
private final Map<String,Object> properties;
|
private final transient Metamodel metamodel;
|
||||||
|
private final transient HibernatePersistenceUnitUtil util;
|
||||||
|
private final transient Map<String,Object> properties;
|
||||||
private final String entityManagerFactoryName;
|
private final String entityManagerFactoryName;
|
||||||
|
|
||||||
private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
|
private final transient PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
|
||||||
|
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
public EntityManagerFactoryImpl(
|
public EntityManagerFactoryImpl(
|
||||||
|
@ -104,6 +108,9 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
||||||
if (entityManagerFactoryName == null) {
|
if (entityManagerFactoryName == null) {
|
||||||
entityManagerFactoryName = persistenceUnitName;
|
entityManagerFactoryName = persistenceUnitName;
|
||||||
}
|
}
|
||||||
|
if (entityManagerFactoryName == null) {
|
||||||
|
entityManagerFactoryName = (String) UUID_GENERATOR.generate(null, null);
|
||||||
|
}
|
||||||
this.entityManagerFactoryName = entityManagerFactoryName;
|
this.entityManagerFactoryName = entityManagerFactoryName;
|
||||||
EntityManagerFactoryRegistry.INSTANCE.addEntityManagerFactory(entityManagerFactoryName, this);
|
EntityManagerFactoryRegistry.INSTANCE.addEntityManagerFactory(entityManagerFactoryName, this);
|
||||||
}
|
}
|
||||||
|
@ -199,29 +206,7 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static EntityManagerFactory getNamedEntityManagerFactory(String entityManagerFactoryName) throws InvalidObjectException {
|
||||||
* Custom serialization hook used during EntityManager serialization.
|
|
||||||
*
|
|
||||||
* @param oos The stream to which to write the factory
|
|
||||||
* @throws IOException Indicates problems writing out the serial data stream
|
|
||||||
*/
|
|
||||||
void serialize(ObjectOutputStream oos) throws IOException {
|
|
||||||
if (entityManagerFactoryName == null) {
|
|
||||||
throw new InvalidObjectException( "could not serialize entity manager factory with null entityManagerFactoryName" );
|
|
||||||
}
|
|
||||||
oos.writeUTF( entityManagerFactoryName );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom deserialization hook used during EntityManager deserialization.
|
|
||||||
*
|
|
||||||
* @param ois The stream from which to "read" the factory
|
|
||||||
* @return The deserialized factory
|
|
||||||
* @throws IOException indicates problems reading back serial data stream
|
|
||||||
* @throws ClassNotFoundException indicates problems reading back serial data stream
|
|
||||||
*/
|
|
||||||
static EntityManagerFactory deserialize(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
|
||||||
final String entityManagerFactoryName = ois.readUTF();
|
|
||||||
Object result = EntityManagerFactoryRegistry.INSTANCE.getNamedEntityManagerFactory(entityManagerFactoryName);
|
Object result = EntityManagerFactoryRegistry.INSTANCE.getNamedEntityManagerFactory(entityManagerFactoryName);
|
||||||
|
|
||||||
if ( result == null ) {
|
if ( result == null ) {
|
||||||
|
@ -231,6 +216,25 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
||||||
return (EntityManagerFactory)result;
|
return (EntityManagerFactory)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||||
|
if (entityManagerFactoryName == null) {
|
||||||
|
throw new InvalidObjectException( "could not serialize entity manager factory with null entityManagerFactoryName" );
|
||||||
|
}
|
||||||
|
oos.defaultWriteObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After deserialization of an EntityManagerFactory, this is invoked to return the EntityManagerFactory instance
|
||||||
|
* that is already in use rather than a cloned copy of the object.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @throws InvalidObjectException
|
||||||
|
*/
|
||||||
|
private Object readResolve() throws InvalidObjectException {
|
||||||
|
return getNamedEntityManagerFactory(entityManagerFactoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static class HibernatePersistenceUnitUtil implements PersistenceUnitUtil, Serializable {
|
private static class HibernatePersistenceUnitUtil implements PersistenceUnitUtil, Serializable {
|
||||||
private final HibernateEntityManagerFactory emf;
|
private final HibernateEntityManagerFactory emf;
|
||||||
|
|
|
@ -71,15 +71,16 @@ public class EntityManagerFactoryRegistry {
|
||||||
entityManagerFactorySet.add(entityManagerFactory);
|
entityManagerFactorySet.add(entityManagerFactory);
|
||||||
Set<EntityManagerFactory> previous = entityManagerFactoryMap.putIfAbsent( name, entityManagerFactorySet);
|
Set<EntityManagerFactory> previous = entityManagerFactoryMap.putIfAbsent( name, entityManagerFactorySet);
|
||||||
|
|
||||||
// if multiple entries are found, give warning and add EMF to existing set
|
// if already added under 'name'. Where 'name' could be session factory name, pu name or uuid (previous
|
||||||
// later, if EntityManagerFactoryImpl.deserialize is called for an EM returned from any EMF in the set
|
// will be null). We will give a warning that an EntityManagerFactory is created with the same name
|
||||||
// an exception will be thrown (failing the deserialization attempt).
|
// as is already used for a different EMF. The best way to avoid the warning is to specify the AvailableSettings.SESSION_FACTORY_NAME
|
||||||
|
// with a unique name.
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
LOG.entityManagerFactoryAlreadyRegistered(name, AvailableSettings.ENTITY_MANAGER_FACTORY_NAME);
|
LOG.entityManagerFactoryAlreadyRegistered(name, AvailableSettings.ENTITY_MANAGER_FACTORY_NAME);
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
while( !done) {
|
while( !done) {
|
||||||
synchronized (previous) {
|
synchronized (previous) {
|
||||||
if (entityManagerFactoryMap.get(name) == previous) { // compare and add EMF if same
|
if (entityManagerFactoryMap.get(name) == previous) { // compare and set EMF if same
|
||||||
previous.add(entityManagerFactory);
|
previous.add(entityManagerFactory);
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,8 +109,7 @@ public abstract class BaseEntityManagerFunctionalTestCase extends BaseUnitTestCa
|
||||||
}
|
}
|
||||||
ejb3Configuration
|
ejb3Configuration
|
||||||
.getHibernateConfiguration()
|
.getHibernateConfiguration()
|
||||||
.setProperty( org.hibernate.cfg.AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true")
|
.setProperty( org.hibernate.cfg.AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true");
|
||||||
.setProperty( AvailableSettings.ENTITY_MANAGER_FACTORY_NAME, "EMF_BaseEntityManagerFunctionalTestCase");
|
|
||||||
|
|
||||||
ejb3Configuration
|
ejb3Configuration
|
||||||
.getHibernateConfiguration()
|
.getHibernateConfiguration()
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.ejb.test.ejb3configuration;
|
package org.hibernate.ejb.test.ejb3configuration;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
|
@ -104,6 +106,27 @@ public class EntityManagerFactorySerializationTest extends BaseEntityManagerFunc
|
||||||
em.close();
|
em.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEntityManagerFactorySerialization() throws Exception {
|
||||||
|
EntityManagerFactory entityManagerFactory = entityManagerFactory();
|
||||||
|
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
ObjectOutput out = new ObjectOutputStream( stream );
|
||||||
|
out.writeObject( entityManagerFactory );
|
||||||
|
out.close();
|
||||||
|
byte[] serialized = stream.toByteArray();
|
||||||
|
stream.close();
|
||||||
|
ByteArrayInputStream byteIn = new ByteArrayInputStream( serialized );
|
||||||
|
ObjectInputStream in = new ObjectInputStream( byteIn );
|
||||||
|
EntityManagerFactory entityManagerFactory2 = (EntityManagerFactory) in.readObject();
|
||||||
|
in.close();
|
||||||
|
byteIn.close();
|
||||||
|
|
||||||
|
assertTrue("deserialized EntityManagerFactory should be the same original EntityManagerFactory instance",
|
||||||
|
entityManagerFactory2 == entityManagerFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class[] getAnnotatedClasses() {
|
public Class[] getAnnotatedClasses() {
|
||||||
return new Class[]{
|
return new Class[]{
|
||||||
|
|
Loading…
Reference in New Issue