Skip to content

Commit 4699c73

Browse files
yrodieregsmet
authored andcommitted
HHH-12720 Test proxy serialization with hibernate.enable_lazy_load_no_trans = true
1 parent dcf1f66 commit 4699c73

File tree

1 file changed

+241
-0
lines changed

1 file changed

+241
-0
lines changed
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.serialization;
8+
9+
import java.io.Serializable;
10+
import java.util.HashSet;
11+
import java.util.Set;
12+
import javax.persistence.Entity;
13+
import javax.persistence.FetchType;
14+
import javax.persistence.Id;
15+
import javax.persistence.JoinColumn;
16+
import javax.persistence.ManyToOne;
17+
import javax.persistence.OneToMany;
18+
19+
import org.hibernate.Hibernate;
20+
import org.hibernate.Session;
21+
import org.hibernate.Transaction;
22+
import org.hibernate.annotations.Fetch;
23+
import org.hibernate.annotations.FetchMode;
24+
import org.hibernate.annotations.LazyCollection;
25+
import org.hibernate.annotations.LazyCollectionOption;
26+
import org.hibernate.annotations.LazyToOne;
27+
import org.hibernate.annotations.LazyToOneOption;
28+
import org.hibernate.cfg.AvailableSettings;
29+
import org.hibernate.cfg.Configuration;
30+
import org.hibernate.internal.util.SerializationHelper;
31+
import org.hibernate.proxy.AbstractLazyInitializer;
32+
import org.hibernate.proxy.HibernateProxy;
33+
34+
import org.hibernate.testing.FailureExpected;
35+
import org.hibernate.testing.TestForIssue;
36+
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
37+
import org.junit.Before;
38+
import org.junit.Test;
39+
40+
import static org.junit.Assert.assertEquals;
41+
import static org.junit.Assert.assertFalse;
42+
import static org.junit.Assert.assertTrue;
43+
44+
/**
45+
* @author Selaron
46+
*/
47+
public class EntityProxySerializationTest extends BaseCoreFunctionalTestCase {
48+
49+
@Override
50+
protected Class<?>[] getAnnotatedClasses() {
51+
return new Class[] { SimpleEntity.class, ChildEntity.class };
52+
}
53+
54+
@Override
55+
protected void configure(final Configuration configuration) {
56+
// enable LL without TX, which used to cause problems when serializing proxies (see HHH-12720)
57+
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, Boolean.TRUE.toString() );
58+
}
59+
60+
/**
61+
* Prepare and persist a {@link SimpleEntity} with two {@link ChildEntity}.
62+
*/
63+
@Before
64+
public void prepare() {
65+
final Session s = openSession();
66+
67+
final Transaction t = s.beginTransaction();
68+
69+
try {
70+
final Number count = (Number) s.createQuery("SELECT count(ID) FROM SimpleEntity").getSingleResult();
71+
if (count.longValue() > 0L) {
72+
// entity already added previously
73+
return;
74+
}
75+
76+
final SimpleEntity entity = new SimpleEntity();
77+
entity.setId( 1L );
78+
entity.setName( "TheParent" );
79+
80+
final ChildEntity c1 = new ChildEntity();
81+
c1.setId( 1L );
82+
c1.setParent( entity );
83+
84+
final ChildEntity c2 = new ChildEntity();
85+
c2.setId( 2L );
86+
c2.setParent( entity );
87+
88+
s.save( entity );
89+
s.save( c1 );
90+
s.save( c2 );
91+
}
92+
finally {
93+
t.commit();
94+
s.close();
95+
}
96+
}
97+
98+
/**
99+
* Tests that lazy loading without transaction nor open session is generally
100+
* working. The magic is done by {@link AbstractLazyInitializer} who opens a
101+
* temporary session.
102+
*/
103+
@SuppressWarnings("unchecked")
104+
@Test
105+
public void testProxyInitializationWithoutTX() {
106+
final Session s = openSession();
107+
108+
final Transaction t = s.beginTransaction();
109+
try {
110+
final ChildEntity child = s.find( ChildEntity.class, 1L );
111+
112+
final SimpleEntity parent = child.getParent();
113+
114+
t.rollback();
115+
session.close();
116+
117+
// assert we have an uninitialized proxy
118+
assertTrue( parent instanceof HibernateProxy );
119+
assertFalse( Hibernate.isInitialized( parent ) );
120+
121+
assertEquals( "TheParent", parent.getName() );
122+
123+
// assert we have an initialized proxy now
124+
assertTrue( Hibernate.isInitialized( parent ) );
125+
}
126+
finally {
127+
if ( t.isActive() ) {
128+
t.rollback();
129+
}
130+
s.close();
131+
}
132+
}
133+
134+
/**
135+
* Tests that lazy loading without transaction nor open session is generally
136+
* working. The magic is done by {@link AbstractLazyInitializer} who opens a
137+
* temporary session.
138+
*/
139+
@SuppressWarnings("unchecked")
140+
@Test
141+
@TestForIssue(jiraKey = "HHH-12720")
142+
@FailureExpected(jiraKey = "HHH-12720")
143+
public void testProxyInitializationWithoutTXAfterDeserialization() {
144+
final Session s = openSession();
145+
146+
final Transaction t = s.beginTransaction();
147+
try {
148+
final ChildEntity child = s.find( ChildEntity.class, 1L );
149+
150+
final SimpleEntity parent = child.getParent();
151+
152+
// destroy AbstractLazyInitializer internal state
153+
final SimpleEntity deserializedParent = (SimpleEntity) SerializationHelper.clone( parent );
154+
155+
t.rollback();
156+
session.close();
157+
158+
// assert we have an uninitialized proxy
159+
assertTrue( deserializedParent instanceof HibernateProxy );
160+
assertFalse( Hibernate.isInitialized( deserializedParent ) );
161+
162+
assertEquals( "TheParent", deserializedParent.getName() );
163+
164+
// assert we have an initialized proxy now
165+
assertTrue( Hibernate.isInitialized( deserializedParent ) );
166+
}
167+
finally {
168+
if ( t.isActive() ) {
169+
t.rollback();
170+
}
171+
s.close();
172+
}
173+
}
174+
175+
@Entity(name = "SimpleEntity")
176+
static class SimpleEntity implements Serializable {
177+
178+
private Long id;
179+
180+
private String name;
181+
182+
Set<ChildEntity> children = new HashSet<>();
183+
184+
@Id
185+
public Long getId() {
186+
return id;
187+
}
188+
189+
public void setId(final Long id) {
190+
this.id = id;
191+
}
192+
193+
public String getName() {
194+
return name;
195+
}
196+
197+
public void setName(final String name) {
198+
this.name = name;
199+
}
200+
201+
@OneToMany(targetEntity = ChildEntity.class, mappedBy = "parent")
202+
@LazyCollection(LazyCollectionOption.EXTRA)
203+
@Fetch(FetchMode.SELECT)
204+
public Set<ChildEntity> getChildren() {
205+
return children;
206+
}
207+
208+
public void setChildren(final Set<ChildEntity> children) {
209+
this.children = children;
210+
}
211+
212+
}
213+
214+
@Entity
215+
static class ChildEntity {
216+
private Long id;
217+
218+
private SimpleEntity parent;
219+
220+
@Id
221+
public Long getId() {
222+
return id;
223+
}
224+
225+
public void setId(final Long id) {
226+
this.id = id;
227+
}
228+
229+
@ManyToOne(fetch = FetchType.LAZY)
230+
@JoinColumn
231+
@LazyToOne(LazyToOneOption.PROXY)
232+
public SimpleEntity getParent() {
233+
return parent;
234+
}
235+
236+
public void setParent(final SimpleEntity parent) {
237+
this.parent = parent;
238+
}
239+
240+
}
241+
}

0 commit comments

Comments
 (0)