Skip to content

Commit c9aaa7f

Browse files
committed
HHH-19843 Get persister from session factory if session is not available
1 parent 8abad90 commit c9aaa7f

File tree

2 files changed

+127
-13
lines changed

2 files changed

+127
-13
lines changed

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

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.hibernate.boot.internal.ClassLoaderAccessImpl;
1515
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
1616
import org.hibernate.engine.spi.SessionFactoryImplementor;
17+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1718
import org.hibernate.event.spi.PreCollectionUpdateEvent;
1819
import org.hibernate.event.spi.PreCollectionUpdateEventListener;
1920
import org.hibernate.event.spi.PreDeleteEvent;
@@ -59,8 +60,9 @@ public class BeanValidationEventListener
5960
private Validator validator;
6061
private GroupsPerOperation groupsPerOperation;
6162

62-
public BeanValidationEventListener(
63-
ValidatorFactory factory, Map<String, Object> settings, ClassLoaderService classLoaderService) {
63+
private SessionFactoryImplementor sessionFactory;
64+
65+
public BeanValidationEventListener(ValidatorFactory factory, Map<String, Object> settings, ClassLoaderService classLoaderService) {
6466
traversableResolver = new HibernateTraversableResolver();
6567
validator = factory.usingContext()
6668
.traversableResolver( traversableResolver )
@@ -70,17 +72,15 @@ public BeanValidationEventListener(
7072

7173
@Override
7274
public void sessionFactoryCreated(SessionFactory factory) {
73-
SessionFactoryImplementor implementor = factory.unwrap( SessionFactoryImplementor.class );
74-
implementor
75-
.getMappingMetamodel()
76-
.forEachEntityDescriptor( entityPersister -> traversableResolver.addPersister( entityPersister, implementor ) );
75+
sessionFactory = factory.unwrap( SessionFactoryImplementor.class );
76+
sessionFactory.getMappingMetamodel()
77+
.forEachEntityDescriptor( entityPersister -> traversableResolver.addPersister( entityPersister, sessionFactory ) );
7778
}
7879

7980
public boolean onPreInsert(PreInsertEvent event) {
8081
validate(
8182
event.getEntity(),
8283
event.getPersister(),
83-
event.getFactory(),
8484
GroupsPerOperation.Operation.INSERT
8585
);
8686
return false;
@@ -90,7 +90,6 @@ public boolean onPreUpdate(PreUpdateEvent event) {
9090
validate(
9191
event.getEntity(),
9292
event.getPersister(),
93-
event.getFactory(),
9493
GroupsPerOperation.Operation.UPDATE
9594
);
9695
return false;
@@ -100,7 +99,6 @@ public boolean onPreDelete(PreDeleteEvent event) {
10099
validate(
101100
event.getEntity(),
102101
event.getPersister(),
103-
event.getFactory(),
104102
GroupsPerOperation.Operation.DELETE
105103
);
106104
return false;
@@ -111,7 +109,6 @@ public boolean onPreUpsert(PreUpsertEvent event) {
111109
validate(
112110
event.getEntity(),
113111
event.getPersister(),
114-
event.getFactory(),
115112
GroupsPerOperation.Operation.UPSERT
116113
);
117114
return false;
@@ -122,16 +119,24 @@ public void onPreUpdateCollection(PreCollectionUpdateEvent event) {
122119
final Object entity = castNonNull( event.getCollection().getOwner() );
123120
validate(
124121
entity,
125-
event.getSession().getEntityPersister( event.getAffectedOwnerEntityName(), entity ),
126-
event.getFactory(),
122+
getEntityPersister( event.getSession(), event.getAffectedOwnerEntityName(), entity ),
127123
GroupsPerOperation.Operation.UPDATE
128124
);
129125
}
130126

127+
private EntityPersister getEntityPersister(SharedSessionContractImplementor session, String entityName, Object entity) {
128+
if ( session != null ) {
129+
return session.getEntityPersister( entityName, entity );
130+
}
131+
return entityName == null
132+
? sessionFactory.getMappingMetamodel().getEntityDescriptor( entity.getClass().getName() )
133+
: sessionFactory.getMappingMetamodel().getEntityDescriptor( entityName )
134+
.getSubclassEntityPersister( entity, sessionFactory );
135+
}
136+
131137
private <T> void validate(
132138
T object,
133139
EntityPersister persister,
134-
SessionFactoryImplementor sessionFactory,
135140
GroupsPerOperation.Operation operation) {
136141
if ( object == null || persister.getRepresentationStrategy().getMode() != RepresentationMode.POJO ) {
137142
return;
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)