Skip to content

Commit c00d460

Browse files
committed
HHH-5255 : Merge detached entity failed when the instrumented lazy property is initialized
1 parent 3d21604 commit c00d460

File tree

7 files changed

+357
-46
lines changed

7 files changed

+357
-46
lines changed

hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,22 @@ public static Object[] replace(
157157
|| original[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
158158
copied[i] = target[i];
159159
}
160+
else if ( target[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
161+
// Should be no need to check for target[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN
162+
// because PropertyAccessStrategyBackRefImpl.get( object ) returns
163+
// PropertyAccessStrategyBackRefImpl.UNKNOWN, so target[i] == original[i].
164+
//
165+
// We know from above that original[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY &&
166+
// original[i] != PropertyAccessStrategyBackRefImpl.UNKNOWN;
167+
// This is a case where the entity being merged has a lazy property
168+
// that has been initialized. Copy the initialized value from original.
169+
if ( types[i].isMutable() ) {
170+
copied[i] = types[i].deepCopy( original[i], session.getFactory() );
171+
}
172+
else {
173+
copied[i] = original[i];
174+
}
175+
}
160176
else {
161177
copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache );
162178
}

hibernate-core/src/test/java/org/hibernate/test/instrument/buildtime/InstrumentTest.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
import org.hibernate.test.instrument.cases.TestFetchAllExecutable;
1515
import org.hibernate.test.instrument.cases.TestInjectFieldInterceptorExecutable;
1616
import org.hibernate.test.instrument.cases.TestIsPropertyInitializedExecutable;
17-
import org.hibernate.test.instrument.cases.TestLazyBasicPropertyUpdateExecutable;
17+
import org.hibernate.test.instrument.cases.TestLazyBasicFieldAccessExecutable;
18+
import org.hibernate.test.instrument.cases.TestLazyBasicPropertyAccessExecutable;
1819
import org.hibernate.test.instrument.cases.TestLazyExecutable;
1920
import org.hibernate.test.instrument.cases.TestLazyManyToOneExecutable;
2021
import org.hibernate.test.instrument.cases.TestLazyPropertyCustomTypeExecutable;
@@ -73,8 +74,13 @@ public void testLazyPropertyCustomTypeExecutable() throws Exception {
7374
}
7475

7576
@Test
76-
public void testLazyBasicPropertyUpdate() throws Exception {
77-
execute( new TestLazyBasicPropertyUpdateExecutable() );
77+
public void testLazyBasicFieldAccess() throws Exception {
78+
execute( new TestLazyBasicFieldAccessExecutable() );
79+
}
80+
81+
@Test
82+
public void testLazyBasicPropertyAccess() throws Exception {
83+
execute( new TestLazyBasicPropertyAccessExecutable() );
7884
}
7985

8086
@Test
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package org.hibernate.test.instrument.cases;
2+
import org.junit.Assert;
3+
4+
import org.hibernate.Hibernate;
5+
import org.hibernate.Session;
6+
import org.hibernate.Transaction;
7+
import org.hibernate.test.instrument.domain.Document;
8+
import org.hibernate.test.instrument.domain.Folder;
9+
import org.hibernate.test.instrument.domain.Owner;
10+
11+
/**
12+
* @author Andrei Ivanov
13+
*/
14+
public class TestLazyBasicFieldAccessExecutable extends AbstractExecutable {
15+
protected String[] getResources() {
16+
return new String[] {"org/hibernate/test/instrument/domain/Documents.hbm.xml"};
17+
}
18+
19+
public void execute() {
20+
Session s = getFactory().openSession();
21+
Transaction t = s.beginTransaction();
22+
Owner o = new Owner();
23+
Document doc = new Document();
24+
Folder fol = new Folder();
25+
o.setName( "gavin" );
26+
doc.setName( "Hibernate in Action" );
27+
doc.setSummary( "blah" );
28+
doc.updateText( "blah blah" );
29+
fol.setName( "books" );
30+
doc.setOwner( o );
31+
doc.setFolder( fol );
32+
fol.getDocuments().add( doc );
33+
Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "summary" ) );
34+
s.persist( o );
35+
s.persist( fol );
36+
t.commit();
37+
s.close();
38+
39+
s = getFactory().openSession();
40+
s.getTransaction().begin();
41+
// update with lazy property initialized
42+
doc.setName( "Doc Name" );
43+
doc.setSummary( "u" );
44+
s.update( doc );
45+
s.getTransaction().commit();
46+
s.close();
47+
48+
s = getFactory().openSession();
49+
s.getTransaction().begin();
50+
// merge with lazy property initialized and updated
51+
doc.setName( "Doc Name 1" );
52+
doc.setSummary( "v" );
53+
Document docManaged = (Document) s.merge( doc );
54+
Assert.assertEquals( "v", docManaged.getSummary() );
55+
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
56+
s.getTransaction().commit();
57+
s.close();
58+
59+
s = getFactory().openSession();
60+
s.getTransaction().begin();
61+
// get the Document with an uninitialized summary
62+
docManaged = (Document) s.get( Document.class, doc.getId() );
63+
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
64+
// merge with lazy property initialized in doc; uninitialized in docManaged.
65+
doc.setSummary( "w" );
66+
Assert.assertSame( docManaged, s.merge( doc ) );
67+
Assert.assertEquals( "w", docManaged.getSummary() );
68+
s.getTransaction().commit();
69+
s.close();
70+
71+
s = getFactory().openSession();
72+
s.getTransaction().begin();
73+
// get the Document with an uninitialized summary
74+
docManaged = (Document) s.get( Document.class, doc.getId() );
75+
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
76+
// initialize docManaged.getSummary
77+
Assert.assertEquals( "w", docManaged.getSummary() );
78+
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
79+
// merge with lazy property initialized in both doc and docManaged.
80+
doc.setSummary( "x" );
81+
Assert.assertSame( docManaged, s.merge( doc ) );
82+
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
83+
Assert.assertEquals( "x", docManaged.getSummary() );
84+
s.getTransaction().commit();
85+
s.close();
86+
87+
s = getFactory().openSession();
88+
s.getTransaction().begin();
89+
// get the Document with an uninitialized summary
90+
Document docWithLazySummary = (Document) s.get( Document.class, doc.getId() );
91+
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
92+
s.getTransaction().commit();
93+
s.close();
94+
95+
s = getFactory().openSession();
96+
s.getTransaction().begin();
97+
// summary should still be uninitialized.
98+
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
99+
docWithLazySummary.setName( "new name" );
100+
// merge the Document with an uninitialized summary
101+
docManaged = (Document) s.merge( docWithLazySummary );
102+
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
103+
s.getTransaction().commit();
104+
s.close();
105+
106+
s = getFactory().openSession();
107+
s.getTransaction().begin();
108+
// get the Document with an uninitialized summary
109+
docManaged = (Document) s.get( Document.class, doc.getId() );
110+
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
111+
// initialize docManaged.getSummary
112+
Assert.assertEquals( "x", docManaged.getSummary() );
113+
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
114+
// merge the Document with an uninitialized summary
115+
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
116+
docManaged = (Document) s.merge( docWithLazySummary );
117+
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
118+
Assert.assertEquals( "x", docManaged.getSummary() );
119+
s.getTransaction().commit();
120+
s.close();
121+
}
122+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package org.hibernate.test.instrument.cases;
2+
import org.junit.Assert;
3+
4+
import org.hibernate.Hibernate;
5+
import org.hibernate.Session;
6+
import org.hibernate.Transaction;
7+
import org.hibernate.test.instrument.domain.Document;
8+
import org.hibernate.test.instrument.domain.Folder;
9+
import org.hibernate.test.instrument.domain.Owner;
10+
11+
/**
12+
* @author Andrei Ivanov
13+
*/
14+
public class TestLazyBasicPropertyAccessExecutable extends AbstractExecutable {
15+
protected String[] getResources() {
16+
return new String[] {"org/hibernate/test/instrument/domain/DocumentsPropAccess.hbm.xml"};
17+
}
18+
19+
public void execute() {
20+
Session s = getFactory().openSession();
21+
Transaction t = s.beginTransaction();
22+
Owner o = new Owner();
23+
Document doc = new Document();
24+
Folder fol = new Folder();
25+
o.setName( "gavin" );
26+
doc.setName( "Hibernate in Action" );
27+
doc.setSummary( "blah" );
28+
doc.updateText( "blah blah" );
29+
fol.setName( "books" );
30+
doc.setOwner( o );
31+
doc.setFolder( fol );
32+
fol.getDocuments().add( doc );
33+
Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "summary" ) );
34+
s.persist( o );
35+
s.persist( fol );
36+
t.commit();
37+
s.close();
38+
39+
s = getFactory().openSession();
40+
s.getTransaction().begin();
41+
// update with lazy property initialized
42+
doc.setName( "Doc Name" );
43+
doc.setSummary( "u" );
44+
s.update( doc );
45+
s.getTransaction().commit();
46+
s.close();
47+
48+
s = getFactory().openSession();
49+
s.getTransaction().begin();
50+
// merge with lazy property initialized and updated
51+
doc.setName( "Doc Name 1" );
52+
doc.setSummary( "v" );
53+
Document docManaged = (Document) s.merge( doc );
54+
Assert.assertEquals( "v", docManaged.getSummary() );
55+
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
56+
s.getTransaction().commit();
57+
s.close();
58+
59+
s = getFactory().openSession();
60+
s.getTransaction().begin();
61+
// get the Document with an uninitialized summary
62+
docManaged = (Document) s.get( Document.class, doc.getId() );
63+
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
64+
// merge with lazy property initialized in doc; uninitialized in docManaged.
65+
doc.setSummary( "w" );
66+
Assert.assertSame( docManaged, s.merge( doc ) );
67+
Assert.assertEquals( "w", docManaged.getSummary() );
68+
s.getTransaction().commit();
69+
s.close();
70+
71+
s = getFactory().openSession();
72+
s.getTransaction().begin();
73+
// get the Document with an uninitialized summary
74+
docManaged = (Document) s.get( Document.class, doc.getId() );
75+
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
76+
// initialize docManaged.getSummary
77+
Assert.assertEquals( "w", docManaged.getSummary() );
78+
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
79+
// merge with lazy property initialized in both doc and docManaged.
80+
doc.setSummary( "x" );
81+
Assert.assertSame( docManaged, s.merge( doc ) );
82+
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
83+
Assert.assertEquals( "x", docManaged.getSummary() );
84+
s.getTransaction().commit();
85+
s.close();
86+
87+
s = getFactory().openSession();
88+
s.getTransaction().begin();
89+
// get the Document with an uninitialized summary
90+
Document docWithLazySummary = (Document) s.get( Document.class, doc.getId() );
91+
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
92+
s.getTransaction().commit();
93+
s.close();
94+
95+
s = getFactory().openSession();
96+
s.getTransaction().begin();
97+
// summary should still be uninitialized.
98+
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
99+
docWithLazySummary.setName( "new name" );
100+
// merge the Document with an uninitialized summary
101+
docManaged = (Document) s.merge( docWithLazySummary );
102+
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
103+
s.getTransaction().commit();
104+
s.close();
105+
106+
s = getFactory().openSession();
107+
s.getTransaction().begin();
108+
// get the Document with an uninitialized summary
109+
docManaged = (Document) s.get( Document.class, doc.getId() );
110+
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
111+
// initialize docManaged.getSummary
112+
Assert.assertEquals( "x", docManaged.getSummary() );
113+
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
114+
// merge the Document with an uninitialized summary
115+
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
116+
docManaged = (Document) s.merge( docWithLazySummary );
117+
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
118+
Assert.assertEquals( "x", docManaged.getSummary() );
119+
s.getTransaction().commit();
120+
s.close();
121+
}
122+
}

hibernate-core/src/test/java/org/hibernate/test/instrument/cases/TestLazyBasicPropertyUpdateExecutable.java

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)