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;
|
||||
|
||||
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.CacheStoreMode;
|
||||
import javax.persistence.EntityExistsException;
|
||||
|
@ -53,16 +63,6 @@ import javax.persistence.spi.PersistenceUnitTransactionType;
|
|||
import javax.transaction.Status;
|
||||
import javax.transaction.SystemException;
|
||||
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.CacheMode;
|
||||
|
@ -124,6 +124,7 @@ import org.jboss.logging.Logger;
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class AbstractEntityManagerImpl implements HibernateEntityManagerImplementor, Serializable {
|
||||
private static final long serialVersionUID = 78818181L;
|
||||
|
||||
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
|
||||
AbstractEntityManagerImpl.class.getName());
|
||||
|
@ -139,7 +140,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
entityManagerSpecificProperties.add( QueryHints.SPEC_HINT_TIMEOUT );
|
||||
}
|
||||
|
||||
private transient EntityManagerFactoryImpl entityManagerFactory;
|
||||
private EntityManagerFactoryImpl entityManagerFactory;
|
||||
protected transient TransactionImpl tx = new TransactionImpl( this );
|
||||
protected PersistenceContextType persistenceContextType;
|
||||
private PersistenceUnitTransactionType transactionType;
|
||||
|
@ -1238,12 +1239,10 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
|
||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||
oos.defaultWriteObject();
|
||||
entityManagerFactory.serialize(oos);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
ois.defaultReadObject();
|
||||
entityManagerFactory = (EntityManagerFactoryImpl)EntityManagerFactoryImpl.deserialize(ois);
|
||||
tx = new TransactionImpl( this );
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ package org.hibernate.ejb;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
|
@ -31,6 +30,7 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.persistence.Cache;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
@ -49,6 +49,8 @@ import org.hibernate.ejb.internal.EntityManagerFactoryRegistry;
|
|||
import org.hibernate.ejb.metamodel.MetamodelImpl;
|
||||
import org.hibernate.ejb.util.PersistenceUtilHelper;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.UUIDGenerator;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.metadata.ClassMetadata;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
@ -61,17 +63,19 @@ import org.hibernate.service.ServiceRegistry;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
||||
private final SessionFactory sessionFactory;
|
||||
private final PersistenceUnitTransactionType transactionType;
|
||||
private final boolean discardOnClose;
|
||||
private final Class sessionInterceptorClass;
|
||||
private final CriteriaBuilderImpl criteriaBuilder;
|
||||
private final Metamodel metamodel;
|
||||
private final HibernatePersistenceUnitUtil util;
|
||||
private final Map<String,Object> properties;
|
||||
private static final long serialVersionUID = 5423543L;
|
||||
private static final IdentifierGenerator UUID_GENERATOR = UUIDGenerator.buildSessionFactoryUniqueIdentifierGenerator();
|
||||
private final transient SessionFactory sessionFactory;
|
||||
private final transient PersistenceUnitTransactionType transactionType;
|
||||
private final transient boolean discardOnClose;
|
||||
private final transient Class sessionInterceptorClass;
|
||||
private final transient CriteriaBuilderImpl criteriaBuilder;
|
||||
private final transient Metamodel metamodel;
|
||||
private final transient HibernatePersistenceUnitUtil util;
|
||||
private final transient Map<String,Object> properties;
|
||||
private final String entityManagerFactoryName;
|
||||
|
||||
private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
|
||||
private final transient PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public EntityManagerFactoryImpl(
|
||||
|
@ -104,6 +108,9 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
if (entityManagerFactoryName == null) {
|
||||
entityManagerFactoryName = persistenceUnitName;
|
||||
}
|
||||
if (entityManagerFactoryName == null) {
|
||||
entityManagerFactoryName = (String) UUID_GENERATOR.generate(null, null);
|
||||
}
|
||||
this.entityManagerFactoryName = entityManagerFactoryName;
|
||||
EntityManagerFactoryRegistry.INSTANCE.addEntityManagerFactory(entityManagerFactoryName, this);
|
||||
}
|
||||
|
@ -199,29 +206,7 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
private static EntityManagerFactory getNamedEntityManagerFactory(String entityManagerFactoryName) throws InvalidObjectException {
|
||||
Object result = EntityManagerFactoryRegistry.INSTANCE.getNamedEntityManagerFactory(entityManagerFactoryName);
|
||||
|
||||
if ( result == null ) {
|
||||
|
@ -231,6 +216,25 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
|
|||
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 final HibernateEntityManagerFactory emf;
|
||||
|
|
|
@ -71,15 +71,16 @@ public class EntityManagerFactoryRegistry {
|
|||
entityManagerFactorySet.add(entityManagerFactory);
|
||||
Set<EntityManagerFactory> previous = entityManagerFactoryMap.putIfAbsent( name, entityManagerFactorySet);
|
||||
|
||||
// if multiple entries are found, give warning and add EMF to existing set
|
||||
// later, if EntityManagerFactoryImpl.deserialize is called for an EM returned from any EMF in the set
|
||||
// an exception will be thrown (failing the deserialization attempt).
|
||||
// if already added under 'name'. Where 'name' could be session factory name, pu name or uuid (previous
|
||||
// will be null). We will give a warning that an EntityManagerFactory is created with the same name
|
||||
// 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) {
|
||||
LOG.entityManagerFactoryAlreadyRegistered(name, AvailableSettings.ENTITY_MANAGER_FACTORY_NAME);
|
||||
boolean done = false;
|
||||
while( !done) {
|
||||
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);
|
||||
done = true;
|
||||
}
|
||||
|
|
|
@ -109,8 +109,7 @@ public abstract class BaseEntityManagerFunctionalTestCase extends BaseUnitTestCa
|
|||
}
|
||||
ejb3Configuration
|
||||
.getHibernateConfiguration()
|
||||
.setProperty( org.hibernate.cfg.AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true")
|
||||
.setProperty( AvailableSettings.ENTITY_MANAGER_FACTORY_NAME, "EMF_BaseEntityManagerFunctionalTestCase");
|
||||
.setProperty( org.hibernate.cfg.AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true");
|
||||
|
||||
ejb3Configuration
|
||||
.getHibernateConfiguration()
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
*/
|
||||
package org.hibernate.ejb.test.ejb3configuration;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
|
@ -104,6 +106,27 @@ public class EntityManagerFactorySerializationTest extends BaseEntityManagerFunc
|
|||
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
|
||||
public Class[] getAnnotatedClasses() {
|
||||
return new Class[]{
|
||||
|
|
Loading…
Reference in New Issue