HHH-4841 : Read-only proxies in NonFlushedChanges are not read-only when applied to a new session
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18699 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
53b1890c1b
commit
8606c4a097
|
@ -672,10 +672,19 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
proxy = persister.createProxy( key.getIdentifier(), session );
|
proxy = persister.createProxy( key.getIdentifier(), session );
|
||||||
proxiesByKey.put(key, proxy); //overwrite old proxy
|
Object proxyOrig = proxiesByKey.put(key, proxy); //overwrite old proxy
|
||||||
|
if ( proxyOrig != null ) {
|
||||||
|
if ( ! ( proxyOrig instanceof HibernateProxy ) ) {
|
||||||
|
throw new AssertionFailure(
|
||||||
|
"proxy not of type HibernateProxy; it is " + proxyOrig.getClass()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// set the read-only/modifiable mode in the new proxy to what it was in the original proxy
|
||||||
|
boolean readOnlyOrig = ( ( HibernateProxy ) proxyOrig ).getHibernateLazyInitializer().isReadOnly();
|
||||||
|
( ( HibernateProxy ) proxy ).getHibernateLazyInitializer().setReadOnly( readOnlyOrig );
|
||||||
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
|
|
|
@ -190,13 +190,18 @@ public final class TwoPhaseLoad {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isReallyReadOnly = readOnly || !persister.isMutable();
|
boolean isReallyReadOnly = readOnly;
|
||||||
|
if ( !persister.isMutable() ) {
|
||||||
|
isReallyReadOnly = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
Object proxy = persistenceContext.getProxy( entityEntry.getEntityKey() );
|
Object proxy = persistenceContext.getProxy( entityEntry.getEntityKey() );
|
||||||
if ( proxy != null ) {
|
if ( proxy != null ) {
|
||||||
// there is already a proxy for this impl
|
// there is already a proxy for this impl
|
||||||
// only set the status to read-only if the proxy is read-only
|
// only set the status to read-only if the proxy is read-only
|
||||||
isReallyReadOnly = ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer().isReadOnly();
|
isReallyReadOnly = ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer().isReadOnly();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if ( isReallyReadOnly ) {
|
if ( isReallyReadOnly ) {
|
||||||
//no need to take a snapshot - this is a
|
//no need to take a snapshot - this is a
|
||||||
//performance optimization, but not really
|
//performance optimization, but not really
|
||||||
|
|
|
@ -360,9 +360,6 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
|
||||||
Object proxy = persister.createProxy( event.getEntityId(), event.getSession() );
|
Object proxy = persister.createProxy( event.getEntityId(), event.getSession() );
|
||||||
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey(keyToLoad);
|
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey(keyToLoad);
|
||||||
persistenceContext.addProxy(keyToLoad, proxy);
|
persistenceContext.addProxy(keyToLoad, proxy);
|
||||||
( ( HibernateProxy ) proxy )
|
|
||||||
.getHibernateLazyInitializer()
|
|
||||||
.setReadOnly( event.getSession().isDefaultReadOnly() || ! persister.isMutable() );
|
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,14 @@ package org.hibernate.proxy;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LazyInitializationException;
|
import org.hibernate.LazyInitializationException;
|
||||||
import org.hibernate.TransientObjectException;
|
import org.hibernate.TransientObjectException;
|
||||||
import org.hibernate.SessionException;
|
import org.hibernate.SessionException;
|
||||||
import org.hibernate.engine.EntityKey;
|
import org.hibernate.engine.EntityKey;
|
||||||
import org.hibernate.engine.SessionImplementor;
|
import org.hibernate.engine.SessionImplementor;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience base class for lazy initialization handlers. Centralizes the basic plumbing of doing lazy
|
* Convenience base class for lazy initialization handlers. Centralizes the basic plumbing of doing lazy
|
||||||
|
@ -48,6 +50,7 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
private boolean readOnly;
|
private boolean readOnly;
|
||||||
private boolean unwrap;
|
private boolean unwrap;
|
||||||
private transient SessionImplementor session;
|
private transient SessionImplementor session;
|
||||||
|
private Boolean readOnlyBeforeAttachedToSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For serialization from the non-pojo initializers (HHH-3309)
|
* For serialization from the non-pojo initializers (HHH-3309)
|
||||||
|
@ -65,11 +68,9 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
protected AbstractLazyInitializer(String entityName, Serializable id, SessionImplementor session) {
|
protected AbstractLazyInitializer(String entityName, Serializable id, SessionImplementor session) {
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.readOnly = false;
|
|
||||||
// initialize other fields depending on session state
|
// initialize other fields depending on session state
|
||||||
if ( session == null ) {
|
if ( session == null ) {
|
||||||
// would be better to call unsetSession(), but it is not final...
|
unsetSession();
|
||||||
session = null;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setSession( session );
|
setSession( session );
|
||||||
|
@ -116,18 +117,27 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
*/
|
*/
|
||||||
public final void setSession(SessionImplementor s) throws HibernateException {
|
public final void setSession(SessionImplementor s) throws HibernateException {
|
||||||
if ( s != session ) {
|
if ( s != session ) {
|
||||||
readOnly = false;
|
|
||||||
// check for s == null first, since it is least expensive
|
// check for s == null first, since it is least expensive
|
||||||
if ( s == null ){
|
if ( s == null ){
|
||||||
// would be better to call unsetSession(), but it is not final...
|
unsetSession();
|
||||||
session = null;
|
|
||||||
}
|
}
|
||||||
else if ( isConnectedToSession() ) {
|
else if ( isConnectedToSession() ) {
|
||||||
//TODO: perhaps this should be some other RuntimeException...
|
//TODO: perhaps this should be some other RuntimeException...
|
||||||
throw new HibernateException("illegally attempted to associate a proxy with two open Sessions");
|
throw new HibernateException("illegally attempted to associate a proxy with two open Sessions");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// s != null
|
||||||
session = s;
|
session = s;
|
||||||
|
if ( readOnlyBeforeAttachedToSession == null ) {
|
||||||
|
// use the default read-only/modifiable setting
|
||||||
|
final EntityPersister persister = s.getFactory().getEntityPersister( entityName );
|
||||||
|
setReadOnly( s.getPersistenceContext().isDefaultReadOnly() || ! persister.isMutable() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// use the read-only/modifiable setting indicated during deserialization
|
||||||
|
setReadOnly( readOnlyBeforeAttachedToSession.booleanValue() );
|
||||||
|
readOnlyBeforeAttachedToSession = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,9 +152,10 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public void unsetSession() {
|
public final void unsetSession() {
|
||||||
session = null;
|
session = null;
|
||||||
readOnly = false;
|
readOnly = false;
|
||||||
|
readOnlyBeforeAttachedToSession = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -236,32 +247,8 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public boolean isReadOnly() {
|
public final boolean isReadOnlySettingAvailable() {
|
||||||
errorIfReadOnlySettingNotAvailable();
|
return ( session != null && ! session.isClosed() );
|
||||||
if ( !isConnectedToSession() ) {
|
|
||||||
throw new TransientObjectException(
|
|
||||||
"The read-only/modifiable setting is only accessible when the proxy is associated with a session." );
|
|
||||||
}
|
|
||||||
return readOnly;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public void setReadOnly(boolean readOnly) {
|
|
||||||
errorIfReadOnlySettingNotAvailable();
|
|
||||||
// only update if readOnly is different from current setting
|
|
||||||
if ( this.readOnly != readOnly ) {
|
|
||||||
Object proxy = getProxyOrNull();
|
|
||||||
if ( proxy == null ) {
|
|
||||||
throw new TransientObjectException(
|
|
||||||
"Cannot set the read-only/modifiable mode unless the proxy is associated with a session." );
|
|
||||||
}
|
|
||||||
this.readOnly = readOnly;
|
|
||||||
if ( initialized ) {
|
|
||||||
session.getPersistenceContext().setReadOnly( target, readOnly );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void errorIfReadOnlySettingNotAvailable() {
|
private void errorIfReadOnlySettingNotAvailable() {
|
||||||
|
@ -275,6 +262,77 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public final boolean isReadOnly() {
|
||||||
|
errorIfReadOnlySettingNotAvailable();
|
||||||
|
return readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public final void setReadOnly(boolean readOnly) {
|
||||||
|
errorIfReadOnlySettingNotAvailable();
|
||||||
|
// only update if readOnly is different from current setting
|
||||||
|
if ( this.readOnly != readOnly ) {
|
||||||
|
final EntityPersister persister = session.getFactory().getEntityPersister( entityName );
|
||||||
|
if ( ! persister.isMutable() && ! readOnly ) {
|
||||||
|
throw new IllegalStateException( "cannot make proxies for immutable entities modifiable");
|
||||||
|
}
|
||||||
|
this.readOnly = readOnly;
|
||||||
|
if ( initialized ) {
|
||||||
|
EntityKey key = generateEntityKeyOrNull( getIdentifier(), session, getEntityName() );
|
||||||
|
if ( key != null && session.getPersistenceContext().containsEntity( key ) ) {
|
||||||
|
session.getPersistenceContext().setReadOnly( target, readOnly );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the read-only/modifiable setting that should be put in affect when it is
|
||||||
|
* attached to a session.
|
||||||
|
*
|
||||||
|
* This method should only be called during serialization when read-only/modifiable setting
|
||||||
|
* is not available (i.e., isReadOnlySettingAvailable() == false)
|
||||||
|
*
|
||||||
|
* @returns, null, if the default setting should be used;
|
||||||
|
* true, for read-only;
|
||||||
|
* false, for modifiable
|
||||||
|
* @throws IllegalStateException if isReadOnlySettingAvailable() == true
|
||||||
|
*/
|
||||||
|
protected final Boolean isReadOnlyBeforeAttachedToSession() {
|
||||||
|
if ( isReadOnlySettingAvailable() ) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Cannot call isReadOnlyBeforeAttachedToSession when isReadOnlySettingAvailable == true"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return readOnlyBeforeAttachedToSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the read-only/modifiable setting that should be put in affect when it is
|
||||||
|
* attached to a session.
|
||||||
|
*
|
||||||
|
* This method should only be called during deserialization, before associating
|
||||||
|
* the proxy with a session.
|
||||||
|
*
|
||||||
|
* @param readOnlyBeforeAttachedToSession, the read-only/modifiable setting to use when
|
||||||
|
* associated with a session; null indicates that the default should be used.
|
||||||
|
* @throws IllegalStateException if isReadOnlySettingAvailable() == true
|
||||||
|
*/
|
||||||
|
/* package-private */
|
||||||
|
final void setReadOnlyBeforeAttachedToSession(Boolean readOnlyBeforeAttachedToSession) {
|
||||||
|
if ( isReadOnlySettingAvailable() ) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Cannot call setReadOnlyBeforeAttachedToSession when isReadOnlySettingAvailable == true"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.readOnlyBeforeAttachedToSession = readOnlyBeforeAttachedToSession;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010, Red Hat Middleware LLC 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 Middleware LLC.
|
||||||
|
*
|
||||||
|
* 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.proxy;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience base class for SerializableProxy.
|
||||||
|
*
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
public abstract class AbstractSerializableProxy implements Serializable {
|
||||||
|
private String entityName;
|
||||||
|
private Serializable id;
|
||||||
|
private Boolean readOnly;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For serialization
|
||||||
|
*/
|
||||||
|
protected AbstractSerializableProxy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractSerializableProxy(String entityName, Serializable id, Boolean readOnly) {
|
||||||
|
this.entityName = entityName;
|
||||||
|
this.id = id;
|
||||||
|
this.readOnly = readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getEntityName() {
|
||||||
|
return entityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Serializable getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the read-only/modifiable setting from this object in an AbstractLazyInitializer.
|
||||||
|
*
|
||||||
|
* This method should only be called during deserialization, before associating the
|
||||||
|
* AbstractLazyInitializer with a session.
|
||||||
|
*
|
||||||
|
* @param li, the read-only/modifiable setting to use when
|
||||||
|
* associated with a session; null indicates that the default should be used.
|
||||||
|
* @throws IllegalStateException if isReadOnlySettingAvailable() == true
|
||||||
|
*/
|
||||||
|
protected void setReadOnlyBeforeAttachedToSession(AbstractLazyInitializer li) {
|
||||||
|
li.setReadOnlyBeforeAttachedToSession( readOnly );
|
||||||
|
}
|
||||||
|
}
|
|
@ -104,11 +104,24 @@ public interface LazyInitializer {
|
||||||
*/
|
*/
|
||||||
public void setImplementation(Object target);
|
public void setImplementation(Object target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the proxy's read-only/modifiable setting available?
|
||||||
|
* @return true, if the setting is available
|
||||||
|
* false, if the proxy is detached or its associated session is closed
|
||||||
|
*/
|
||||||
|
public boolean isReadOnlySettingAvailable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the proxy read-only?.
|
* Is the proxy read-only?.
|
||||||
*
|
*
|
||||||
|
* The read-only/modifiable setting is not available when the proxy is
|
||||||
|
* detached or its associated session is closed.
|
||||||
|
*
|
||||||
|
* To check if the read-only/modifiable setting is available:
|
||||||
|
* @see org.hibernate.proxy.LazyInitializer#isReadOnlySettingAvailable()
|
||||||
|
*
|
||||||
* @return true, if this proxy is read-only; false, otherwise
|
* @return true, if this proxy is read-only; false, otherwise
|
||||||
* @throws org.hibernate.TransientObjectException if the proxy is not association with a session
|
* @throws org.hibernate.TransientObjectException if the proxy is detached (getSession() == null)
|
||||||
* @throws org.hibernate.SessionException if the proxy is associated with a sesssion that is closed
|
* @throws org.hibernate.SessionException if the proxy is associated with a sesssion that is closed
|
||||||
*
|
*
|
||||||
* @see org.hibernate.Session#isReadOnly(Object entityOrProxy)
|
* @see org.hibernate.Session#isReadOnly(Object entityOrProxy)
|
||||||
|
|
|
@ -212,11 +212,10 @@ public final class CGLIBLazyInitializer extends BasicLazyInitializer implements
|
||||||
persistentClass,
|
persistentClass,
|
||||||
interfaces,
|
interfaces,
|
||||||
getIdentifier(),
|
getIdentifier(),
|
||||||
( getSession() != null && getSession().isOpen() ? isReadOnly() : false ),
|
( isReadOnlySettingAvailable() ? Boolean.valueOf( isReadOnly() ) : isReadOnlyBeforeAttachedToSession() ),
|
||||||
getIdentifierMethod,
|
getIdentifierMethod,
|
||||||
setIdentifierMethod,
|
setIdentifierMethod,
|
||||||
componentIdType
|
componentIdType
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,19 +28,17 @@ import java.io.Serializable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.proxy.AbstractSerializableProxy;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.type.AbstractComponentType;
|
import org.hibernate.type.AbstractComponentType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializable placeholder for <tt>CGLIB</tt> proxies
|
* Serializable placeholder for <tt>CGLIB</tt> proxies
|
||||||
*/
|
*/
|
||||||
public final class SerializableProxy implements Serializable {
|
public final class SerializableProxy extends AbstractSerializableProxy {
|
||||||
|
|
||||||
private String entityName;
|
|
||||||
private Class persistentClass;
|
private Class persistentClass;
|
||||||
private Class[] interfaces;
|
private Class[] interfaces;
|
||||||
private Serializable id;
|
|
||||||
private boolean readOnly;
|
|
||||||
private Class getIdentifierMethodClass;
|
private Class getIdentifierMethodClass;
|
||||||
private Class setIdentifierMethodClass;
|
private Class setIdentifierMethodClass;
|
||||||
private String getIdentifierMethodName;
|
private String getIdentifierMethodName;
|
||||||
|
@ -55,16 +53,14 @@ public final class SerializableProxy implements Serializable {
|
||||||
final Class persistentClass,
|
final Class persistentClass,
|
||||||
final Class[] interfaces,
|
final Class[] interfaces,
|
||||||
final Serializable id,
|
final Serializable id,
|
||||||
final boolean readOnly,
|
final Boolean readOnly,
|
||||||
final Method getIdentifierMethod,
|
final Method getIdentifierMethod,
|
||||||
final Method setIdentifierMethod,
|
final Method setIdentifierMethod,
|
||||||
AbstractComponentType componentIdType
|
AbstractComponentType componentIdType
|
||||||
) {
|
) {
|
||||||
this.entityName = entityName;
|
super( entityName, id, readOnly );
|
||||||
this.persistentClass = persistentClass;
|
this.persistentClass = persistentClass;
|
||||||
this.interfaces = interfaces;
|
this.interfaces = interfaces;
|
||||||
this.id = id;
|
|
||||||
this.readOnly = readOnly;
|
|
||||||
if (getIdentifierMethod!=null) {
|
if (getIdentifierMethod!=null) {
|
||||||
getIdentifierMethodClass = getIdentifierMethod.getDeclaringClass();
|
getIdentifierMethodClass = getIdentifierMethod.getDeclaringClass();
|
||||||
getIdentifierMethodName = getIdentifierMethod.getName();
|
getIdentifierMethodName = getIdentifierMethod.getName();
|
||||||
|
@ -79,8 +75,8 @@ public final class SerializableProxy implements Serializable {
|
||||||
|
|
||||||
private Object readResolve() {
|
private Object readResolve() {
|
||||||
try {
|
try {
|
||||||
return CGLIBLazyInitializer.getProxy(
|
HibernateProxy proxy = CGLIBLazyInitializer.getProxy(
|
||||||
entityName,
|
getEntityName(),
|
||||||
persistentClass,
|
persistentClass,
|
||||||
interfaces,
|
interfaces,
|
||||||
getIdentifierMethodName==null ?
|
getIdentifierMethodName==null ?
|
||||||
|
@ -90,12 +86,15 @@ public final class SerializableProxy implements Serializable {
|
||||||
null :
|
null :
|
||||||
setIdentifierMethodClass.getDeclaredMethod(setIdentifierMethodName, setIdentifierMethodParams),
|
setIdentifierMethodClass.getDeclaredMethod(setIdentifierMethodName, setIdentifierMethodParams),
|
||||||
componentIdType,
|
componentIdType,
|
||||||
id,
|
getId(),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
setReadOnlyBeforeAttachedToSession( ( CGLIBLazyInitializer ) proxy.getHibernateLazyInitializer() );
|
||||||
|
return proxy;
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException nsme) {
|
catch (NoSuchMethodException nsme) {
|
||||||
throw new HibernateException("could not create proxy for entity: " + entityName, nsme);
|
throw new HibernateException("could not create proxy for entity: " + getEntityName(), nsme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import javassist.util.proxy.ProxyFactory;
|
||||||
import javassist.util.proxy.ProxyObject;
|
import javassist.util.proxy.ProxyObject;
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.engine.SessionImplementor;
|
import org.hibernate.engine.SessionImplementor;
|
||||||
import org.hibernate.proxy.pojo.BasicLazyInitializer;
|
import org.hibernate.proxy.pojo.BasicLazyInitializer;
|
||||||
|
@ -229,7 +230,7 @@ public class JavassistLazyInitializer extends BasicLazyInitializer implements Me
|
||||||
persistentClass,
|
persistentClass,
|
||||||
interfaces,
|
interfaces,
|
||||||
getIdentifier(),
|
getIdentifier(),
|
||||||
( getSession() != null && getSession().isOpen() ? isReadOnly() : false ),
|
( isReadOnlySettingAvailable() ? Boolean.valueOf( isReadOnly() ) : isReadOnlyBeforeAttachedToSession() ),
|
||||||
getIdentifierMethod,
|
getIdentifierMethod,
|
||||||
setIdentifierMethod,
|
setIdentifierMethod,
|
||||||
componentIdType
|
componentIdType
|
||||||
|
|
|
@ -28,19 +28,17 @@ import java.io.Serializable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.proxy.AbstractSerializableProxy;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.type.AbstractComponentType;
|
import org.hibernate.type.AbstractComponentType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializable placeholder for Javassist proxies
|
* Serializable placeholder for Javassist proxies
|
||||||
*/
|
*/
|
||||||
public final class SerializableProxy implements Serializable {
|
public final class SerializableProxy extends AbstractSerializableProxy {
|
||||||
|
|
||||||
private String entityName;
|
|
||||||
private Class persistentClass;
|
private Class persistentClass;
|
||||||
private Class[] interfaces;
|
private Class[] interfaces;
|
||||||
private Serializable id;
|
|
||||||
private boolean readOnly;
|
|
||||||
private Class getIdentifierMethodClass;
|
private Class getIdentifierMethodClass;
|
||||||
private Class setIdentifierMethodClass;
|
private Class setIdentifierMethodClass;
|
||||||
private String getIdentifierMethodName;
|
private String getIdentifierMethodName;
|
||||||
|
@ -55,16 +53,14 @@ public final class SerializableProxy implements Serializable {
|
||||||
final Class persistentClass,
|
final Class persistentClass,
|
||||||
final Class[] interfaces,
|
final Class[] interfaces,
|
||||||
final Serializable id,
|
final Serializable id,
|
||||||
final boolean readOnly,
|
final Boolean readOnly,
|
||||||
final Method getIdentifierMethod,
|
final Method getIdentifierMethod,
|
||||||
final Method setIdentifierMethod,
|
final Method setIdentifierMethod,
|
||||||
AbstractComponentType componentIdType
|
AbstractComponentType componentIdType
|
||||||
) {
|
) {
|
||||||
this.entityName = entityName;
|
super( entityName, id, readOnly );
|
||||||
this.persistentClass = persistentClass;
|
this.persistentClass = persistentClass;
|
||||||
this.interfaces = interfaces;
|
this.interfaces = interfaces;
|
||||||
this.id = id;
|
|
||||||
this.readOnly = readOnly;
|
|
||||||
if (getIdentifierMethod!=null) {
|
if (getIdentifierMethod!=null) {
|
||||||
getIdentifierMethodClass = getIdentifierMethod.getDeclaringClass();
|
getIdentifierMethodClass = getIdentifierMethod.getDeclaringClass();
|
||||||
getIdentifierMethodName = getIdentifierMethod.getName();
|
getIdentifierMethodName = getIdentifierMethod.getName();
|
||||||
|
@ -79,8 +75,8 @@ public final class SerializableProxy implements Serializable {
|
||||||
|
|
||||||
private Object readResolve() {
|
private Object readResolve() {
|
||||||
try {
|
try {
|
||||||
return JavassistLazyInitializer.getProxy(
|
HibernateProxy proxy = JavassistLazyInitializer.getProxy(
|
||||||
entityName,
|
getEntityName(),
|
||||||
persistentClass,
|
persistentClass,
|
||||||
interfaces,
|
interfaces,
|
||||||
getIdentifierMethodName==null ?
|
getIdentifierMethodName==null ?
|
||||||
|
@ -90,13 +86,14 @@ public final class SerializableProxy implements Serializable {
|
||||||
null :
|
null :
|
||||||
setIdentifierMethodClass.getDeclaredMethod(setIdentifierMethodName, setIdentifierMethodParams),
|
setIdentifierMethodClass.getDeclaredMethod(setIdentifierMethodName, setIdentifierMethodParams),
|
||||||
componentIdType,
|
componentIdType,
|
||||||
id,
|
getId(),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
setReadOnlyBeforeAttachedToSession( ( JavassistLazyInitializer ) proxy.getHibernateLazyInitializer() );
|
||||||
|
return proxy;
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException nsme) {
|
catch (NoSuchMethodException nsme) {
|
||||||
throw new HibernateException("could not create proxy for entity: " + entityName, nsme);
|
throw new HibernateException("could not create proxy for entity: " + getEntityName(), nsme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,7 @@ public class GetLoadTest extends AbstractOperationTestCase {
|
||||||
SimpleJtaTransactionManagerImpl.getInstance().commit();
|
SimpleJtaTransactionManagerImpl.getInstance().commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testLoadReadOnlyFailureExpected() throws Exception {
|
public void testLoadReadOnly() throws Exception {
|
||||||
clearCounts();
|
clearCounts();
|
||||||
|
|
||||||
SimpleJtaTransactionManagerImpl.getInstance().begin();
|
SimpleJtaTransactionManagerImpl.getInstance().begin();
|
||||||
|
|
|
@ -123,6 +123,31 @@ public class ProxyTest extends FunctionalTestCase {
|
||||||
s.close();
|
s.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testInitializedProxySerializationAfterSessionClosed() {
|
||||||
|
Session s = openSession();
|
||||||
|
Transaction t = s.beginTransaction();
|
||||||
|
DataPoint dp = new DataPoint();
|
||||||
|
dp.setDescription("a data point");
|
||||||
|
dp.setX( new BigDecimal(1.0) );
|
||||||
|
dp.setY( new BigDecimal(2.0) );
|
||||||
|
s.persist(dp);
|
||||||
|
s.flush();
|
||||||
|
s.clear();
|
||||||
|
|
||||||
|
dp = (DataPoint) s.load( DataPoint.class, new Long( dp.getId() ) );
|
||||||
|
assertFalse( Hibernate.isInitialized(dp) );
|
||||||
|
Hibernate.initialize( dp );
|
||||||
|
assertTrue( Hibernate.isInitialized(dp) );
|
||||||
|
s.close();
|
||||||
|
SerializationHelper.clone( dp );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
t = s.beginTransaction();
|
||||||
|
s.delete( dp );
|
||||||
|
t.commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
public void testProxySerialization() {
|
public void testProxySerialization() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
Transaction t = s.beginTransaction();
|
Transaction t = s.beginTransaction();
|
||||||
|
|
|
@ -1328,6 +1328,7 @@ public class ReadOnlyProxyTest extends FunctionalTestCase {
|
||||||
}
|
}
|
||||||
catch ( SessionException ex) {
|
catch ( SessionException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertFalse( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().isReadOnlySettingAvailable() );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
s = openSession();
|
s = openSession();
|
||||||
|
@ -1360,6 +1361,7 @@ public class ReadOnlyProxyTest extends FunctionalTestCase {
|
||||||
}
|
}
|
||||||
catch ( TransientObjectException ex) {
|
catch ( TransientObjectException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertFalse( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().isReadOnlySettingAvailable() );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
s = openSession();
|
s = openSession();
|
||||||
|
@ -1393,6 +1395,7 @@ public class ReadOnlyProxyTest extends FunctionalTestCase {
|
||||||
}
|
}
|
||||||
catch ( TransientObjectException ex) {
|
catch ( TransientObjectException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertFalse( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().isReadOnlySettingAvailable() );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
s.delete( dp );
|
s.delete( dp );
|
||||||
|
@ -1421,6 +1424,7 @@ public class ReadOnlyProxyTest extends FunctionalTestCase {
|
||||||
}
|
}
|
||||||
catch ( TransientObjectException ex) {
|
catch ( TransientObjectException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertFalse( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().isReadOnlySettingAvailable() );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
|
@ -1450,6 +1454,7 @@ public class ReadOnlyProxyTest extends FunctionalTestCase {
|
||||||
}
|
}
|
||||||
catch ( SessionException ex) {
|
catch ( SessionException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertFalse( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().isReadOnlySettingAvailable() );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
s = openSession();
|
s = openSession();
|
||||||
|
@ -1482,6 +1487,7 @@ public class ReadOnlyProxyTest extends FunctionalTestCase {
|
||||||
}
|
}
|
||||||
catch ( TransientObjectException ex) {
|
catch ( TransientObjectException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertFalse( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().isReadOnlySettingAvailable() );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
s = openSession();
|
s = openSession();
|
||||||
|
@ -1492,6 +1498,39 @@ public class ReadOnlyProxyTest extends FunctionalTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testSetClosedSessionInLazyInitializer() {
|
||||||
|
DataPoint dpOrig = createDataPoint( CacheMode.IGNORE );
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.setCacheMode(CacheMode.IGNORE);
|
||||||
|
|
||||||
|
s.beginTransaction();
|
||||||
|
DataPoint dp = ( DataPoint ) s.load( DataPoint.class, new Long( dpOrig.getId() ) );
|
||||||
|
assertTrue( dp instanceof HibernateProxy );
|
||||||
|
assertFalse( Hibernate.isInitialized( dp ) );
|
||||||
|
checkReadOnly( s, dp, false );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
assertTrue( s.contains( dp ) );
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
assertNull( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().getSession() );
|
||||||
|
assertTrue( ( ( SessionImplementor ) s ).isClosed() );
|
||||||
|
try {
|
||||||
|
( ( HibernateProxy ) dp ).getHibernateLazyInitializer().setSession( ( SessionImplementor ) s );
|
||||||
|
fail( "should have failed because session was closed" );
|
||||||
|
}
|
||||||
|
catch ( SessionException ex) {
|
||||||
|
// expected
|
||||||
|
assertFalse( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().isReadOnlySettingAvailable() );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.delete( dp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void testDetachedSetReadOnlyAfterEvictViaSession() {
|
public void testDetachedSetReadOnlyAfterEvictViaSession() {
|
||||||
DataPoint dpOrig = createDataPoint( CacheMode.IGNORE );
|
DataPoint dpOrig = createDataPoint( CacheMode.IGNORE );
|
||||||
|
@ -1515,6 +1554,7 @@ public class ReadOnlyProxyTest extends FunctionalTestCase {
|
||||||
}
|
}
|
||||||
catch ( TransientObjectException ex) {
|
catch ( TransientObjectException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertFalse( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().isReadOnlySettingAvailable() );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
s.delete( dp );
|
s.delete( dp );
|
||||||
|
@ -1543,6 +1583,7 @@ public class ReadOnlyProxyTest extends FunctionalTestCase {
|
||||||
}
|
}
|
||||||
catch ( TransientObjectException ex) {
|
catch ( TransientObjectException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertFalse( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().isReadOnlySettingAvailable() );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
|
|
Loading…
Reference in New Issue