Skip to content

Commit 6ede95f

Browse files
marko-bekhtabeikov
authored andcommitted
HHH-17620 Allow configuring filters on a stateless session
1 parent 40a2b53 commit 6ede95f

21 files changed

+571
-415
lines changed

hibernate-core/src/main/java/org/hibernate/Session.java

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,37 +1260,13 @@ public interface Session extends SharedSessionContract, EntityManager {
12601260
*/
12611261
<T> NaturalIdMultiLoadAccess<T> byMultipleNaturalId(String entityName);
12621262

1263-
/**
1264-
* Enable the named {@linkplain Filter filter} for this current session.
1265-
* <p>
1266-
* The returned {@link Filter} object must be used to bind arguments
1267-
* to parameters of the filter, and every parameter must be set before
1268-
* any other operation of this session is called.
1269-
*
1270-
* @param filterName the name of the filter to be enabled.
1271-
*
1272-
* @return the {@link Filter} instance representing the enabled filter.
1273-
*
1274-
* @throws UnknownFilterException if there is no such filter
1275-
*
1276-
* @see org.hibernate.annotations.FilterDef
1277-
*/
1263+
@Override
12781264
Filter enableFilter(String filterName);
12791265

1280-
/**
1281-
* Retrieve a currently enabled {@linkplain Filter filter} by name.
1282-
*
1283-
* @param filterName the name of the filter to be retrieved.
1284-
*
1285-
* @return the {@link Filter} instance representing the enabled filter.
1286-
*/
1266+
@Override
12871267
Filter getEnabledFilter(String filterName);
12881268

1289-
/**
1290-
* Disable the named {@linkplain Filter filter} for the current session.
1291-
*
1292-
* @param filterName the name of the filter to be disabled.
1293-
*/
1269+
@Override
12941270
void disableFilter(String filterName);
12951271

12961272
/**

hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,39 @@ default <T> T doReturningWork(ReturningWork<T> work) throws HibernateException {
312312
*/
313313
<T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass);
314314

315+
/**
316+
* Enable the named {@linkplain Filter filter} for this current session.
317+
* <p>
318+
* The returned {@link Filter} object must be used to bind arguments
319+
* to parameters of the filter, and every parameter must be set before
320+
* any other operation of this session is called.
321+
*
322+
* @param filterName the name of the filter to be enabled.
323+
*
324+
* @return the {@link Filter} instance representing the enabled filter.
325+
*
326+
* @throws UnknownFilterException if there is no such filter
327+
*
328+
* @see org.hibernate.annotations.FilterDef
329+
*/
330+
Filter enableFilter(String filterName);
331+
332+
/**
333+
* Retrieve a currently enabled {@linkplain Filter filter} by name.
334+
*
335+
* @param filterName the name of the filter to be retrieved.
336+
*
337+
* @return the {@link Filter} instance representing the enabled filter.
338+
*/
339+
Filter getEnabledFilter(String filterName);
340+
341+
/**
342+
* Disable the named {@linkplain Filter filter} for the current session.
343+
*
344+
* @param filterName the name of the filter to be disabled.
345+
*/
346+
void disableFilter(String filterName);
347+
315348
/**
316349
* The factory which created this session.
317350
*/

hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.checkerframework.checker.nullness.qual.Nullable;
1515

1616
import org.hibernate.CacheMode;
17+
import org.hibernate.Filter;
1718
import org.hibernate.FlushMode;
1819
import org.hibernate.HibernateException;
1920
import org.hibernate.Interceptor;
@@ -651,4 +652,19 @@ public RootGraph<?> getEntityGraph(String graphName) {
651652
public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
652653
return delegate.getEntityGraphs( entityClass );
653654
}
655+
656+
@Override
657+
public Filter enableFilter(String filterName) {
658+
return delegate.enableFilter( filterName );
659+
}
660+
661+
@Override
662+
public Filter getEnabledFilter(String filterName) {
663+
return delegate.getEnabledFilter( filterName );
664+
}
665+
666+
@Override
667+
public void disableFilter(String filterName) {
668+
delegate.disableFilter( filterName );
669+
}
654670
}

hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import jakarta.persistence.EntityGraph;
2222
import org.hibernate.CacheMode;
2323
import org.hibernate.EntityNameResolver;
24+
import org.hibernate.Filter;
2425
import org.hibernate.FlushMode;
2526
import org.hibernate.HibernateException;
2627
import org.hibernate.Interceptor;
@@ -1491,6 +1492,28 @@ public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
14911492
return getFactory().findEntityGraphsByType( entityClass );
14921493
}
14931494

