diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java index fc6259bc7f8a..eef3c3edef3d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java @@ -1627,12 +1627,30 @@ public void bindConcreteProxy() { } public void bindWhere() { - final SQLRestriction restriction = getOverridableAnnotation( annotatedClass, SQLRestriction.class, context ); + final SQLRestriction restriction = extractSQLRestriction( annotatedClass, context ); if ( restriction != null ) { this.where = restriction.value(); } } + private static SQLRestriction extractSQLRestriction(ClassDetails classDetails, MetadataBuildingContext context) { + final SourceModelBuildingContext sourceModelContext = context.getMetadataCollector().getSourceModelBuildingContext(); + final SQLRestriction fromClass = getOverridableAnnotation( classDetails, SQLRestriction.class, context ); + if ( fromClass != null ) { + return fromClass; + } + ClassDetails classToCheck = classDetails.getSuperClass(); + while ( classToCheck != null ) { + final SQLRestriction fromSuper = getOverridableAnnotation( classToCheck, SQLRestriction.class, context ); + if ( fromSuper != null + && classToCheck.hasAnnotationUsage( jakarta.persistence.MappedSuperclass.class, sourceModelContext )) { + return fromSuper; + } + classToCheck = classToCheck.getSuperClass(); + } + return null; + } + public void setWrapIdsInEmbeddedComponents(boolean wrapIdsInEmbeddedComponents) { this.wrapIdsInEmbeddedComponents = wrapIdsInEmbeddedComponents; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/customsql/CustomSqlRestrictionOverridesTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/customsql/CustomSqlRestrictionOverridesTest.java index 18d16f011963..40b8ab4933d1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/customsql/CustomSqlRestrictionOverridesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/customsql/CustomSqlRestrictionOverridesTest.java @@ -27,6 +27,7 @@ import java.security.NoSuchAlgorithmException; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; @SessionFactory @DomainModel(annotatedClasses = CustomSqlRestrictionOverridesTest.Secure.class) @@ -39,12 +40,18 @@ public class CustomSqlRestrictionOverridesTest { @Test public void testCustomSql(SessionFactoryScope scope) throws NoSuchAlgorithmException { - Secure sec = new Secure(); - sec.hash = MessageDigest.getInstance( "SHA-256" ).digest("hello".getBytes()); - scope.inTransaction(s -> s.persist(sec) ); - Secure secure = scope.fromTransaction( s -> s.find( Secure.class, sec.id ) ); - assertNotNull(secure); + Secure sec1 = new Secure(); + sec1.hash = MessageDigest.getInstance( "SHA-256" ).digest( "hello".getBytes() ); + scope.inTransaction( s -> s.persist( sec1 ) ); + Secure sec2 = new Secure(); + sec2.hash = MessageDigest.getInstance( "SHA-256" ).digest( "not hello".getBytes() ); + scope.inTransaction( s -> s.persist( sec2 ) ); + Secure secure1 = scope.fromTransaction( s -> s.find( Secure.class, sec1.id ) ); + assertNotNull( secure1 ); + Secure secure2 = scope.fromTransaction( s -> s.find( Secure.class, sec2.id ) ); + assertNull( secure2 ); } + @Entity @Table(name = "SecureTable") @DialectOverride.SQLRestriction(dialect = H2Dialect.class, @@ -60,7 +67,8 @@ public void testCustomSql(SessionFactoryScope scope) throws NoSuchAlgorithmExcep @DialectOverride.SQLRestriction(dialect = OracleDialect.class, override = @SQLRestriction("hash = standard_hash('hello', 'SHA256')")) static class Secure { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; byte[] hash; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/where/annotations/MappedSuperclassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/where/annotations/MappedSuperclassTest.java new file mode 100644 index 000000000000..b134eb4e45e6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/where/annotations/MappedSuperclassTest.java @@ -0,0 +1,94 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.where.annotations; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; +import org.hibernate.annotations.SQLRestriction; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +@Jpa( + annotatedClasses = { + MappedSuperclassTest.Child.class, + MappedSuperclassTest.SubClass.class + } +) +public class MappedSuperclassTest { + + @AfterEach + public void tearDown(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + entityManager.createQuery( "delete from SubClass" ).executeUpdate(); + entityManager.createQuery( "delete from Child" ).executeUpdate(); + } + ); + } + + @Test + public void testFindParent(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + Child child1 = new SubClass( 1L ); + child1.flag = true; + entityManager.persist( child1 ); + + Child child2 = new Child( 2L ); + child2.flag = false; + entityManager.persist( child2 ); + } + ); + scope.inTransaction( + entityManager -> { + List children = entityManager.createQuery( "select c from Child c", Child.class ) + .getResultList(); + assertThat( children.size() ).isEqualTo( 1 ); + } + ); + } + + @Entity(name = "Child") + public static class Child extends Intermediate { + @Id + private Long id; + + public Child() { + } + + public Child(long id) { + this.id = id; + } + } + + @Entity(name = "SubClass") + public static class SubClass extends Child { + public SubClass() { + } + + public SubClass(long id) { + super( id ); + } + } + + public static class Intermediate extends Parent { + } + + @MappedSuperclass + @SQLRestriction("flag = false") + public static class Parent { + public Parent() { + } + + boolean flag; + } +}