Skip to content

Commit ebed130

Browse files
committed
HHH-19843 Get persister from session factory if session is not available
1 parent f79de81 commit ebed130

File tree

2 files changed

+127
-6
lines changed

2 files changed

+127
-6
lines changed

hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/BeanValidationEventListener.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.hibernate.boot.internal.ClassLoaderAccessImpl;
1414
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
1515
import org.hibernate.engine.spi.SessionFactoryImplementor;
16+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1617
import org.hibernate.event.spi.PreCollectionUpdateEvent;
1718
import org.hibernate.event.spi.PreCollectionUpdateEventListener;
1819
import org.hibernate.event.spi.PreDeleteEvent;
@@ -51,8 +52,9 @@ public class BeanValidationEventListener
5152
private final Validator validator;
5253
private final GroupsPerOperation groupsPerOperation;
5354

54-
public BeanValidationEventListener(
55-
ValidatorFactory factory, Map<String, Object> settings, ClassLoaderService classLoaderService) {
55+
private SessionFactoryImplementor sessionFactory;
56+
57+
public BeanValidationEventListener(ValidatorFactory factory, Map<String, Object> settings, ClassLoaderService classLoaderService) {
5658
traversableResolver = new HibernateTraversableResolver();
5759
validator =
5860
factory.usingContext()
@@ -63,9 +65,9 @@ public BeanValidationEventListener(
6365

6466
@Override
6567
public void sessionFactoryCreated(SessionFactory factory) {
66-
var implementor = factory.unwrap( SessionFactoryImplementor.class );
67-
implementor.getMappingMetamodel()
68-
.forEachEntityDescriptor( entityPersister -> traversableResolver.addPersister( entityPersister, implementor ) );
68+
sessionFactory = factory.unwrap( SessionFactoryImplementor.class );
69+
sessionFactory.getMappingMetamodel()
70+
.forEachEntityDescriptor( entityPersister -> traversableResolver.addPersister( entityPersister, sessionFactory ) );
6971
}
7072

7173
public boolean onPreInsert(PreInsertEvent event) {
@@ -110,11 +112,21 @@ public void onPreUpdateCollection(PreCollectionUpdateEvent event) {
110112
final Object entity = castNonNull( event.getCollection().getOwner() );
111113
validate(
112114
entity,
113-
event.getSession().getEntityPersister( event.getAffectedOwnerEntityName(), entity ),
115+
getEntityPersister( event.getSession(), event.getAffectedOwnerEntityName(), entity ),
114116
GroupsPerOperation.Operation.UPDATE
115117
);
116118
}
117119

120+
private EntityPersister getEntityPersister(SharedSessionContractImplementor session, String entityName, Object entity) {
121+
if ( session != null ) {
122+
return session.getEntityPersister( entityName, entity );
123+
}
124+
return entityName == null
125+
? sessionFactory.getMappingMetamodel().getEntityDescriptor( entity.getClass().getName() )
126+
: sessionFactory.getMappingMetamodel().getEntityDescriptor( entityName )
127+
.getSubclassEntityPersister( entity, sessionFactory );
128+
}
129+
118130
private <T> void validate(
119131
T object,
120132
EntityPersister persister,
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.annotations.beanvalidation;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.Id;
9+
import jakarta.persistence.JoinColumn;
10+
import jakarta.persistence.ManyToOne;
11+
import jakarta.persistence.OneToMany;
12+
import jakarta.persistence.Table;
13+
import jakarta.validation.ConstraintViolationException;
14+
import jakarta.validation.constraints.Size;
15+
import org.hibernate.cfg.AvailableSettings;
16+
import org.hibernate.testing.orm.junit.DomainModel;
17+
import org.hibernate.testing.orm.junit.Jira;
18+
import org.hibernate.testing.orm.junit.ServiceRegistry;
19+
import org.hibernate.testing.orm.junit.SessionFactory;
20+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
21+
import org.hibernate.testing.orm.junit.Setting;
22+
import org.junit.jupiter.api.AfterEach;
23+
import org.junit.jupiter.api.Test;
24+
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
import static org.junit.jupiter.api.Assertions.assertThrows;
30+
31+
@SessionFactory
32+
@DomainModel(annotatedClasses = {
33+
CollectionActionsValidationStatelessTest.Author.class,
34+
CollectionActionsValidationStatelessTest.Book.class,
35+
})
36+
@ServiceRegistry(settings = @Setting(name = AvailableSettings.JAKARTA_VALIDATION_MODE, value = "auto"))
37+
@Jira("https://hibernate.atlassian.net/browse/HHH-19843")
38+
public class CollectionActionsValidationStatelessTest {
39+
40+
@Test
41+
void smoke(SessionFactoryScope scope) {
42+
scope.inStatelessTransaction( session -> {
43+
final ConstraintViolationException e = assertThrows( ConstraintViolationException.class, () -> {
44+
ArrayList<Book> books = new ArrayList<>();
45+
Author author = new Author( 1L, "first", "last", books );
46+
Book book = new Book( 10L, "", author );
47+
books.add( book );
48+
49+
session.upsertMultiple( List.of( author ) );
50+
} );
51+
assertThat( e.getConstraintViolations() ).hasSize( 1 );
52+
} );
53+
}
54+
55+
@AfterEach
56+
public void tearDown(SessionFactoryScope scope) {
57+
scope.getSessionFactory().getSchemaManager().truncate();
58+
}
59+
60+
@Table(name = "author")
61+
@Entity
62+
static class Author {
63+
64+
public Author() {
65+
}
66+
67+
public Author(long id, String firstName, String lastName, List<Book> books) {
68+
this.firstName = firstName;
69+
this.lastName = lastName;
70+
this.books = books;
71+
this.id = id;
72+
}
73+
74+
@Id
75+
Long id;
76+
77+
String firstName;
78+
79+
String lastName;
80+
81+
@OneToMany
82+
@JoinColumn(name = "bookId")
83+
@Size(min = 10)
84+
List<Book> books;
85+
86+
}
87+
88+
@Table(name = "book")
89+
@Entity
90+
static class Book {
91+
92+
public Book() {
93+
}
94+
95+
public Book(long id, String title, Author author) {
96+
this.id = id;
97+
this.title = title;
98+
this.author = author;
99+
}
100+
101+
@Id
102+
Long id;
103+
104+
String title;
105+
106+
@ManyToOne
107+
Author author;
108+
}
109+
}

0 commit comments

Comments
 (0)