1495+
// filter support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1496+
1497+
@Override
1498+
public Filter getEnabledFilter(String filterName) {
1499+
pulseTransactionCoordinator();
1500+
return getLoadQueryInfluencers().getEnabledFilter( filterName );
1501+
}
1502+
1503+
@Override
1504+
public Filter enableFilter(String filterName) {
1505+
checkOpen();
1506+
pulseTransactionCoordinator();
1507+
return getLoadQueryInfluencers().enableFilter( filterName );
1508+
}
1509+
1510+
@Override
1511+
public void disableFilter(String filterName) {
1512+
checkOpen();
1513+
pulseTransactionCoordinator();
1514+
getLoadQueryInfluencers().disableFilter( filterName );
1515+
}
1516+
14941517
private void writeObject(ObjectOutputStream oos) throws IOException {
14951518
if ( log.isTraceEnabled() ) {
14961519
log.trace( "Serializing " + getClass().getSimpleName() + " [" );

hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,29 +1893,6 @@ public LoadQueryInfluencers getLoadQueryInfluencers() {
18931893
return loadQueryInfluencers;
18941894
}
18951895

1896-
// filter support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1897-
1898-
@Override
1899-
public Filter getEnabledFilter(String filterName) {
1900-
pulseTransactionCoordinator();
1901-
return loadQueryInfluencers.getEnabledFilter( filterName );
1902-
}
1903-
1904-
@Override
1905-
public Filter enableFilter(String filterName) {
1906-
checkOpen();
1907-
pulseTransactionCoordinator();
1908-
return loadQueryInfluencers.enableFilter( filterName );
1909-
}
1910-
1911-
@Override
1912-
public void disableFilter(String filterName) {
1913-
checkOpen();
1914-
pulseTransactionCoordinator();
1915-
loadQueryInfluencers.disableFilter( filterName );
1916-
}
1917-
1918-
19191896
// fetch profile support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19201897

19211898
@Override
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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.orm.test.filter;
8+
9+
import java.util.List;
10+
import java.util.function.BiConsumer;
11+
import java.util.function.Consumer;
12+
13+
import org.hibernate.StatelessSession;
14+
import org.hibernate.engine.spi.SessionImplementor;
15+
16+
import org.hibernate.testing.orm.junit.SessionFactory;
17+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
18+
import org.hibernate.testing.orm.junit.SessionFactoryScopeAware;
19+
import org.junit.jupiter.params.provider.Arguments;
20+
21+
@SessionFactory
22+
public abstract class AbstractStatefulStatelessFilterTest implements SessionFactoryScopeAware {
23+
24+
protected SessionFactoryScope scope;
25+
26+
@Override
27+
public void injectSessionFactoryScope(SessionFactoryScope scope) {
28+
this.scope = scope;
29+
}
30+
31+
protected List<? extends Arguments> transactionKind() {
32+
// We want to test both regular and stateless session:
33+
BiConsumer<SessionFactoryScope, Consumer<SessionImplementor>> kind1 = SessionFactoryScope::inTransaction;
34+
BiConsumer<SessionFactoryScope, Consumer<StatelessSession>> kind2 = SessionFactoryScope::inStatelessTransaction;
35+
return List.of(
36+
Arguments.of( kind1 ),
37+
Arguments.of( kind2 )
38+
);
39+
}
40+
}

hibernate-core/src/test/java/org/hibernate/orm/test/filter/CriteriaQueryWithAppliedFilterTest.java

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
import java.io.Serializable;
1010
import java.util.List;
11+
import java.util.function.BiConsumer;
12+
import java.util.function.Consumer;
13+
1114
import jakarta.persistence.Column;
1215
import jakarta.persistence.Embeddable;
1316
import jakarta.persistence.Embedded;
@@ -19,6 +22,7 @@
1922
import jakarta.persistence.criteria.Root;
2023
import jakarta.persistence.criteria.Subquery;
2124

25+
import org.hibernate.SharedSessionContract;
2226
import org.hibernate.annotations.Filter;
2327
import org.hibernate.annotations.FilterDef;
2428
import org.hibernate.annotations.ParamDef;
@@ -29,7 +33,8 @@
2933
import org.hibernate.testing.orm.junit.SessionFactoryScope;
3034
import org.junit.jupiter.api.AfterEach;
3135
import org.junit.jupiter.api.BeforeEach;
32-
import org.junit.jupiter.api.Test;
36+
import org.junit.jupiter.params.ParameterizedTest;
37+
import org.junit.jupiter.params.provider.MethodSource;
3338

3439
import static org.hamcrest.core.Is.is;
3540
import static org.junit.Assert.assertThat;
@@ -44,12 +49,12 @@
4449
)
4550
@SessionFactory
4651
@TestForIssue(jiraKey = "HHH-10991")
47-
public class CriteriaQueryWithAppliedFilterTest {
52+
public class CriteriaQueryWithAppliedFilterTest extends AbstractStatefulStatelessFilterTest {
4853

4954
private final static Identifier STUDENT_ID = new Identifier( 2, new Identifier2( 4, 5L ) );
5055

5156
@BeforeEach
52-
void setUP(SessionFactoryScope scope) {
57+
void setUP() {
5358
scope.inTransaction( session -> {
5459
final Student student = new Student();
5560
student.setId( STUDENT_ID );
@@ -70,20 +75,21 @@ void setUP(SessionFactoryScope scope) {
7075
}
7176

7277
@AfterEach
73-
void tearDown(SessionFactoryScope scope) {
78+
void tearDown() {
7479
scope.inTransaction( session -> session.createQuery( "delete from Student" ).executeUpdate() );
7580
}
7681

77-
@Test
78-
void testSubquery(SessionFactoryScope scope) {
82+
@ParameterizedTest
83+
@MethodSource("transactionKind")
84+
void testSubquery(BiConsumer<SessionFactoryScope, Consumer<? extends SharedSessionContract>> inTransaction) {
7985
final CriteriaBuilder detachedCriteriaBuilder = scope.getSessionFactory().getCriteriaBuilder();
8086
final CriteriaQuery<Student> criteria = detachedCriteriaBuilder.createQuery( Student.class );
8187
criteria.from( Student.class );
8288
final Subquery<Integer> subquery = criteria.subquery( Integer.class );
8389
final Root<Student> studentRoot = subquery.from( Student.class );
8490
subquery.select( detachedCriteriaBuilder.min( studentRoot.get( "age" ) ));
8591

86-
scope.inTransaction( session -> {
92+
inTransaction.accept( scope, session -> {
8793
final CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
8894
final CriteriaQuery<Student> query = criteriaBuilder.createQuery( Student.class );
8995
final Root<Student> root = query.from( Student.class );
@@ -130,8 +136,9 @@ void testSubquery(SessionFactoryScope scope) {
130136
});
131137
}
132138

133-
@Test
134-
void testSubqueryWithRestrictionsOnComponentTypes(SessionFactoryScope scope) {
139+
@ParameterizedTest
140+
@MethodSource("transactionKind")
141+
void testSubqueryWithRestrictionsOnComponentTypes(BiConsumer<SessionFactoryScope, Consumer<? extends SharedSessionContract>> inTransaction) {
135142
final CriteriaBuilder detachedCriteriaBuilder = scope.getSessionFactory().getCriteriaBuilder();
136143
final CriteriaQuery<Student> criteria = detachedCriteriaBuilder.createQuery( Student.class );
137144
criteria.from( Student.class );
@@ -140,7 +147,7 @@ void testSubqueryWithRestrictionsOnComponentTypes(SessionFactoryScope scope) {
140147
subquery.select( detachedCriteriaBuilder.max( studentRoot.get( "age" ) ) );
141148
subquery.where( detachedCriteriaBuilder.equal( studentRoot.get( "id" ), STUDENT_ID ) );
142149

143-
scope.inTransaction( session -> {
150+
inTransaction.accept( scope, session -> {
144151
session.enableFilter( "statusFilter" ).setParameter( "status", "active" );
145152

146153
// final Criteria query = session.createCriteria( Student.class );
@@ -168,8 +175,9 @@ void testSubqueryWithRestrictionsOnComponentTypes(SessionFactoryScope scope) {
168175
});
169176
}
170177

171-
@Test
172-
void testSubqueryWithRestrictionsOnComponentTypes2(SessionFactoryScope scope) {
178+
@ParameterizedTest
179+
@MethodSource("transactionKind")
180+
void testSubqueryWithRestrictionsOnComponentTypes2(BiConsumer<SessionFactoryScope, Consumer<? extends SharedSessionContract>> inTransaction) {
173181
final CriteriaBuilder detachedCriteriaBuilder = scope.getSessionFactory().getCriteriaBuilder();
174182
final CriteriaQuery<Student> criteria = detachedCriteriaBuilder.createQuery( Student.class );
175183
criteria.from( Student.class );
@@ -183,7 +191,7 @@ void testSubqueryWithRestrictionsOnComponentTypes2(SessionFactoryScope scope) {
183191
)
184192
);
185193

186-
scope.inTransaction( session -> {
194+
inTransaction.accept( scope, session -> {
187195
session.enableFilter( "statusFilter" ).setParameter( "status", "active" );
188196

189197
// final Criteria query = session.createCriteria( Student.class );
@@ -212,9 +220,10 @@ void testSubqueryWithRestrictionsOnComponentTypes2(SessionFactoryScope scope) {
212220
});
213221
}
214222

215-
@Test
216-
void testRestrictionsOnComponentTypes(SessionFactoryScope scope) {
217-
scope.inTransaction( session -> {
223+
@ParameterizedTest
224+
@MethodSource("transactionKind")
225+
void testRestrictionsOnComponentTypes(BiConsumer<SessionFactoryScope, Consumer<? extends SharedSessionContract>> inTransaction) {
226+
inTransaction.accept( scope, session -> {
218227
session.enableFilter( "statusFilter" ).setParameter( "status", "active" );
219228

220229
// final Criteria query = session.createCriteria( Student.class );

0 commit comments

Comments
 (0)