Skip to content

Commit 9fb8de1

Browse files
codebase/hibernate-stateless-session [BAEL-8322] (#18778)
* add domain entities * add main application entry * add test cases * explicitly enable cascade and lazy loading * improve indentation * add test cases for dirty checking * add test case for loading association eagerly using EntityGraph * refactor: update variable name
1 parent 866b692 commit 9fb8de1

File tree

4 files changed

+359
-0
lines changed

4 files changed

+359
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.baeldung.statelesssession;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
class Application {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(Application.class, args);
11+
}
12+
13+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.baeldung.statelesssession;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.FetchType;
6+
import jakarta.persistence.GeneratedValue;
7+
import jakarta.persistence.GenerationType;
8+
import jakarta.persistence.Id;
9+
import jakarta.persistence.JoinColumn;
10+
import jakarta.persistence.ManyToOne;
11+
import jakarta.persistence.Table;
12+
13+
@Entity
14+
@Table(name = "articles")
15+
class Article {
16+
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
19+
private Long id;
20+
21+
@Column(nullable = false)
22+
private String title;
23+
24+
@ManyToOne(fetch = FetchType.LAZY)
25+
@JoinColumn(name = "author_id", nullable = false)
26+
private Author author;
27+
28+
public Long getId() {
29+
return id;
30+
}
31+
32+
public String getTitle() {
33+
return title;
34+
}
35+
36+
public void setTitle(String title) {
37+
this.title = title;
38+
}
39+
40+
public Author getAuthor() {
41+
return author;
42+
}
43+
44+
public void setAuthor(Author author) {
45+
this.author = author;
46+
}
47+
48+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.baeldung.statelesssession;
2+
3+
import jakarta.persistence.CascadeType;
4+
import jakarta.persistence.Column;
5+
import jakarta.persistence.Entity;
6+
import jakarta.persistence.FetchType;
7+
import jakarta.persistence.GeneratedValue;
8+
import jakarta.persistence.GenerationType;
9+
import jakarta.persistence.Id;
10+
import jakarta.persistence.OneToMany;
11+
import jakarta.persistence.Table;
12+
13+
import java.util.List;
14+
15+
@Entity
16+
@Table(name = "authors")
17+
class Author {
18+
19+
@Id
20+
@GeneratedValue(strategy = GenerationType.IDENTITY)
21+
private Long id;
22+
23+
@Column(nullable = false)
24+
private String name;
25+
26+
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
27+
private List<Article> articles;
28+
29+
public Long getId() {
30+
return id;
31+
}
32+
33+
public String getName() {
34+
return name;
35+
}
36+
37+
public void setName(String name) {
38+
this.name = name;
39+
}
40+
41+
public List<Article> getArticles() {
42+
return articles;
43+
}
44+
45+
public void setArticles(List<Article> articles) {
46+
this.articles = articles;
47+
}
48+
49+
}
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
package com.baeldung.statelesssession;
2+
3+
import jakarta.persistence.EntityGraph;
4+
import jakarta.persistence.EntityManagerFactory;
5+
import net.bytebuddy.utility.RandomString;
6+
import org.hibernate.LazyInitializationException;
7+
import org.hibernate.SessionFactory;
8+
import org.hibernate.StatelessSession;
9+
import org.hibernate.TransientObjectException;
10+
import org.junit.jupiter.api.Test;
11+
import org.springframework.beans.factory.annotation.Autowired;
12+
import org.springframework.boot.test.context.SpringBootTest;
13+
14+
import static org.assertj.core.api.Assertions.assertThat;
15+
import static org.junit.jupiter.api.Assertions.assertThrows;
16+
17+
@SpringBootTest(classes = Application.class)
18+
class StatelessSessionIntegrationTest {
19+
20+
@Autowired
21+
private EntityManagerFactory entityManagerFactory;
22+
23+
@Test
24+
void whenInsertingEntityWithUnsavedReference_thenTransientObjectExceptionThrown() {
25+
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
26+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
27+
Author author = new Author();
28+
author.setName(RandomString.make());
29+
30+
Article article = new Article();
31+
article.setTitle(RandomString.make());
32+
article.setAuthor(author);
33+
34+
Exception exception = assertThrows(TransientObjectException.class, () -> {
35+
statelessSession.insert(article);
36+
});
37+
assertThat(exception.getMessage())
38+
.contains("object references an unsaved transient instance - save the transient instance before flushing");
39+
}
40+
}
41+
42+
@Test
43+
void whenInsertingEntitiesInsideTransaction_thenEntitiesSavedSuccessfully() {
44+
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
45+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
46+
statelessSession.getTransaction().begin();
47+
48+
Author author = new Author();
49+
author.setName(RandomString.make());
50+
statelessSession.insert(author);
51+
52+
Article article = new Article();
53+
article.setTitle(RandomString.make());
54+
article.setAuthor(author);
55+
statelessSession.insert(article);
56+
57+
statelessSession.getTransaction().commit();
58+
59+
assertThat(author.getId())
60+
.isNotNull();
61+
assertThat(article.getId())
62+
.isNotNull();
63+
assertThat(article.getAuthor())
64+
.isEqualTo(author);
65+
}
66+
}
67+
68+
@Test
69+
void whenCollectionAccessedLazily_thenLazyInitializationExceptionThrown() {
70+
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
71+
Long authorId;
72+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
73+
statelessSession.getTransaction().begin();
74+
75+
Author author = new Author();
76+
author.setName(RandomString.make());
77+
statelessSession.insert(author);
78+
79+
Article article = new Article();
80+
article.setTitle(RandomString.make());
81+
article.setAuthor(author);
82+
statelessSession.insert(article);
83+
84+
statelessSession.getTransaction().commit();
85+
authorId = author.getId();
86+
}
87+
88+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
89+
Author author = statelessSession.get(Author.class, authorId);
90+
assertThat(author)
91+
.hasNoNullFieldsOrProperties();
92+
assertThrows(LazyInitializationException.class, () -> {
93+
author.getArticles().size();
94+
});
95+
}
96+
}
97+
98+
@Test
99+
void whenRelatedEntityFetchedUsingJoin_thenCollectionLoadedEagerly() {
100+
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
101+
Long authorId;
102+
103+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
104+
statelessSession.getTransaction().begin();
105+
106+
Author author = new Author();
107+
author.setName(RandomString.make());
108+
statelessSession.insert(author);
109+
110+
Article article = new Article();
111+
article.setTitle(RandomString.make());
112+
article.setAuthor(author);
113+
statelessSession.insert(article);
114+
115+
statelessSession.getTransaction().commit();
116+
authorId = author.getId();
117+
}
118+
119+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
120+
Author author = statelessSession
121+
.createQuery(
122+
"SELECT a FROM Author a LEFT JOIN FETCH a.articles WHERE a.id = :id",
123+
Author.class)
124+
.setParameter("id", authorId)
125+
.getSingleResult();
126+
127+
assertThat(author)
128+
.hasNoNullFieldsOrProperties();
129+
assertThat(author.getArticles())
130+
.isNotNull()
131+
.hasSize(1);
132+
}
133+
}
134+
135+
@Test
136+
void whenRelatedEntityFetchedUsingEntityGraph_thenCollectionLoadedEagerly() {
137+
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
138+
Long authorId;
139+
140+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
141+
statelessSession.getTransaction().begin();
142+
143+
Author author = new Author();
144+
author.setName(RandomString.make());
145+
statelessSession.insert(author);
146+
147+
Article article = new Article();
148+
article.setTitle(RandomString.make());
149+
article.setAuthor(author);
150+
statelessSession.insert(article);
151+
152+
statelessSession.getTransaction().commit();
153+
authorId = author.getId();
154+
}
155+
156+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
157+
EntityGraph<Author> authorWithArticlesGraph = statelessSession.createEntityGraph(Author.class);
158+
authorWithArticlesGraph.addAttributeNodes("articles");
159+
160+
Author author = statelessSession
161+
.createQuery("SELECT a FROM Author a WHERE a.id = :id", Author.class)
162+
.setParameter("id", authorId)
163+
.setHint("jakarta.persistence.fetchgraph", authorWithArticlesGraph)
164+
.getSingleResult();
165+
166+
assertThat(author)
167+
.hasNoNullFieldsOrProperties();
168+
assertThat(author.getArticles())
169+
.isNotNull()
170+
.hasSize(1);
171+
}
172+
}
173+
174+
@Test
175+
void whenSameEntityRetrievedMultipleTimes_thenDifferentInstancesReturned() {
176+
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
177+
Long authorId;
178+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
179+
statelessSession.getTransaction().begin();
180+
181+
Author author = new Author();
182+
author.setName(RandomString.make());
183+
statelessSession.insert(author);
184+
185+
statelessSession.getTransaction().commit();
186+
authorId = author.getId();
187+
}
188+
189+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
190+
Author author1 = statelessSession.get(Author.class, authorId);
191+
Author author2 = statelessSession.get(Author.class, authorId);
192+
193+
assertThat(author1)
194+
.isNotSameAs(author2);
195+
}
196+
}
197+
198+
@Test
199+
void whenEntityModifiedInStatelessSession_thenChangesNotAutomaticallyPersisted() {
200+
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
201+
Long authorId;
202+
String originalName = RandomString.make();
203+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
204+
statelessSession.getTransaction().begin();
205+
206+
Author author = new Author();
207+
author.setName(originalName);
208+
statelessSession.insert(author);
209+
210+
author.setName(RandomString.make());
211+
212+
statelessSession.getTransaction().commit();
213+
authorId = author.getId();
214+
}
215+
216+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
217+
Author author = statelessSession.get(Author.class, authorId);
218+
assertThat(author.getName())
219+
.isEqualTo(originalName);
220+
}
221+
}
222+
223+
@Test
224+
void whenEntityExplicitlyUpdated_thenChangesPersisted() {
225+
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
226+
Long authorId;
227+
String newName = RandomString.make();
228+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
229+
statelessSession.getTransaction().begin();
230+
231+
Author author = new Author();
232+
author.setName(RandomString.make());
233+
statelessSession.insert(author);
234+
235+
author.setName(newName);
236+
statelessSession.update(author);
237+
238+
statelessSession.getTransaction().commit();
239+
authorId = author.getId();
240+
}
241+
242+
try (StatelessSession statelessSession = sessionFactory.openStatelessSession()) {
243+
Author author = statelessSession.get(Author.class, authorId);
244+
assertThat(author.getName())
245+
.isEqualTo(newName);
246+
}
247+
}
248+
249+
}

0 commit comments

Comments
 (0)