Skip to content

Commit f020c5d

Browse files
committed
HHH-19038 - Evaluate the session validity in AbstractPersistentCollection before actually dereferencing it
Add test for issue Signed-off-by: Jan Schatteman <jschatte@redhat.com>
1 parent 21ec538 commit f020c5d

File tree

2 files changed

+157
-3
lines changed

2 files changed

+157
-3
lines changed

hibernate-core/src/main/java/org/hibernate/collection/spi/AbstractPersistentCollection.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ public int getSize() {
179179
if ( cachedSize>=0 ) {
180180
return cachedSize;
181181
}
182+
throwLazyInitializationExceptionIfNotConnected();
182183
final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( this );
183184
if ( entry == null ) {
184-
throwLazyInitializationExceptionIfNotConnected();
185185
throwLazyInitializationException("collection not associated with session");
186186
throw new AssertionFailure("impossible");
187187
}
@@ -355,9 +355,9 @@ protected Boolean readElementExistence(final Object element) {
355355

356356
@Override
357357
public boolean elementExists(Object element) {
358+
throwLazyInitializationExceptionIfNotConnected();
358359
final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( this );
359360
if ( entry == null ) {
360-
throwLazyInitializationExceptionIfNotConnected();
361361
throwLazyInitializationException("collection not associated with session");
362362
throw new AssertionFailure("impossible");
363363
}
@@ -409,9 +409,9 @@ public Object doWork() {
409409

410410
@Override
411411
public Object elementByIndex(Object index) {
412+
throwLazyInitializationExceptionIfNotConnected();
412413
final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( this );
413414
if ( entry == null ) {
414-
throwLazyInitializationExceptionIfNotConnected();
415415
throwLazyInitializationException("collection not associated with session");
416416
throw new AssertionFailure("impossible");
417417
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.collection.basic;
6+
7+
8+
import jakarta.persistence.Entity;
9+
import jakarta.persistence.Id;
10+
import jakarta.persistence.ManyToOne;
11+
import jakarta.persistence.OneToMany;
12+
import org.hibernate.Hibernate;
13+
import org.hibernate.LazyInitializationException;
14+
import org.hibernate.dialect.H2Dialect;
15+
import org.hibernate.testing.orm.junit.DomainModel;
16+
import org.hibernate.testing.orm.junit.RequiresDialect;
17+
import org.hibernate.testing.orm.junit.SessionFactory;
18+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
19+
import org.junit.jupiter.api.Test;
20+
21+
import java.util.ArrayList;
22+
import java.util.HashMap;
23+
import java.util.List;
24+
import java.util.Map;
25+
26+
import static org.junit.jupiter.api.Assertions.*;
27+
28+
29+
/**
30+
* @author Jan Schatteman
31+
*/
32+
@DomainModel(
33+
annotatedClasses = {DetachedElementTest.EntityWithList.class, DetachedElementTest.ListElement.class,
34+
DetachedElementTest.EntityWithMap.class, DetachedElementTest.MapElement.class}
35+
)
36+
@SessionFactory
37+
@RequiresDialect( H2Dialect.class )
38+
public class DetachedElementTest {
39+
40+
@Test
41+
public void testList(SessionFactoryScope scope) {
42+
scope.inSession(
43+
session -> {
44+
session.getTransaction().begin();
45+
EntityWithList parent = new EntityWithList(1);
46+
ListElement element = new ListElement(2, parent);
47+
session.persist( parent );
48+
session.persist( element );
49+
session.getTransaction().commit();
50+
session.clear();
51+
52+
// shouldn't throw exceptions for these operations
53+
assertEquals( 1, parent.children.size() );
54+
assertFalse( parent.children.isEmpty() );
55+
assertTrue( parent.children.contains(element) );
56+
assertTrue( parent.children.remove(element) );
57+
58+
assertThrows( LazyInitializationException.class,
59+
() -> Hibernate.get(parent.children, 0)
60+
);
61+
}
62+
);
63+
}
64+
65+
@Test
66+
public void testMap(SessionFactoryScope scope) {
67+
scope.inSession(
68+
session -> {
69+
session.getTransaction().begin();
70+
EntityWithMap parent = new EntityWithMap(1);
71+
MapElement element = new MapElement(2, parent);
72+
session.persist(parent);
73+
session.persist(element);
74+
session.getTransaction().commit();
75+
session.clear();
76+
77+
// shouldn't throw exceptions for these operations
78+
assertEquals( 1, parent.children.size() );
79+
assertFalse( parent.children.isEmpty() );
80+
assertTrue( parent.children.containsKey(element.id) );
81+
assertTrue( parent.children.containsValue(element) );
82+
83+
assertThrows( LazyInitializationException.class,
84+
() -> Hibernate.get(parent.children, 2L)
85+
);
86+
}
87+
);
88+
}
89+
90+
@Entity
91+
public static class EntityWithList {
92+
@Id
93+
long id;
94+
95+
@OneToMany(mappedBy = "parent")
96+
List<ListElement> children = new ArrayList<>();
97+
98+
public EntityWithList(int id) {
99+
this.id = id;
100+
}
101+
102+
protected EntityWithList() {}
103+
}
104+
105+
@Entity
106+
public static class ListElement {
107+
@Id
108+
long id;
109+
110+
@ManyToOne
111+
private EntityWithList parent;
112+
113+
public ListElement(long id, EntityWithList parent) {
114+
this.id = id;
115+
this.parent = parent;
116+
parent.children.add(this);
117+
}
118+
119+
protected ListElement() {}
120+
}
121+
122+
@Entity
123+
public static class EntityWithMap {
124+
@Id
125+
long id;
126+
127+
@OneToMany(mappedBy = "parent")
128+
Map<Long, MapElement> children = new HashMap<>();
129+
130+
public EntityWithMap(int id) {
131+
this.id = id;
132+
}
133+
134+
protected EntityWithMap() {}
135+
}
136+
137+
@Entity
138+
public static class MapElement {
139+
@Id
140+
long id;
141+
142+
@ManyToOne
143+
private EntityWithMap parent;
144+
145+
public MapElement(long id, EntityWithMap parent) {
146+
this.id = id;
147+
this.parent = parent;
148+
parent.children.put(id, this);
149+
}
150+
151+
protected MapElement() {}
152+
}
153+
154+
}

0 commit comments

Comments
 (0)