From b40cfb58dbe4606609c3fa2b1e5e210466c593df Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Wed, 27 Jan 2010 09:26:42 +0000 Subject: [PATCH] HHH-4781 : Read-only entities changed to modifiable on refresh git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18643 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../def/DefaultRefreshEventListener.java | 11 +- .../test/readonly/ReadOnlyProxyTest.java | 89 +++++++ .../ReadOnlySessionLazyNonLazyTest.java | 2 +- .../test/readonly/ReadOnlySessionTest.java | 224 +++++++++++++++++- .../hibernate/test/readonly/ReadOnlyTest.java | 41 +++- 5 files changed, 363 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java b/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java index dd1cb8858a..7c8e9507ea 100644 --- a/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java +++ b/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java @@ -71,7 +71,13 @@ public class DefaultRefreshEventListener implements RefreshEventListener { final EventSource source = event.getSession(); - if ( source.getPersistenceContext().reassociateIfUninitializedProxy( event.getObject() ) ) return; + boolean isTransient = ! source.contains( event.getObject() ); + if ( source.getPersistenceContext().reassociateIfUninitializedProxy( event.getObject() ) ) { + if ( isTransient ) { + source.setReadOnly( event.getObject(), source.isDefaultReadOnly() ); + } + return; + } final Object object = source.getPersistenceContext().unproxyAndReassociate( event.getObject() ); @@ -143,6 +149,9 @@ public class DefaultRefreshEventListener implements RefreshEventListener { String previousFetchProfile = source.getFetchProfile(); source.setFetchProfile("refresh"); Object result = persister.load( id, object, event.getLockOptions(), source ); + // Keep the same read-only/modifiable setting for the entity that it had before refreshing; + // If it was transient, then set it to the default for the source. + source.setReadOnly( result, ( e == null ? source.isDefaultReadOnly() : e.isReadOnly() ) ); source.setFetchProfile(previousFetchProfile); UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() ); diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyProxyTest.java b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyProxyTest.java index 778a61cd12..797b6e08be 100644 --- a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyProxyTest.java +++ b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyProxyTest.java @@ -840,6 +840,95 @@ public class ReadOnlyProxyTest extends FunctionalTestCase { s.close(); } + public void testReadOnlyRefresh() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setDescription( "original" ); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + dp = ( DataPoint ) s.load( DataPoint.class, dp.getId() ); + s.setReadOnly( dp, true ); + assertFalse( Hibernate.isInitialized( dp ) ); + s.refresh( dp ); + assertFalse( Hibernate.isInitialized( dp ) ); + assertEquals( "original", dp.getDescription() ); + assertTrue( Hibernate.isInitialized( dp ) ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + assertTrue( s.isReadOnly( dp ) ); + assertTrue( s.isReadOnly( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().getImplementation() ) ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + assertTrue( s.isReadOnly( dp ) ); + assertTrue( s.isReadOnly( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().getImplementation() ) ); + t.commit(); + + s.clear(); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertEquals( "original", dp.getDescription() ); + s.delete( dp ); + t.commit(); + s.close(); + + } + + public void testReadOnlyRefreshDetached() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setDescription( "original" ); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + dp = ( DataPoint ) s.load( DataPoint.class, dp.getId() ); + assertFalse( Hibernate.isInitialized( dp ) ); + assertFalse( s.isReadOnly( dp ) ); + s.setReadOnly( dp, true ); + assertTrue( s.isReadOnly( dp ) ); + s.evict( dp ); + s.refresh( dp ); + assertFalse( Hibernate.isInitialized( dp ) ); + assertFalse( s.isReadOnly( dp ) ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + assertTrue( Hibernate.isInitialized( dp ) ); + s.setReadOnly( dp, true ); + s.evict( dp ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + assertFalse( s.isReadOnly( dp ) ); + t.commit(); + + s.clear(); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertEquals( "original", dp.getDescription() ); + s.delete( dp ); + t.commit(); + s.close(); + } + public void testReadOnlyProxyMergeDetachedProxyWithChange() { DataPoint dpOrig = createDataPoint( CacheMode.IGNORE ); diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionLazyNonLazyTest.java b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionLazyNonLazyTest.java index 4200035ee1..1bddb921e5 100644 --- a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionLazyNonLazyTest.java +++ b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionLazyNonLazyTest.java @@ -124,7 +124,7 @@ public class ReadOnlySessionLazyNonLazyTest extends FunctionalTestCase { c = ( Container ) s.get( Container.class, cOrig.getId() ); assertSame( cOrig, c ); checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); - //s.refresh( cOrig ); + s.refresh( cOrig ); assertSame( cOrig, c ); checkContainer( cOrig, expectedInitializedObjects, expectedReadOnlyObjects, s ); s.evict( cOrig ); diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionTest.java b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionTest.java index da180ef75e..78cc123975 100644 --- a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionTest.java +++ b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlySessionTest.java @@ -40,6 +40,7 @@ import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.junit.functional.FunctionalTestCase; import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.proxy.HibernateProxy; /** * @@ -183,7 +184,7 @@ public class ReadOnlySessionTest extends FunctionalTestCase { s.close(); } - public void testReadOnlyRefreshFailureExpected() { + public void testReadOnlyRefresh() { Session s = openSession(); s.setCacheMode(CacheMode.IGNORE); @@ -201,11 +202,18 @@ public class ReadOnlySessionTest extends FunctionalTestCase { s.setDefaultReadOnly( true ); t = s.beginTransaction(); dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertTrue( s.isReadOnly( dp ) ); + assertEquals( "original", dp.getDescription() ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + s.refresh( dp ); + assertTrue( s.isReadOnly( dp ) ); assertEquals( "original", dp.getDescription() ); dp.setDescription( "changed" ); assertEquals( "changed", dp.getDescription() ); s.setDefaultReadOnly( false ); s.refresh( dp ); + assertTrue( s.isReadOnly( dp ) ); assertEquals( "original", dp.getDescription() ); dp.setDescription( "changed" ); assertEquals( "changed", dp.getDescription() ); @@ -218,7 +226,169 @@ public class ReadOnlySessionTest extends FunctionalTestCase { s.delete( dp ); t.commit(); s.close(); + } + public void testReadOnlyRefreshDetached() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setDescription( "original" ); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + s.setDefaultReadOnly( false ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + assertFalse( s.isReadOnly( dp ) ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + s.evict( dp ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + assertFalse( s.isReadOnly( dp ) ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + s.setDefaultReadOnly( true ); + s.evict( dp ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + assertTrue( s.isReadOnly( dp ) ); + dp.setDescription( "changed" ); + t.commit(); + + s.clear(); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertEquals( "original", dp.getDescription() ); + s.delete( dp ); + t.commit(); + s.close(); + } + + public void testReadOnlyProxyRefresh() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setDescription( "original" ); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + dp = ( DataPoint ) s.load( DataPoint.class, dp.getId() ); + assertTrue( s.isReadOnly( dp ) ); + assertFalse( Hibernate.isInitialized( dp ) ); + s.refresh( dp ); + assertFalse( Hibernate.isInitialized( dp ) ); + assertTrue( s.isReadOnly( dp ) ); + s.setDefaultReadOnly( false ); + s.refresh( dp ); + assertFalse( Hibernate.isInitialized( dp ) ); + assertTrue( s.isReadOnly( dp ) ); + assertEquals( "original", dp.getDescription() ); + assertTrue( Hibernate.isInitialized( dp ) ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + assertTrue( s.isReadOnly( dp ) ); + assertTrue( s.isReadOnly( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().getImplementation() ) ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + assertTrue( s.isReadOnly( dp ) ); + assertTrue( s.isReadOnly( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().getImplementation() ) ); + s.setDefaultReadOnly( true ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + s.refresh( dp ); + assertTrue( s.isReadOnly( dp ) ); + assertTrue( s.isReadOnly( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().getImplementation() ) ); + assertEquals( "original", dp.getDescription() ); + dp.setDescription( "changed" ); + t.commit(); + + s.clear(); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertEquals( "original", dp.getDescription() ); + s.delete( dp ); + t.commit(); + s.close(); + + } + + public void testReadOnlyProxyRefreshDetached() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setDescription( "original" ); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + dp = ( DataPoint ) s.load( DataPoint.class, dp.getId() ); + assertFalse( Hibernate.isInitialized( dp ) ); + assertTrue( s.isReadOnly( dp ) ); + s.evict( dp ); + s.refresh( dp ); + assertFalse( Hibernate.isInitialized( dp ) ); + s.setDefaultReadOnly( false ); + assertTrue( s.isReadOnly( dp ) ); + s.evict( dp ); + s.refresh( dp ); + assertFalse( Hibernate.isInitialized( dp ) ); + assertFalse( s.isReadOnly( dp ) ); + assertFalse( s.isReadOnly( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().getImplementation() ) ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + assertTrue( Hibernate.isInitialized( dp ) ); + s.evict( dp ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + assertFalse( s.isReadOnly( dp ) ); + assertFalse( s.isReadOnly( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().getImplementation() ) ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + s.setDefaultReadOnly( true ); + s.evict( dp ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + assertTrue( s.isReadOnly( dp ) ); + assertTrue( s.isReadOnly( ( ( HibernateProxy ) dp ).getHibernateLazyInitializer().getImplementation() ) ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + t.commit(); + + s.clear(); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertEquals( "original", dp.getDescription() ); + s.delete( dp ); + t.commit(); + s.close(); } public void testReadOnlyDelete() { @@ -453,4 +623,56 @@ public class ReadOnlySessionTest extends FunctionalTestCase { s.close(); } + + public void testMergeWithReadOnlyProxy() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + dp.setDescription( "description" ); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + s.setDefaultReadOnly( true ); + DataPoint dpProxy = ( DataPoint ) s.load( DataPoint.class, new Long( dp.getId() ) ); + assertTrue( s.isReadOnly( dpProxy ) ); + assertFalse( Hibernate.isInitialized( dpProxy ) ); + s.evict( dpProxy ); + dpProxy = ( DataPoint ) s.merge( dpProxy ); + assertTrue( s.isReadOnly( dpProxy ) ); + assertFalse( Hibernate.isInitialized( dpProxy ) ); + dpProxy = ( DataPoint ) s.merge( dp ); + assertTrue( s.isReadOnly( dpProxy ) ); + assertTrue( Hibernate.isInitialized( dpProxy ) ); + assertEquals( "description", dpProxy.getDescription() ); + s.evict( dpProxy ); + dpProxy = ( DataPoint ) s.merge( dpProxy ); + assertTrue( s.isReadOnly( dpProxy ) ); + assertTrue( Hibernate.isInitialized( dpProxy ) ); + assertEquals( "description", dpProxy.getDescription() ); + dpProxy.setDescription( null ); + dpProxy = ( DataPoint ) s.merge( dp ); + assertTrue( s.isReadOnly( dpProxy ) ); + assertTrue( Hibernate.isInitialized( dpProxy ) ); + assertEquals( "description", dpProxy.getDescription() ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, new Long( dp.getId() ) ); + assertNull( dp.getDescription() ); + s.delete( dp ); + t.commit(); + s.close(); + + } } \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java index 16f6613bc3..f83f13f2d8 100755 --- a/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java +++ b/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java @@ -169,7 +169,7 @@ public class ReadOnlyTest extends FunctionalTestCase { } - public void testReadOnlyRefreshFailureExpected() { + public void testReadOnlyRefresh() { Session s = openSession(); s.setCacheMode(CacheMode.IGNORE); @@ -206,6 +206,45 @@ public class ReadOnlyTest extends FunctionalTestCase { } + public void testReadOnlyRefreshDetached() { + + Session s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + Transaction t = s.beginTransaction(); + DataPoint dp = new DataPoint(); + dp.setDescription( "original" ); + dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) ); + dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) ); + s.save(dp); + t.commit(); + s.close(); + + s = openSession(); + s.setCacheMode(CacheMode.IGNORE); + t = s.beginTransaction(); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + assertFalse( s.isReadOnly( dp ) ); + s.setReadOnly( dp, true ); + dp.setDescription( "changed" ); + assertEquals( "changed", dp.getDescription() ); + s.evict( dp ); + s.refresh( dp ); + assertEquals( "original", dp.getDescription() ); + assertFalse( s.isReadOnly( dp ) ); + t.commit(); + + s.clear(); + t = s.beginTransaction(); + dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() ); + assertEquals( "original", dp.getDescription() ); + s.delete( dp ); + t.commit(); + s.close(); + } + public void testReadOnlyDelete() { Session s = openSession();