diff --git a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/BaseMappedSuperclass.java b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/BaseMappedSuperclass.java new file mode 100644 index 000000000000..a783d6558811 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/BaseMappedSuperclass.java @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.bytecode.internal.bytebuddy; + +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; + +@MappedSuperclass +public abstract class BaseMappedSuperclass { + @Id + protected Long id; + protected String value; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/GenerateProxiesTest.java b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/GenerateProxiesTest.java index a1ae08fe2c86..16f89f7ea08e 100644 --- a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/GenerateProxiesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/GenerateProxiesTest.java @@ -4,24 +4,11 @@ */ package org.hibernate.bytecode.internal.bytebuddy; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import java.util.LinkedHashMap; -import java.util.Map; -import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl; -import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext; -import org.hibernate.bytecode.enhance.spi.EnhancementException; -import org.hibernate.bytecode.enhance.spi.Enhancer; -import org.hibernate.bytecode.spi.ByteCodeHelper; -import org.hibernate.bytecode.spi.ReflectionOptimizer; -import org.hibernate.property.access.internal.PropertyAccessStrategyFieldImpl; -import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyHelper; -import org.hibernate.testing.orm.junit.JiraKey; import org.junit.Test; public class GenerateProxiesTest { @@ -41,45 +28,4 @@ public void generateProxy() throws InstantiationException, IllegalAccessExceptio assertNotNull( proxyClass ); assertNotNull( proxyClass.getConstructor().newInstance() ); } - - @Test - public void generateFastClassAndReflectionOptimizer() { - BytecodeProviderImpl bytecodeProvider = new BytecodeProviderImpl(); - ReflectionOptimizer reflectionOptimizer = bytecodeProvider.getReflectionOptimizer( SimpleEntity.class, - new String[]{ "getId", "getName" }, new String[]{ "setId", "setName" }, - new Class[]{ Long.class, String.class } ); - assertEquals( 2, reflectionOptimizer.getAccessOptimizer().getPropertyNames().length ); - assertNotNull( reflectionOptimizer.getInstantiationOptimizer().newInstance() ); - } - - @Test - @JiraKey("HHH-16772") - public void generateFastMappedSuperclassAndReflectionOptimizer() { - BytecodeProviderImpl bytecodeProvider = new BytecodeProviderImpl(); - final Map propertyAccessMap = new LinkedHashMap<>(); - - final PropertyAccessStrategyFieldImpl propertyAccessStrategy = new PropertyAccessStrategyFieldImpl(); - - propertyAccessMap.put( - "timestamp", - propertyAccessStrategy.buildPropertyAccess(MappedSuperclassEntity.class, "value", true ) - ); - - ReflectionOptimizer reflectionOptimizer = bytecodeProvider.getReflectionOptimizer( - MappedSuperclassEntity.class, - propertyAccessMap - ); - - assertNotNull(reflectionOptimizer); - assertEquals( 1, reflectionOptimizer.getAccessOptimizer().getPropertyNames().length ); - assertNotNull( reflectionOptimizer.getInstantiationOptimizer().newInstance() ); - } - - @Test - public void generateEnhancedClass() throws EnhancementException, IOException { - Enhancer enhancer = new EnhancerImpl( new DefaultEnhancementContext(), new ByteBuddyState() ); - enhancer.enhance( SimpleEntity.class.getName(), - ByteCodeHelper.readByteCode( SimpleEntity.class.getClassLoader() - .getResourceAsStream( SimpleEntity.class.getName().replace( '.', '/' ) + ".class" ) ) ); - } } diff --git a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/MappedSuperclassEntity.java b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/MappedSuperclassEntity.java index 3a93ed58b9ff..5e1b76caa3f2 100644 --- a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/MappedSuperclassEntity.java +++ b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/MappedSuperclassEntity.java @@ -5,7 +5,6 @@ package org.hibernate.bytecode.internal.bytebuddy; import jakarta.persistence.Entity; -import org.hibernate.bytecode.internal.bytebuddy.mappedsuperclass.BaseMappedSuperclass; @Entity public class MappedSuperclassEntity extends BaseMappedSuperclass { diff --git a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ReflectionOptimizerTests.java b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ReflectionOptimizerTests.java new file mode 100644 index 000000000000..604b6eb3dd15 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ReflectionOptimizerTests.java @@ -0,0 +1,67 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.bytecode.internal.bytebuddy; + +import org.hibernate.bytecode.spi.ReflectionOptimizer; +import org.hibernate.testing.orm.junit.JiraKey; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNotNull; + +/** + * @author Steve Ebersole + */ +public class ReflectionOptimizerTests { + + @Test + public void generateFastClassAndReflectionOptimizer() { + BytecodeProviderImpl bytecodeProvider = new BytecodeProviderImpl(); + ReflectionOptimizer reflectionOptimizer = bytecodeProvider.getReflectionOptimizer( SimpleEntity.class, + new String[]{ "getId", "getName" }, new String[]{ "setId", "setName" }, + new Class[]{ Long.class, String.class } ); + assertThat( reflectionOptimizer ).isNotNull(); + + final ReflectionOptimizer.AccessOptimizer accessOptimizer = reflectionOptimizer.getAccessOptimizer(); + assertThat( accessOptimizer.getPropertyNames() ).hasSize( 2 ); + + final Object instance = reflectionOptimizer.getInstantiationOptimizer().newInstance(); + assertNotNull( instance ); + + final Object[] initialValues = accessOptimizer.getPropertyValues( instance ); + assertThat( initialValues ).containsExactly( null, null ); + + accessOptimizer.setPropertyValues( instance, new Object[] { 1L, "a name" } ); + + final Object[] injectedValues = accessOptimizer.getPropertyValues( instance ); + assertThat( injectedValues ).containsExactly( 1L, "a name" ); + } + + @Test + @JiraKey("HHH-16772") + public void generateFastMappedSuperclassAndReflectionOptimizer() { + BytecodeProviderImpl bytecodeProvider = new BytecodeProviderImpl(); + ReflectionOptimizer reflectionOptimizer = bytecodeProvider.getReflectionOptimizer( + MappedSuperclassEntity.class, + new String[]{ "getId", "getValue" }, new String[]{ "setId", "setValue" }, + new Class[]{ Long.class, String.class } + ); + assertThat( reflectionOptimizer ).isNotNull(); + + final ReflectionOptimizer.AccessOptimizer accessOptimizer = reflectionOptimizer.getAccessOptimizer(); + assertThat( accessOptimizer.getPropertyNames() ).hasSize( 2 ); + + final Object instance = reflectionOptimizer.getInstantiationOptimizer().newInstance(); + assertNotNull( instance ); + + final Object[] initialValues = accessOptimizer.getPropertyValues( instance ); + assertThat( initialValues ).containsExactly( null, null ); + + accessOptimizer.setPropertyValues( instance, new Object[] { 1L, "a value" } ); + + final Object[] injectedValues = accessOptimizer.getPropertyValues( instance ); + assertThat( injectedValues ).containsExactly( 1L, "a value" ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/SimpleEnhancerTests.java b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/SimpleEnhancerTests.java new file mode 100644 index 000000000000..660572b69fad --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/SimpleEnhancerTests.java @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.bytecode.internal.bytebuddy; + +import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl; +import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext; +import org.hibernate.bytecode.enhance.spi.EnhancementException; +import org.hibernate.bytecode.enhance.spi.Enhancer; +import org.hibernate.bytecode.spi.ByteCodeHelper; +import org.junit.Test; + +import java.io.IOException; + +/** + * @author Steve Ebersole + */ +public class SimpleEnhancerTests { + @Test + public void generateEnhancedClass() throws EnhancementException, IOException { + Enhancer enhancer = new EnhancerImpl( new DefaultEnhancementContext(), new ByteBuddyState() ); + enhancer.enhance( SimpleEntity.class.getName(), + ByteCodeHelper.readByteCode( SimpleEntity.class.getClassLoader() + .getResourceAsStream( SimpleEntity.class.getName().replace( '.', '/' ) + ".class" ) ) ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/mappedsuperclass/BaseMappedSuperclass.java b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/mappedsuperclass/BaseMappedSuperclass.java deleted file mode 100644 index 0a46725f97b8..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/mappedsuperclass/BaseMappedSuperclass.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.bytecode.internal.bytebuddy.mappedsuperclass; - -import jakarta.persistence.Id; -import jakarta.persistence.MappedSuperclass; - -@MappedSuperclass -public abstract class BaseMappedSuperclass { - -@Id -protected Long id; - -protected long value; -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/aggregation/UuidAggregationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/aggregation/UuidAggregationTest.java deleted file mode 100644 index 968f22f0e2cb..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/aggregation/UuidAggregationTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.aggregation; - -import java.util.UUID; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.SessionFactory; -import org.hibernate.testing.orm.junit.SessionFactoryScope; - -import org.junit.jupiter.api.Test; - -import jakarta.persistence.Entity; -import jakarta.persistence.Id; - -@DomainModel(annotatedClasses = { UuidAggregationTest.UuidIdentifiedEntity.class }) -@SessionFactory -public class UuidAggregationTest { - - @Entity(name = "UuidIdentifiedEntity") - public static class UuidIdentifiedEntity { - - @Id - private UUID id; - - public UuidIdentifiedEntity() { - super(); - } - - public UUID getId() { - return id; - } - - public void setId(final UUID id) { - this.id = id; - } - } - - @Test - @JiraKey(value = "HHH-15495") - public void testMaxUuid(SessionFactoryScope scope) { - scope.inTransaction( - s -> { - s.createSelectionQuery( "select max(id) from UuidIdentifiedEntity", UUID.class ).getSingleResult(); - } - ); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/LoaderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/LoaderTest.java index 75eb7c18916f..b6c24f298c8a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/LoaderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/LoaderTest.java @@ -4,87 +4,65 @@ */ package org.hibernate.orm.test.annotations.loader; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import org.hibernate.ObjectNotFoundException; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; import java.util.Iterator; import java.util.Set; -import org.hibernate.ObjectNotFoundException; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.resource.transaction.spi.TransactionStatus; - -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; /** * @author Emmanuel Bernard */ -public class LoaderTest extends BaseCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[]{ - Player.class, - Team.class - }; - } - +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel( annotatedClasses = { Player.class, Team.class } ) +@SessionFactory +public class LoaderTest { @Test - public void testBasic() throws Exception { + public void testBasic(SessionFactoryScope sessions) throws Exception { // set up data... - Session s = openSession( ); - Transaction tx = s.beginTransaction(); - Team t = new Team(); - Player p = new Player(); - p.setName( "me" ); - t.getPlayers().add( p ); - p.setTeam( t ); - s.persist(p); - s.persist( t ); - tx.commit(); - s.close(); - - s = openSession(); - tx = s.beginTransaction(); - Team t2 = s.getReference( Team.class, t.getId() ); - Set players = t2.getPlayers(); - Iterator iterator = players.iterator(); - assertEquals( "me", iterator.next().getName() ); - tx.commit(); - s.close(); + sessions.inTransaction( (session) -> { + Team t = new Team( 1L ); + Player p = new Player( 1L, "me" ); + t.addPlayer( p ); + session.persist( p ); + session.persist( t ); + } ); - // clean up data - s = openSession(); - tx = s.beginTransaction(); - t = s.get( Team.class, t2.getId() ); - p = s.get( Player.class, p.getId() ); - s.remove( p ); - s.remove( t ); - tx.commit(); - s.close(); + // test + sessions.inTransaction( (session) -> { + Team t2 = session.getReference( Team.class, 1 ); + Set players = t2.getPlayers(); + Iterator iterator = players.iterator(); + assertThat( iterator.next().getName() ).isEqualTo( "me" ); + } ); } @Test - public void testGetNotExisting() { - Session s = openSession(); - s.beginTransaction(); + public void testGetNotExisting(SessionFactoryScope sessions) { + sessions.inTransaction( (session) -> { + final Team reference = session.getReference( Team.class, 1 ); + assertThat( reference ).isNotNull(); - try { - long notExistingId = 1l; - s.getReference( Team.class, notExistingId ); - s.get( Team.class, notExistingId ); - s.getTransaction().commit(); - } - catch (ObjectNotFoundException e) { - if ( s.getTransaction().getStatus() == TransactionStatus.ACTIVE ) { - s.getTransaction().rollback(); + // now try a find which should return us a null + try { + final Team found = session.find( Team.class, 1 ); + assertThat( found ).isNull(); + } + catch (ObjectNotFoundException unexpected) { + fail( "#find threw an ObjectNotFoundException" ); } - fail("#get threw an ObjectNotFoundExcepton"); - } - finally { - s.close(); - } + } ); + } + + @AfterEach + public void dropTestData(SessionFactoryScope sessions) { + sessions.dropData(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/Player.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/Player.java index d18823a17ccb..f14635cee94a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/Player.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/Player.java @@ -4,7 +4,6 @@ */ package org.hibernate.orm.test.annotations.loader; import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; @@ -14,13 +13,33 @@ @Entity public class Player { - private Long id; - private Team team; private String name; + private Team team; + + public Player() { + } + + public Player(Long id) { + this( id, "Player #" + id ); + } + + public Player(Long id, String name) { + this.id = id; + this.name = name; + } + + public Player(Long id, Team team) { + this( id, "Player #" + id, team ); + } + + public Player(Long id, String name, Team team) { + this.id = id; + this.name = name; + this.team = team; + } @Id - @GeneratedValue public Long getId() { return id; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/Team.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/Team.java index a9ec9d50cd14..cc73e988efd2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/Team.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/loader/Team.java @@ -3,27 +3,39 @@ * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.orm.test.annotations.loader; -import java.util.HashSet; -import java.util.Set; + import jakarta.persistence.Entity; import jakarta.persistence.EntityResult; import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.OneToMany; - import jakarta.persistence.SqlResultSetMapping; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.SQLSelect; +import java.util.HashSet; +import java.util.Set; + @Entity public class Team { private Long id; - private Set players = new HashSet(); + private String name; + private Set players = new HashSet<>(); + + public Team() { + } + + public Team(Long id) { + this( id, "Team #" + id ); + } + + public Team(Long id, String name) { + this.id = id; + this.name = name; + } @Id - @GeneratedValue public Long getId() { return id; } @@ -32,6 +44,14 @@ public void setId(Long id) { this.id = id; } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + @OneToMany(targetEntity = Player.class, mappedBy = "team", fetch = FetchType.EAGER) @Fetch(FetchMode.SELECT) @SQLSelect(sql = "select * from Player where team_id = ?1", @@ -44,4 +64,9 @@ public Set getPlayers() { public void setPlayers(Set players) { this.players = players; } + + public void addPlayer(Player p) { + players.add( p ); + p.setTeam( this ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/hhh13179/HHH13179Test.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cache/hhh13179/HHH13179Test.java deleted file mode 100644 index b030e4341218..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/hhh13179/HHH13179Test.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.cache.hhh13179; - -import org.hibernate.stat.CacheRegionStatistics; - -import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.orm.junit.SessionFactory; -import org.hibernate.testing.orm.junit.SessionFactoryScope; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -/** - * Check that second level caching works for hbm mapped joined subclass inheritance structures - */ -@JiraKey("HHH-13179") -@DomainModel( - xmlMappings = { - "org/hibernate/orm/test/cache/hhh13179/JoinedSubclassPerson.hbm.xml", - "org/hibernate/orm/test/cache/hhh13179/UnionSubclassPerson.hbm.xml", - "org/hibernate/orm/test/cache/hhh13179/DiscriminatorSubclassPerson.hbm.xml" - } -) -@SessionFactory(generateStatistics = true) -public class HHH13179Test { - - - @Test - public void testJoinedSubclassCaching(SessionFactoryScope scope) { - // BaseCoreFunctionalTestCase automatically creates the SessionFactory and provides the Session. - String regionName = JoinedSubclassPerson.class.getName(); - scope.inTransaction( - session -> { - CacheRegionStatistics cacheRegionStatistics = session.getSessionFactory() - .getStatistics() - .getCacheRegionStatistics( - regionName ); - assertThat( cacheRegionStatistics.getPutCount() ).as( "Cache put should be 0" ).isEqualTo( 0 ); - - JoinedSubclassPerson person1 = new JoinedSubclassUIPerson(); - person1.setOid( 1L ); - session.persist( person1 ); - } - ); - - scope.inTransaction( - session -> { - JoinedSubclassPerson person2 = session.get( JoinedSubclassPerson.class, 1L ); - - CacheRegionStatistics cacheRegionStatistics = session.getSessionFactory() - .getStatistics() - .getCacheRegionStatistics( regionName ); - assertThat( cacheRegionStatistics.getHitCount() ).as( "Cache hit should be 1" ).isEqualTo( 1 ); - assertThat( cacheRegionStatistics.getPutCount() ).as( "Cache put should be 1" ).isEqualTo( 1 ); - } - ); - - } - - @Test - public void testUnionSubclassCaching(SessionFactoryScope scope) { - // BaseCoreFunctionalTestCase automatically creates the SessionFactory and provides the Session. - String regionName = UnionSubclassPerson.class.getName(); - scope.inTransaction( - session -> { - CacheRegionStatistics cacheRegionStatistics = session.getSessionFactory() - .getStatistics() - .getCacheRegionStatistics( - regionName ); - assertThat( cacheRegionStatistics.getPutCount() ).as( "Cache put should be 0" ).isEqualTo( 0 ); - - UnionSubclassPerson person1 = new UnionSubclassUIPerson(); - person1.setOid( 1L ); - session.persist( person1 ); - } - ); - - scope.inTransaction( - session -> { - UnionSubclassPerson person2 = session.get( UnionSubclassPerson.class, 1L ); - - CacheRegionStatistics cacheRegionStatistics = session.getSessionFactory() - .getStatistics() - .getCacheRegionStatistics( regionName ); - assertThat( cacheRegionStatistics.getHitCount() ).as( "Cache hit should be 1" ).isEqualTo( 1 ); - assertThat( cacheRegionStatistics.getPutCount() ).as( "Cache put should be 1" ).isEqualTo( 1 ); - } - ); - } - - @Test - public void testDiscriminatorSubclassCaching(SessionFactoryScope scope) { - // BaseCoreFunctionalTestCase automatically creates the SessionFactory and provides the Session. - String regionName = DiscriminatorSubclassPerson.class.getName(); - - scope.inTransaction( - session -> { - CacheRegionStatistics cacheRegionStatistics = session.getSessionFactory() - .getStatistics() - .getCacheRegionStatistics( - regionName ); - assertThat( cacheRegionStatistics.getPutCount() ).as( "Cache put should be 0" ).isEqualTo( 0 ); - - DiscriminatorSubclassPerson person1 = new DiscriminatorSubclassUIPerson(); - person1.setOid( 1L ); - session.persist( person1 ); - - } - ); - - - scope.inTransaction( - session -> { - session.get( DiscriminatorSubclassPerson.class, 1L ); - - CacheRegionStatistics cacheRegionStatistics = session.getSessionFactory() - .getStatistics() - .getCacheRegionStatistics( regionName ); - assertThat( cacheRegionStatistics.getHitCount() ).as( "Cache hit should be 1" ).isEqualTo( 1 ); - assertThat( cacheRegionStatistics.getPutCount() ).as( "Cache put should be 1" ).isEqualTo( 1 ); - } - ); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/hhh13179/HbmInheritanceCachingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cache/hhh13179/HbmInheritanceCachingTests.java new file mode 100644 index 000000000000..5aa92fb60ce2 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cache/hhh13179/HbmInheritanceCachingTests.java @@ -0,0 +1,112 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.cache.hhh13179; + +import org.hibernate.stat.CacheRegionStatistics; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +/** + * Check that second level caching statistics work for inheritance hierarchies mapped using HBM + */ +@JiraKey("HHH-13179") +@DomainModel( xmlMappings = { + "org/hibernate/orm/test/cache/hhh13179/JoinedSubclassPerson.hbm.xml", + "org/hibernate/orm/test/cache/hhh13179/UnionSubclassPerson.hbm.xml", + "org/hibernate/orm/test/cache/hhh13179/DiscriminatorSubclassPerson.hbm.xml" +} ) +@SessionFactory(generateStatistics = true) +@SuppressWarnings("JUnitMalformedDeclaration") +public class HbmInheritanceCachingTests { + + @Test + public void testJoinedSubclassCaching(SessionFactoryScope scope) { + final String regionName = JoinedSubclassPerson.class.getName(); + final CacheRegionStatistics cacheRegionStatistics = scope.getSessionFactory() + .getStatistics() + .getCacheRegionStatistics( regionName ); + assert cacheRegionStatistics != null; + assertThat( cacheRegionStatistics.getHitCount() ).isEqualTo( 0 ); + assertThat( cacheRegionStatistics.getPutCount() ).isEqualTo( 0 ); + + scope.inTransaction( (session) -> { + final JoinedSubclassPerson person1 = new JoinedSubclassUIPerson(); + person1.setOid( 1L ); + session.persist( person1 ); + } ); + + assertThat( cacheRegionStatistics.getHitCount() ).isEqualTo( 0 ); + assertThat( cacheRegionStatistics.getPutCount() ).isEqualTo( 1 ); + + scope.inTransaction((session) -> { + final JoinedSubclassPerson person2 = session.find( JoinedSubclassPerson.class, 1L ); + assertThat( person2 ).isNotNull(); + } ); + + assertThat( cacheRegionStatistics.getHitCount() ).isEqualTo( 1 ); + assertThat( cacheRegionStatistics.getPutCount() ).isEqualTo( 1 ); + } + + @Test + public void testUnionSubclassCaching(SessionFactoryScope scope) { + final String regionName = UnionSubclassPerson.class.getName(); + final CacheRegionStatistics cacheRegionStatistics = scope.getSessionFactory() + .getStatistics() + .getCacheRegionStatistics( regionName ); + assert cacheRegionStatistics != null; + assertThat( cacheRegionStatistics.getHitCount() ).isEqualTo( 0 ); + assertThat( cacheRegionStatistics.getPutCount() ).isEqualTo( 0 ); + + scope.inTransaction( (session) -> { + final UnionSubclassPerson person1 = new UnionSubclassUIPerson(); + person1.setOid( 1L ); + session.persist( person1 ); + } ); + + assertThat( cacheRegionStatistics.getHitCount() ).isEqualTo( 0 ); + assertThat( cacheRegionStatistics.getPutCount() ).isEqualTo( 1 ); + + scope.inTransaction( (session) -> { + UnionSubclassPerson person2 = session.find( UnionSubclassPerson.class, 1L ); + assertThat( person2 ).isNotNull(); + } ); + + assertThat( cacheRegionStatistics.getHitCount() ).isEqualTo( 1 ); + assertThat( cacheRegionStatistics.getPutCount() ).isEqualTo( 1 ); + } + + @Test + public void testDiscriminatorSubclassCaching(SessionFactoryScope scope) { + final String regionName = DiscriminatorSubclassPerson.class.getName(); + final CacheRegionStatistics cacheRegionStatistics = scope.getSessionFactory() + .getStatistics() + .getCacheRegionStatistics( regionName ); + assert cacheRegionStatistics != null; + assertThat( cacheRegionStatistics.getHitCount() ).isEqualTo( 0 ); + assertThat( cacheRegionStatistics.getPutCount() ).isEqualTo( 0 ); + + scope.inTransaction( (session) -> { + DiscriminatorSubclassPerson person1 = new DiscriminatorSubclassUIPerson(); + person1.setOid( 1L ); + session.persist( person1 ); + } ); + + assertThat( cacheRegionStatistics.getHitCount() ).isEqualTo( 0 ); + assertThat( cacheRegionStatistics.getPutCount() ).isEqualTo( 1 ); + + scope.inTransaction( (session) -> { + final DiscriminatorSubclassPerson found = session.find( DiscriminatorSubclassPerson.class, 1L ); + assertThat( found ).isNotNull(); + } ); + + assertThat( cacheRegionStatistics.getHitCount() ).isEqualTo( 1 ); + assertThat( cacheRegionStatistics.getPutCount() ).isEqualTo( 1 ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/component/basic2/ComponentJoinsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/component/basic2/ComponentJoinsTest.java index 98e08fd17c01..1de176bdebdc 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/component/basic2/ComponentJoinsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/component/basic2/ComponentJoinsTest.java @@ -4,78 +4,37 @@ */ package org.hibernate.orm.test.component.basic2; -import org.hibernate.Session; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; /** * Tests related to specifying joins on components (embedded values). * * @author Steve Ebersole */ -public class ComponentJoinsTest extends BaseCoreFunctionalTestCase { - @Override - public Class[] getAnnotatedClasses() { - return new Class[] { - Person.class, - Component.class, - Component.Emb.Stuff.class }; - } - - @Test - public void testComponentJoins() { - // Just checking proper query construction and syntax checking via database query parser... - Session session = openSession(); - session.beginTransaction(); - // use it in WHERE - session.createQuery( "select p from Person p join p.name as n where n.lastName like '%'" ).list(); - // use it in SELECT - session.createQuery( "select n.lastName from Person p join p.name as n" ).list(); - session.createQuery( "select n from Person p join p.name as n" ).list(); - // use it in ORDER BY - session.createQuery( "select n from Person p join p.name as n order by n.lastName" ).list(); - session.createQuery( "select n from Person p join p.name as n order by p" ).list(); - session.createQuery( "select n from Person p join p.name as n order by n" ).list(); - session.getTransaction().commit(); - session.close(); - } - - @Test - @JiraKey(value = "HHH-7849") - public void testComponentJoinsHHH7849() { - // Just checking proper query construction and syntax checking via database query parser... - Session session = openSession(); - session.beginTransaction(); - // use it in WHERE - session.createQuery( "select c from Component c join c.emb as e where e.stuffs is empty " ).list(); - - session.getTransaction().commit(); - session.close(); - } +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = {Person.class, Component.class, Component.Emb.Stuff.class}) +@SessionFactory +public class ComponentJoinsTest { @Test - public void dummy() { - Session session = openSession(); - session.beginTransaction(); - session.persist( new Person( 1, "Steve", "Ebersone" ) ); - session.getTransaction().commit(); - session.close(); - - - session = openSession(); - session.beginTransaction(); - Person person = session.get( Person.class, 1 ); - person.getName().setLastName( "Ebersole" ); - session.getTransaction().commit(); - session.close(); - - - session = openSession(); - session.beginTransaction(); - session.createQuery( "delete Person" ).executeUpdate(); - session.getTransaction().commit(); - session.close(); + public void testComponentJoins(SessionFactoryScope sessions) { + sessions.inTransaction( (session) -> { + // use it in WHERE + session.createQuery( "select p from Person p join p.name as n where n.lastName like '%'" ).list(); + session.createQuery( "select c from Component c join c.emb as e where e.stuffs is empty " ).list(); + + // use it in SELECT + session.createQuery( "select n.lastName from Person p join p.name as n" ).list(); + session.createQuery( "select n from Person p join p.name as n" ).list(); + + // use it in ORDER BY + session.createQuery( "select n from Person p join p.name as n order by n.lastName" ).list(); + session.createQuery( "select n from Person p join p.name as n order by p" ).list(); + session.createQuery( "select n from Person p join p.name as n order by n" ).list(); + } ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/DB2zDialectInitTestCase.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/DB2zDialectInitTestCase.java deleted file mode 100644 index ce15d82210ec..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/DB2zDialectInitTestCase.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.dialect; - -import org.hibernate.dialect.DB2zDialect; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.orm.junit.JiraKey; -import org.junit.Test; - -import static org.junit.Assert.assertNotNull; - -/** - * @author Onno Goczol - */ -@JiraKey(value = "HHH-15046") -@RequiresDialect(DB2zDialect.class) -public class DB2zDialectInitTestCase { - - static class DB2zDialectWithExplicitTimezoneSupport extends DB2zDialect { - } - - @Test - public void testInitWithTimezoneSupport() { - final var db2zDialect = new DB2zDialectWithExplicitTimezoneSupport(); - assertNotNull(db2zDialect); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/DB2iDialectInitTestCase.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/Db2VariantDialectInitTests.java similarity index 56% rename from hibernate-core/src/test/java/org/hibernate/orm/test/dialect/DB2iDialectInitTestCase.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/Db2VariantDialectInitTests.java index 7db3c7f6204d..c614583d3fe3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/DB2iDialectInitTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/Db2VariantDialectInitTests.java @@ -5,23 +5,26 @@ package org.hibernate.orm.test.dialect; import org.hibernate.dialect.DB2iDialect; -import org.hibernate.testing.RequiresDialect; +import org.hibernate.dialect.DB2zDialect; import org.hibernate.testing.orm.junit.JiraKey; import org.junit.Test; import static org.junit.Assert.assertNotNull; /** - * @author Onno Goczol + * @author Steve Ebersole */ @JiraKey(value = "HHH-15046") -@RequiresDialect(DB2iDialect.class) -public class DB2iDialectInitTestCase { +public class Db2VariantDialectInitTests { + @Test + public void testDB2zDialectInit() { + final var db2zDialect = new DB2zDialect(); + assertNotNull( db2zDialect ); + } @Test - public void testInitUniqueDelegate() { + public void testDB2iDialectInit() { final var db2iDialect = new DB2iDialect(); - assertNotNull(db2iDialect); + assertNotNull( db2iDialect ); } - } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/EntityGraphFetchingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/EntityGraphFetchingTest.java new file mode 100644 index 000000000000..2202bbdd40e3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/EntityGraphFetchingTest.java @@ -0,0 +1,68 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.entitygraph; + +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import org.hibernate.graph.GraphParser; +import org.hibernate.graph.GraphSemantic; +import org.hibernate.graph.RootGraph; +import org.hibernate.testing.jdbc.SQLStatementInspector; +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.domain.library.Book; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + + +@JiraKey(value = "HHH-10485") +@DomainModel( standardModels = StandardDomainModel.LIBRARY ) +@SessionFactory(useCollectingStatementInspector = true) +@SuppressWarnings("JUnitMalformedDeclaration") +public class EntityGraphFetchingTest { + + @Test + void testWithoutEntityGraph(SessionFactoryScope scope) { + final SQLStatementInspector sqlCollector = scope.getCollectingStatementInspector(); + sqlCollector.clear(); + + scope.inTransaction( (session) -> { + final CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); + final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery( Book.class ); + criteriaQuery.from( Book.class ); + + session.createQuery( criteriaQuery ).getResultList(); + + assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); + assertThat( sqlCollector.getSqlQueries().get( 0 ) ).doesNotContain( " join " ); + } ); + } + + @Test + @JiraKey(value = "HHH-10485") + void testWithEntityGraph(SessionFactoryScope scope) { + SQLStatementInspector sqlCollector = scope.getCollectingStatementInspector(); + sqlCollector.clear(); + + scope.inTransaction( (session) -> { + final RootGraph fetchGraph = GraphParser.parse( Book.class, "authors", session ); + + CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery( Book.class ); + criteriaQuery.from( Book.class ); + + session.createQuery( criteriaQuery ) + .setHint( GraphSemantic.FETCH.getJakartaHintName(), fetchGraph ) + .getResultList(); + + assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); + assertThat( sqlCollector.getSqlQueries().get( 0 ) ).contains( " join " ); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/EntityGraphWithFetchAnnotationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/EntityGraphWithFetchAnnotationTest.java deleted file mode 100644 index d4ed854875d3..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/EntityGraphWithFetchAnnotationTest.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.entitygraph; - -import java.util.List; -import jakarta.persistence.Entity; -import jakarta.persistence.EntityGraph; -import jakarta.persistence.EntityManager; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; -import jakarta.persistence.criteria.CriteriaBuilder; -import jakarta.persistence.criteria.CriteriaQuery; - -import org.hibernate.annotations.Fetch; -import org.hibernate.annotations.FetchMode; -import org.hibernate.graph.GraphSemantic; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.jdbc.SQLStatementInspector; -import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.SessionFactory; -import org.hibernate.testing.orm.junit.SessionFactoryScope; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * @author Vlad Mihalcea - */ -@DomainModel( - annotatedClasses = { - EntityGraphWithFetchAnnotationTest.Order.class, - EntityGraphWithFetchAnnotationTest.Product.class, - EntityGraphWithFetchAnnotationTest.Tag.class - } -) -@SessionFactory(useCollectingStatementInspector = true) -public class EntityGraphWithFetchAnnotationTest { - - @Test - @JiraKey(value = "HHH-10485") - void testWithoutEntityGraph(SessionFactoryScope scope) { - SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); - statementInspector.clear(); - - scope.inTransaction( - session -> { - EntityManager entityManager = session.unwrap( EntityManager.class ); - CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = criteriaBuilder - .createQuery( Order.class ); - criteriaQuery.from( Order.class ); - - entityManager - .createQuery( criteriaQuery ) - .setFirstResult( 10 ) - .setMaxResults( 20 ) - .getResultList(); - - statementInspector.assertExecutedCount( 1 ); - statementInspector.assertNumberOfOccurrenceInQuery( 0, "left join", 0 ); - } - ); - } - - @Test - @JiraKey(value = "HHH-10485") - void testWithEntityGraph(SessionFactoryScope scope) { - SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); - statementInspector.clear(); - - scope.inTransaction( - session -> { - EntityManager entityManager = session.unwrap( EntityManager.class ); - CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = criteriaBuilder - .createQuery( Order.class ); - criteriaQuery.from( Order.class ); - - EntityGraph entityGraph = entityManager.createEntityGraph( Order.class ); - entityGraph.addAttributeNodes( "products" ); - - entityManager - .createQuery( criteriaQuery ) - .setFirstResult( 10 ) - .setMaxResults( 20 ) - .setHint( GraphSemantic.FETCH.getJpaHintName(), entityGraph ) - .getResultList(); - - statementInspector.assertExecutedCount( 1 ); - String sql = statementInspector.getSqlQueries().get( 0 ); - assertThat( sql, containsString( "left join" ) ); - } - ); - } - - @Entity(name = "Order") - @Table(name = "orders") - public static class Order { - - @Id - @GeneratedValue - private long id; - - @OneToMany - @Fetch(FetchMode.SELECT) - private List products; - - @OneToMany - @Fetch(FetchMode.SELECT) - private List tags; - - public long getId() { - return this.id; - } - - public void setId(long id) { - this.id = id; - } - - public List getProducts() { - return this.products; - } - - public void setProducts(List products) { - this.products = products; - } - - public List getTags() { - return this.tags; - } - - public void setTags(List tags) { - this.tags = tags; - } - - } - - @Entity(name = "Product") - @Table(name = "products") - public static class Product { - - @Id - @GeneratedValue - private long id; - - private String name; - - public long getId() { - return this.id; - } - - public void setId(long id) { - this.id = id; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - } - - @Entity(name = "Tag") - @Table(name = "tags") - public static class Tag { - - @Id - @GeneratedValue - private long id; - - private String name; - - public long getId() { - return this.id; - } - - public void setId(long id) { - this.id = id; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/fetchprofiles/EntityLoadedInTwoPhaseLoadTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/fetchprofiles/EntityLoadedInTwoPhaseLoadTest.java index 0ac0cc3a9a6d..f1b200aad232 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/fetchprofiles/EntityLoadedInTwoPhaseLoadTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/fetchprofiles/EntityLoadedInTwoPhaseLoadTest.java @@ -8,274 +8,184 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; - +import jakarta.persistence.Table; import org.hibernate.LazyInitializationException; import org.hibernate.annotations.FetchProfile; -import org.hibernate.cfg.Configuration; -import org.hibernate.cfg.Environment; - +import org.hibernate.stat.spi.StatisticsImplementor; +import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; - -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.cfg.StatisticsSettings.GENERATE_STATISTICS; +import static org.junit.jupiter.api.Assertions.fail; + +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey( value = "HHH-12297") -public class EntityLoadedInTwoPhaseLoadTest extends BaseCoreFunctionalTestCase { - +@ServiceRegistry( + settings = @Setting( name = GENERATE_STATISTICS, value = "true" ) +) +@DomainModel( annotatedClasses = { + EntityLoadedInTwoPhaseLoadTest.StartNode.class, + EntityLoadedInTwoPhaseLoadTest.MiddleNode.class, + EntityLoadedInTwoPhaseLoadTest.TerminalNode.class, + EntityLoadedInTwoPhaseLoadTest.Branch1Node.class, + EntityLoadedInTwoPhaseLoadTest.Branch2Node.class +} ) +@SessionFactory +public class EntityLoadedInTwoPhaseLoadTest { static final String FETCH_PROFILE_NAME = "fp1"; - public void configure(Configuration cfg) { - cfg.setProperty( Environment.GENERATE_STATISTICS, true ); - } - @Test - public void testIfAllRelationsAreInitialized() { - long startId = this.createSampleData(); - sessionFactory().getStatistics().clear(); + public void testIfAllRelationsAreInitialized(SessionFactoryScope sessions) { + final StatisticsImplementor statistics = sessions.getSessionFactory().getStatistics(); + statistics.clear(); + + final StartNode startNode = sessions.fromTransaction( (session) -> { + session.enableFetchProfile( FETCH_PROFILE_NAME ); + return session.find( StartNode.class, 1 ); + } ); + + // should have loaded all the data + assertThat( statistics.getEntityLoadCount() ).isEqualTo( 4 ); + // should have loaded it in one query (join fetch) + assertThat( statistics.getPrepareStatementCount() ).isEqualTo( 1 ); + try { - Start start = this.loadStartWithFetchProfile( startId ); - @SuppressWarnings( "unused" ) - String value = start.getVia2().getMid().getFinish().getValue(); - assertEquals( 4, sessionFactory().getStatistics().getEntityLoadCount() ); + // access the data which was supposed to have been fetched + assertThat( startNode.branch2Node.middleNode.terminalNode.name ).isNotNull(); } catch (LazyInitializationException e) { fail( "Everything should be initialized" ); } } - public Start loadStartWithFetchProfile(long startId) { - return doInHibernate( this::sessionFactory, session -> { - session.enableFetchProfile( FETCH_PROFILE_NAME ); - return session.get( Start.class, startId ); - } ); - } - - private long createSampleData() { - return doInHibernate( this::sessionFactory, session -> { - Finish finish = new Finish( "foo" ); - Mid mid = new Mid( finish ); - Via2 via2 = new Via2( mid ); - Start start = new Start( null, via2 ); - - session.persist( start ); + @BeforeEach + void createTestData(SessionFactoryScope sessions) { + sessions.inTransaction( (session) -> { + TerminalNode terminalNode = new TerminalNode( 1, "foo" ); + MiddleNode middleNode = new MiddleNode( 1, terminalNode ); + Branch2Node branch2Node = new Branch2Node( 1, middleNode ); + StartNode startNode = new StartNode( 1, null, branch2Node ); - return start.getId(); + session.persist( startNode ); } ); } - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Start.class, - Mid.class, - Finish.class, - Via1.class, - Via2.class - }; + @AfterEach + void dropTestData(SessionFactoryScope sessions) { + sessions.dropData(); } - @Entity(name = "FinishEntity") - public static class Finish { - + @Entity + @Table(name="start_node") + @FetchProfile(name = FETCH_PROFILE_NAME, fetchOverrides = { + @FetchProfile.FetchOverride(entity = StartNode.class, association = "branch1Node"), + @FetchProfile.FetchOverride(entity = StartNode.class, association = "branch2Node") + }) + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class StartNode { @Id - @GeneratedValue - private long id; - - @Column(name = "val", nullable = false) - private String value; - - public Finish() { - } - - public Finish(String value) { - this.value = value; - } + private Integer id; + @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + private Branch1Node branch1Node; + @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + private Branch2Node branch2Node; - public long getId() { - return id; + public StartNode() { } - public void setId(long id) { + public StartNode(Integer id, Branch1Node branch1Node, Branch2Node branch2Node) { this.id = id; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; + this.branch1Node = branch1Node; + this.branch2Node = branch2Node; } } - @Entity(name = "MidEntity") + @Entity(name = "Via1Entity") @FetchProfile(name = FETCH_PROFILE_NAME, fetchOverrides = { - @FetchProfile.FetchOverride(entity = Mid.class, association = "finish") + @FetchProfile.FetchOverride(entity = Branch1Node.class, association = "middleNode") }) - public static class Mid { - + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class Branch1Node { @Id - @GeneratedValue - private long id; - + private Integer id; @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) - private Finish finish; - - public Mid() { - } + private MiddleNode middleNode; - public Mid(Finish finish) { - this.finish = finish; + public Branch1Node() { } - public long getId() { - return id; - } - - public void setId(long id) { + public Branch1Node(Integer id, MiddleNode middleNode) { this.id = id; + this.middleNode = middleNode; } - - public Finish getFinish() { - return finish; - } - - public void setFinish(Finish finish) { - this.finish = finish; - } - } - @Entity(name = "StartEntity") + @Entity(name = "Via2Entity") @FetchProfile(name = FETCH_PROFILE_NAME, fetchOverrides = { - @FetchProfile.FetchOverride(entity = Start.class, association = "via1"), - @FetchProfile.FetchOverride(entity = Start.class, association = "via2") + @FetchProfile.FetchOverride(entity = Branch2Node.class, association = "middleNode") }) - public static class Start { - + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class Branch2Node { @Id - @GeneratedValue - private long id; - - @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) - private Via1 via1; - + private Integer id; @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) - private Via2 via2; - - public Start() { - } + private MiddleNode middleNode; - public Start(Via1 via1, Via2 via2) { - this.via1 = via1; - this.via2 = via2; + public Branch2Node() { } - public long getId() { - return id; - } - - public void setId(long id) { + public Branch2Node(Integer id, MiddleNode middleNode) { this.id = id; + this.middleNode = middleNode; } - - public Via1 getVia1() { - return via1; - } - - public void setVia1(Via1 via1) { - this.via1 = via1; - } - - public Via2 getVia2() { - return via2; - } - - public void setVia2(Via2 via2) { - this.via2 = via2; - } - } - @Entity(name = "Via1Entity") + @Entity + @Table(name="middle_node") @FetchProfile(name = FETCH_PROFILE_NAME, fetchOverrides = { - @FetchProfile.FetchOverride(entity = Via1.class, association = "mid") + @FetchProfile.FetchOverride(entity = MiddleNode.class, association = "terminalNode") }) - public static class Via1 { - + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class MiddleNode { @Id - @GeneratedValue - private long id; - + private Integer id; @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) - private Mid mid; - - public Via1() { - } + private TerminalNode terminalNode; - public Via1(Mid mid) { - this.mid = mid; + public MiddleNode() { } - public long getId() { - return id; - } - - public void setId(long id) { + public MiddleNode(Integer id, TerminalNode terminalNode) { this.id = id; + this.terminalNode = terminalNode; } - - public Mid getMid() { - return mid; - } - - public void setMid(Mid mid) { - this.mid = mid; - } - } - @Entity(name = "Via2Entity") - @FetchProfile(name = FETCH_PROFILE_NAME, fetchOverrides = { - @FetchProfile.FetchOverride(entity = Via2.class, association = "mid") - }) - public static class Via2 { - + @Entity + @Table(name="terminal_node") + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class TerminalNode { @Id - @GeneratedValue - private long id; + private Integer id; + @Column(nullable = false) + private String name; - @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) - private Mid mid; - - public Via2() { - } - - public Via2(Mid mid) { - this.mid = mid; - } - - public long getId() { - return id; + public TerminalNode() { } - public void setId(long id) { + public TerminalNode(Integer id, String name) { this.id = id; + this.name = name; } - - public Mid getMid() { - return mid; - } - - public void setMid(Mid mid) { - this.mid = mid; - } - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/flush/TestFlushJoinTransaction.java b/hibernate-core/src/test/java/org/hibernate/orm/test/flush/TestFlushJoinTransaction.java index 99e6872c6a8f..f86e23e2d837 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/flush/TestFlushJoinTransaction.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/flush/TestFlushJoinTransaction.java @@ -4,80 +4,76 @@ */ package org.hibernate.orm.test.flush; -import java.util.Map; - import jakarta.persistence.TransactionRequiredException; - -import org.hibernate.Session; -import org.hibernate.cfg.AvailableSettings; -import org.junit.Test; - -import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.jta.TestingJtaBootstrap; import org.hibernate.testing.jta.TestingJtaPlatformImpl; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.SettingConfiguration; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Michiel Hendriks */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-13936") -public class TestFlushJoinTransaction extends BaseNonConfigCoreFunctionalTestCase { - - @Override - protected void addSettings(Map settings) { - super.addSettings( settings ); - TestingJtaBootstrap.prepare( settings ); - settings.put( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" ); - } - +@ServiceRegistry( + settingConfigurations = @SettingConfiguration( configurer = TestingJtaBootstrap.class ) +) +@DomainModel +@SessionFactory +public class TestFlushJoinTransaction { @Test - public void testFlush() throws Exception { - Session session = openSession(); - try { - TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); - session.flush(); - TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); - } - catch (TransactionRequiredException e) { - fail("No TransactionRequiredException expected."); - } - finally { - session.close(); - } + public void testFlush(SessionFactoryScope sessions) { + sessions.inSession( (session) -> { + try { + TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); + session.flush(); + TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); + } + catch (TransactionRequiredException e) { + fail("No TransactionRequiredException expected."); + } + catch (Exception e) { + fail("Unexpected JTA exception", e); + } + } ); } @Test - public void testIsConnectedFlush() throws Exception { - Session session = openSession(); - try { - TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); - session.isConnected(); - session.flush(); - TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); - } - catch (TransactionRequiredException e) { - fail("No TransactionRequiredException expected."); - } - finally { - session.close(); - } + public void testIsConnectedFlush(SessionFactoryScope sessions) { + sessions.inSession( (session) -> { + try { + TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); + session.isConnected(); + session.flush(); + TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); + } + catch (TransactionRequiredException e) { + fail("No TransactionRequiredException expected."); + } + catch (Exception e) { + fail("Unexpected JTA exception", e); + } + } ); } @Test - public void testIsConnectedFlushShouldThrowExceptionIfNoTransaction() { - Session session = openSession(); - try { - session.isConnected(); - session.flush(); - fail("A TransactionRequiredException should be thrown"); - } - catch (TransactionRequiredException e) { - //expected - } - finally { - session.close(); - } + public void testIsConnectedFlushShouldThrowExceptionIfNoTransaction(SessionFactoryScope sessions) { + sessions.inSession( (session) -> { + try { + session.isConnected(); + session.flush(); + fail("A TransactionRequiredException should be thrown"); + } + catch (TransactionRequiredException e) { + //expected + } + } ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/CoalesceTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/CoalesceTest.java index 535f41a8c48d..c6950d868bc1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/CoalesceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/CoalesceTest.java @@ -4,131 +4,80 @@ */ package org.hibernate.orm.test.hql; -import java.util.List; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.TypedQuery; - - +import org.hibernate.testing.orm.domain.gambit.EntityOfBasics; +import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Before; -import org.junit.Test; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertThat; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; /** * @author Johannes Buehler */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey( value = "HHH-10463") -public class CoalesceTest extends BaseCoreFunctionalTestCase { - - private Person person; +@DomainModel(annotatedClasses = org.hibernate.testing.orm.domain.gambit.EntityOfBasics.class) +@SessionFactory +public class CoalesceTest { + final String QRY_STR = "from EntityOfBasics e where e.theString = coalesce(:p , e.theString)"; - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Person.class - }; - } + @Test + public void testCoalesce(SessionFactoryScope sessions) { + sessions.inTransaction( (session) -> { + final List resultList = session.createQuery( QRY_STR, EntityOfBasics.class ) + .setParameter("p", "a string") + .getResultList(); + assertThat( resultList ).hasSize( 1 ); + } ); - @Before - public void setUp() { - doInHibernate( this::sessionFactory, session -> { - person = new Person(); - person.setName("Johannes"); - person.setSurname("Buehler"); - session.persist(person); + sessions.inTransaction( (session) -> { + final List resultList = session.createQuery( QRY_STR, EntityOfBasics.class ) + .setParameter("p", "$^&@#") + .getResultList(); + assertThat( resultList ).hasSize( 0 ); } ); } @Test - public void HHH_10463_TestCoalesce() { - doInHibernate( this::sessionFactory, session -> { - TypedQuery query = session.createQuery( "from Person p where p.name = coalesce(:name , p.name) ", Person.class ); - query.setParameter("name", "Johannes"); - List resultList = query.getResultList(); - assertThat(resultList, hasItem(person)); + public void testCoalesceWithNull(SessionFactoryScope sessions) { + sessions.inTransaction( (session) -> { + final List resultList = session.createQuery( QRY_STR, EntityOfBasics.class ) + .setParameter("p", null) + .getResultList(); + assertThat( resultList ).hasSize( 1 ); } ); - } @Test - public void HHH_10463_NullInCoalesce() { - doInHibernate( this::sessionFactory, session -> { - TypedQuery query = session.createQuery( "from Person p where p.name = coalesce(:name, p.name) ", Person.class ); - query.setParameter("name", null); - List resultList = query.getResultList(); - assertThat(resultList, hasItem(person)); + public void testCoalesceWithCast(SessionFactoryScope sessions) { + final String qryStr = "from EntityOfBasics e where e.theString = coalesce(cast(:p as string) , e.theString)"; + sessions.inTransaction( (session) -> { + final List resultList = session.createQuery( qryStr, EntityOfBasics.class ) + .setParameter("p", null) + .getResultList(); + assertThat( resultList ).hasSize( 1 ); } ); } - @Test - public void HHH_10463_NullInCoalesce_PostgreSQL_Workaround() { - doInHibernate( this::sessionFactory, session -> { - TypedQuery query = session.createQuery( "from Person p where p.name = coalesce(cast( :name as string) , p.name) ", Person.class ); - query.setParameter("name", null); - List resultList = query.getResultList(); - assertThat(resultList, hasItem(person)); + @BeforeEach + public void createTestData(SessionFactoryScope sessions) { + sessions.inTransaction( (session) -> { + final EntityOfBasics entity = new EntityOfBasics( 1 ); + entity.setTheString( "a string" ); + entity.setTheField( "another string" ); + session.persist( entity ); } ); } - @Entity(name = "Person") - public static class Person { - - @Id - @GeneratedValue - private Integer id; - - @Column - private String name; - - @Column - private String surname; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getSurname() { - return surname; - } - - public void setSurname(String surname) { - this.surname = surname; - } - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Person )) return false; - - Person person = (Person) o; - - return id != null ? id.equals(person.id) : person.id == null; - - } - - @Override - public int hashCode() { - return id != null ? id.hashCode() : 0; - } + @AfterEach + void dropTestData(SessionFactoryScope sessions) { + sessions.dropData(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/joinedSubclass/JoinedSubclassNativeQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/joinedSubclass/JoinedSubclassNativeQueryTest.java index 5bd483e575ce..1aa3d30295be 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/joinedSubclass/JoinedSubclassNativeQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/joinedSubclass/JoinedSubclassNativeQueryTest.java @@ -4,80 +4,82 @@ */ package org.hibernate.orm.test.hql.joinedSubclass; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.internal.SqlTypedMappingImpl; - -import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.type.spi.TypeConfiguration; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.Inheritance; -import jakarta.persistence.InheritanceType; +import java.util.Locale; + +import static org.assertj.core.api.Assertions.assertThat; /** * @author Jan Schatteman */ -@DomainModel( - annotatedClasses = { - JoinedSubclassNativeQueryTest.Person.class, - JoinedSubclassNativeQueryTest.Employee.class - } -) +@DomainModel( annotatedClasses = { + JoinedSubclassNativeQueryTest.Person.class, + JoinedSubclassNativeQueryTest.Employee.class +} ) @SessionFactory +@SuppressWarnings("JUnitMalformedDeclaration") public class JoinedSubclassNativeQueryTest { - @BeforeAll - public void setup(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - Person p = new Person(); - p.setFirstName( "Jan" ); - session.persist( p ); - } - ); - } - - @AfterAll - public void tearDown(SessionFactoryScope scope) { - scope.inTransaction( - session -> session.createMutationQuery( "delete from Person" ).executeUpdate() - ); - } - @Test @JiraKey( value = "HHH-16180") public void testJoinedInheritanceNativeQuery(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - final SessionFactoryImplementor sessionFactory = scope.getSessionFactory(); - final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration(); + final SessionFactoryImplementor sessionFactory = scope.getSessionFactory(); + final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration(); final String nullColumnString = sessionFactory - .getJdbcServices() - .getDialect() - .getSelectClauseNullString( + .getJdbcServices() + .getDialect() + .getSelectClauseNullString( new SqlTypedMappingImpl( typeConfiguration.getBasicTypeForJavaType( String.class ) ), typeConfiguration ); - // PostgreSQLDialect#getSelectClauseNullString produces e.g. `null::text` which we interpret as parameter, - // so workaround this problem by configuring to ignore JDBC parameters - session.setProperty( AvailableSettings.NATIVE_IGNORE_JDBC_PARAMETERS, true ); - Person p = (Person) session.createNativeQuery( "select p.*, " + nullColumnString + " as company_name, 0 as clazz_ from Person p", Person.class ).getSingleResult(); - Assertions.assertNotNull( p ); - Assertions.assertEquals( p.getFirstName(), "Jan" ); - } + + final String qry = String.format( + Locale.ROOT, + "select p.*, %s as company_name, 0 as clazz_ from Person p", + nullColumnString ); + + scope.inTransaction( (session) -> { + // PostgreSQLDialect#getSelectClauseNullString produces e.g. `null::text` which we interpret as parameter, + // so workaround this problem by configuring to ignore JDBC parameters + session.setProperty( AvailableSettings.NATIVE_IGNORE_JDBC_PARAMETERS, true ); + + Person p = session.createNativeQuery( qry, Person.class ).getSingleResult(); + assertThat( p ).isNotNull(); + assertThat( p.getFirstName() ).isEqualTo( "Jan" ); + } ); + } + + @BeforeEach + public void setup(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + Person p = new Person(); + p.setFirstName( "Jan" ); + session.persist( p ); + } ); + } + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.getSessionFactory().getSchemaManager().truncate(); } @Entity(name = "Person") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/uuid/UuidAggregationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/uuid/UuidAggregationTest.java new file mode 100644 index 000000000000..38c5f3eda670 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/uuid/UuidAggregationTest.java @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.id.uuid; + +import org.hibernate.testing.orm.domain.gambit.EntityOfBasics; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = EntityOfBasics.class) +@SessionFactory +public class UuidAggregationTest { + @Test + @JiraKey(value = "HHH-15495") + public void testMaxUuid(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + session.createSelectionQuery( "select max(theUuid) from EntityOfBasics", UUID.class ).getSingleResult(); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/JoinedInheritanceCollectionSameHierarchyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/JoinedInheritanceCollectionSameHierarchyTest.java index f357cf940b58..f16927b8667b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/JoinedInheritanceCollectionSameHierarchyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/JoinedInheritanceCollectionSameHierarchyTest.java @@ -4,26 +4,26 @@ */ package org.hibernate.orm.test.inheritance; -import java.util.List; - -import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.Jira; -import org.hibernate.testing.orm.junit.SessionFactory; -import org.hibernate.testing.orm.junit.SessionFactoryScope; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Test; - import jakarta.persistence.Entity; import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Inheritance; import jakarta.persistence.InheritanceType; import jakarta.persistence.ManyToMany; import jakarta.persistence.ManyToOne; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.Jira; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("JUnitMalformedDeclaration") @DomainModel( annotatedClasses = { // The user entities come first, so they get the lowest discriminator values JoinedInheritanceCollectionSameHierarchyTest.UserEntity.class, @@ -39,18 +39,8 @@ public class JoinedInheritanceCollectionSameHierarchyTest { @Test public void testGetDiscriminatorCollection(SessionFactoryScope scope) { - final Long id = scope.fromTransaction( session -> { - final UserEntity user = new UserEntity( "test_user" ); - session.persist( user ); - final GoodCompany company = new GoodCompany(); - company.employee = user; - session.persist( company ); - final CompanyRegistry companyRegistry = new CompanyRegistry( List.of( company ) ); - session.persist( companyRegistry ); - return companyRegistry.id; - } ); scope.inSession( session -> { - final CompanyRegistry companyRegistry = session.get( CompanyRegistry.class, id ); + final CompanyRegistry companyRegistry = session.find( CompanyRegistry.class, 30 ); assertThat( companyRegistry.getCompanies() ).hasSize( 1 ) .extracting( AbstractCompany::getEmployee ) .extracting( UserEntity::getName ) @@ -58,21 +48,36 @@ public void testGetDiscriminatorCollection(SessionFactoryScope scope) { } ); } - @AfterAll - public void tearDown(SessionFactoryScope scope) { - scope.inTransaction( session -> { - session.createMutationQuery( "delete from CompanyRegistry" ).executeUpdate(); - session.createMutationQuery( "delete from AbstractCompany" ).executeUpdate(); - session.createMutationQuery( "delete from SuperEntity" ).executeUpdate(); + @BeforeEach + void createTestData(SessionFactoryScope sessions) { + sessions.inTransaction( session -> { + final UserEntity user = new UserEntity( 1, "test_user" ); + session.persist( user ); + final GoodCompany company = new GoodCompany( 20 ); + company.employee = user; + session.persist( company ); + final CompanyRegistry companyRegistry = new CompanyRegistry( 30, List.of( company ) ); + session.persist( companyRegistry ); } ); } + @AfterAll + public void dropTestData(SessionFactoryScope sessions) { + sessions.dropData(); + } + @Entity( name = "SuperEntity" ) @Inheritance( strategy = InheritanceType.JOINED ) static abstract class SuperEntity { @Id - @GeneratedValue - Long id; + Integer id; + + public SuperEntity() { + } + + public SuperEntity(Integer id) { + this.id = id; + } } @Entity( name = "CompanyRegistry" ) @@ -83,7 +88,8 @@ static class CompanyRegistry extends SuperEntity { public CompanyRegistry() { } - public CompanyRegistry(List companies) { + public CompanyRegistry(Integer id, List companies) { + super( id ); this.companies = companies; } @@ -97,6 +103,13 @@ abstract static class AbstractCompany extends SuperEntity { @ManyToOne( fetch = FetchType.LAZY ) UserEntity employee; + public AbstractCompany() { + } + + public AbstractCompany(Integer id) { + super( id ); + } + public UserEntity getEmployee() { return employee; } @@ -104,16 +117,36 @@ public UserEntity getEmployee() { @Entity( name = "GoodCompany" ) static class GoodCompany extends AbstractCompany { + public GoodCompany() { + } + + public GoodCompany(Integer id) { + super( id ); + } } @Entity( name = "BadCompany" ) static class BadCompany extends AbstractCompany { // (unused) sibling subtype for 'GoodCompany' + + public BadCompany() { + } + + public BadCompany(Integer id) { + super( id ); + } } @Entity( name = "AbstractUser" ) static class BaseUser extends SuperEntity { // necessary intermediate entity so 'BaseUser' is the first child type and gets the lowest discriminator value + + public BaseUser() { + } + + public BaseUser(Integer id) { + super( id ); + } } @Entity( name = "UserEntity" ) @@ -123,7 +156,8 @@ static class UserEntity extends BaseUser { public UserEntity() { } - public UserEntity(String name) { + public UserEntity(Integer id, String name) { + super( id ); this.name = name; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java index df793f6b2b0d..dd2a385cb509 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java @@ -4,7 +4,6 @@ */ package org.hibernate.orm.test.interceptor; -import jakarta.persistence.PersistenceException; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import java.util.LinkedList; @@ -26,13 +25,11 @@ import org.hibernate.resource.jdbc.spi.StatementInspector; import org.hibernate.type.Type; -import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; /** * @author Gavin King @@ -139,37 +136,6 @@ public boolean onFlushDirty( } - /** - * Test that setting a transaction timeout will cause an Exception to occur - * if the transaction timeout is exceeded. - */ - @Test - public void testTimeout() throws Exception { - final int TIMEOUT = 2; - final int WAIT = TIMEOUT + 1; - Session s = openSession(); - // Get the transaction and set the timeout BEFORE calling begin() - Transaction t = s.getTransaction(); - t.setTimeout( TIMEOUT ); - t.begin(); - // Sleep for an amount of time that exceeds the transaction timeout - Thread.sleep( WAIT * 1000 ); - try { - // Do something with the transaction and try to commit it - s.persist( new User( "john", "test" ) ); - t.commit(); - fail( "Transaction should have timed out" ); - } - catch (PersistenceException e) { - assertTyping( TransactionException.class, e ); - assertTrue( - "Transaction failed for the wrong reason. Expecting transaction timeout, but found [" + - e.getMessage() + "]", - e.getMessage().contains( "transaction timeout expired" ) - ); - } - } - @Test public void testComponentInterceptor() { final int checkPerm = 500; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/refcursor/StandardRefCursorSupportTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/refcursor/StandardRefCursorSupportTest.java deleted file mode 100644 index 691646bd08b3..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/refcursor/StandardRefCursorSupportTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.jdbc.refcursor; - -import java.sql.DatabaseMetaData; -import java.sql.SQLException; - -import org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.junit.Test; - -import org.mockito.Mockito; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -/** - * Unit test of the {@link StandardRefCursorSupport} class. - * - * @author Daniel Heinrich - */ -@JiraKey(value = "HHH-10612") -public class StandardRefCursorSupportTest { - - interface TestDatabaseMetaData extends DatabaseMetaData { - boolean supportsRefCursors() throws SQLException; - } - - @Test - public void testSupportsRefCursorsAboveJava8() throws Exception { - TestDatabaseMetaData metaMock = Mockito.mock(TestDatabaseMetaData.class); - Mockito.when(metaMock.supportsRefCursors()).thenReturn(true); - - boolean result = StandardRefCursorSupport.supportsRefCursors(metaMock); - assertThat(result, is(true)); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Animal.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Animal.java index 691049bdd705..27cc53cf036d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Animal.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Animal.java @@ -4,14 +4,11 @@ */ package org.hibernate.orm.test.jpa.criteria; -import java.util.Date; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; -import jakarta.persistence.Temporal; -import jakarta.persistence.TemporalType; /** * Animal @@ -24,7 +21,6 @@ public class Animal { private Animal mother; private Animal father; private String name; - private Date born; public String getName() { return name; @@ -60,13 +56,4 @@ public Animal getFather() { public void setFather(Animal father) { this.father = father; } - - @Temporal(TemporalType.TIMESTAMP) - public Date getBorn() { - return born; - } - - public void setBorn(Date born) { - this.born = born; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/HumanDTO.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/HumanDTO.java deleted file mode 100644 index 6ece660f63d6..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/HumanDTO.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.jpa.criteria; - -public class HumanDTO { - - private Long id; - - private String name; - - private String dateBorn; - - public HumanDTO(Long id, String name, String dateBorn) { - this.id = id; - this.name = name; - this.dateBorn = dateBorn; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDateBorn() { - return dateBorn; - } - - public void setDateBorn(String dateBorn) { - this.dateBorn = dateBorn; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/QueryBuilderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/QueryBuilderTest.java index 1033a13b4876..3c36fb7cc6bb 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/QueryBuilderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/QueryBuilderTest.java @@ -5,7 +5,6 @@ package org.hibernate.orm.test.jpa.criteria; import java.util.ArrayList; -import java.util.Date; import java.util.HashSet; import java.util.List; import jakarta.persistence.EntityManager; @@ -21,6 +20,8 @@ import org.hibernate.community.dialect.InformixDialect; import org.hibernate.dialect.CockroachDialect; +import org.hibernate.exception.GenericJDBCException; +import org.hibernate.exception.SQLGrammarException; import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; import org.hibernate.orm.test.jpa.metamodel.Address; import org.hibernate.orm.test.jpa.metamodel.Alias; @@ -37,13 +38,14 @@ import org.hibernate.orm.test.jpa.metamodel.Spouse; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.SkipForDialect; +import org.hibernate.testing.transaction.TransactionUtil2; import org.junit.Test; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; /** * @author Steve Ebersole @@ -282,36 +284,40 @@ public void testFunctionDialectFunctions() { @Test @JiraKey(value = "HHH-10737") - @FailureExpected(jiraKey = "HHH-10737") public void testMissingDialectFunction() { - doInJPA( this::entityManagerFactory, em -> { + TransactionUtil2.inTransaction( entityManagerFactory(), (em) -> { Human human = new Human(); human.setId( 200L ); human.setName( "2" ); - human.setBorn( new Date() ); em.persist( human ); + } ); - em.getTransaction().commit(); - + TransactionUtil2.inTransaction( entityManagerFactory(), (em) -> { CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery criteria = cb.createQuery( HumanDTO.class ); + CriteriaQuery criteria = cb.createQuery( Long.class ); + Root root = criteria.from( Human.class ); - criteria.select( - cb.construct( - HumanDTO.class, - root.get( Human_.id ), + criteria.select( cb.count( cb.literal( 1 ) ) ); + + criteria.where( + cb.equal( root.get( Human_.name ), cb.function( - "convert", + "does_not_exist", String.class, - root.get( Human_.born ), - cb.literal( 110 ) + root.get( Human_.id ) ) ) ); - em.createQuery( criteria ).getResultList(); + try { + em.createQuery( criteria ).getResultList(); + fail( "Expecting a SQLGrammarException" ); + } + catch (SQLGrammarException | GenericJDBCException expected) { + // on Sybase, this results in GenericJDBCException + } } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/InWithHeterogeneousCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/InWithHeterogeneousCollectionTest.java index a227c4139ef6..c96d8f8fb57f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/InWithHeterogeneousCollectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/InWithHeterogeneousCollectionTest.java @@ -4,101 +4,41 @@ */ package org.hibernate.orm.test.jpa.criteria.basic; -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; - -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Path; import jakarta.persistence.criteria.Root; - import org.hibernate.dialect.H2Dialect; -import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.domain.helpdesk.Ticket; +import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; -/** - * @author Jeremy Carnus - * @author Guillaume Smet - */ +import java.util.Arrays; + +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-12989") -public class InWithHeterogeneousCollectionTest extends BaseCoreFunctionalTestCase { +@RequiresDialect(value = H2Dialect.class, comment = "Not dialect specific") +@DomainModel(standardModels = StandardDomainModel.HELPDESK) +@SessionFactory +public class InWithHeterogeneousCollectionTest { @Test - @RequiresDialect(H2Dialect.class) - public void testCaseClause() { - doInHibernate( this::sessionFactory, session -> { - CriteriaBuilder cb = session.getCriteriaBuilder(); - - CriteriaQuery criteria = cb.createQuery( Event.class ); - - Root eventRoot = criteria.from( Event.class ); - Path namePath = eventRoot.get( "name" ); - Path tagPath = eventRoot.get( "tag" ); - - Expression expression = cb.function( - "lower", - String.class, - namePath ); - - criteria.select( eventRoot ); - criteria.where( tagPath.in( Arrays.asList( expression, "my-tag" ) ) ); - List resultList = session.createQuery( criteria ).getResultList(); - - Assert.assertEquals( 2, resultList.size() ); - } ); - } - - @Before - public void setup() { - doInHibernate( this::sessionFactory, session -> { - session.persist( new Event( 1L, "EventName1", "EventName1".toLowerCase( Locale.ROOT ) ) ); - session.persist( new Event( 2L, "EventName2", "my-tag" ) ); + public void testHeterogeneousInExpressions(SessionFactoryScope sessions) { + sessions.inTransaction( (session) -> { + final CriteriaBuilder cb = session.getCriteriaBuilder(); + + final CriteriaQuery criteria = cb.createQuery( Ticket.class ); + final Root root = criteria.from( Ticket.class ); + final Path keyPath = root.get( "key" ); + final Expression lowercaseKey = cb.lower( keyPath ); + criteria.where( keyPath.in( Arrays.asList( lowercaseKey, "HHH-1" ) ) ); + session.createQuery( criteria ).getResultList(); } ); } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[]{ Event.class }; - } - - @Entity(name = "Event") - public static class Event { - - @Id - private Long id; - - @Column - private String name; - - @Column - private String tag; - - protected Event() { - } - - public Event(Long id, String name, String tag) { - this.id = id; - this.name = name; - this.tag = tag; - } - - public String getName() { - return name; - } - - public String getTag() { - return tag; - } - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nestedfetch/NestedFetchTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nestedfetch/NestedFetchTest.java index 9de81ce967b4..044a7d9f6aad 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nestedfetch/NestedFetchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nestedfetch/NestedFetchTest.java @@ -4,164 +4,178 @@ */ package org.hibernate.orm.test.jpa.criteria.nestedfetch; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Set; - -import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; -import org.hibernate.testing.orm.junit.Jira; -import org.hibernate.testing.orm.junit.Jpa; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import jakarta.persistence.Embeddable; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; -import jakarta.persistence.IdClass; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; -import jakarta.persistence.PrimaryKeyJoinColumn; +import jakarta.persistence.Table; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Fetch; import jakarta.persistence.criteria.JoinType; import jakarta.persistence.criteria.Root; +import org.hibernate.testing.jdbc.SQLStatementInspector; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.Jira; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import java.util.HashSet; +import java.util.Set; -@Jpa( annotatedClasses = { - NestedFetchTest.RootEntity.class, - NestedFetchTest.Chil1PK.class, - NestedFetchTest.Child1Entity.class, - NestedFetchTest.Child2Entity.class, +import static org.assertj.core.api.Assertions.assertThat; + +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel( annotatedClasses = { + NestedFetchTest.Product.class, + NestedFetchTest.Customer.class, + NestedFetchTest.Order.class, + NestedFetchTest.OrderLine.class, } ) +@SessionFactory( useCollectingStatementInspector = true ) @Jira( "https://hibernate.atlassian.net/browse/HHH-16905" ) public class NestedFetchTest { @BeforeAll - public void setUp(EntityManagerFactoryScope scope) { - scope.inTransaction( entityManager -> { - final RootEntity root = new RootEntity(); - entityManager.persist( root ); - final Child2Entity child2 = new Child2Entity( "222" ); - entityManager.persist( child2 ); - final Child1Entity child1 = new Child1Entity( root, child2 ); - entityManager.persist( child1 ); + public void createTestData(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + final Product sprocket = new Product( 1, "Sprocket" ); + final Product thingamajig = new Product( 2, "Thingamajig" ); + session.persist( sprocket ); + session.persist( thingamajig ); + + final Customer ibm = new Customer( 1, "IBM" ); + session.persist( ibm ); + + final Order order = new Order( 1, "ibm-1", ibm ); + order.addOrderLine( sprocket, 20 ); + order.addOrderLine( thingamajig, 1500 ); + session.persist( order ); } ); } @AfterAll - public void tearDown(EntityManagerFactoryScope scope) { - scope.inTransaction( entityManager -> { - entityManager.createQuery( "delete from Child1Entity" ).executeUpdate(); - entityManager.createQuery( "delete from Child2Entity" ).executeUpdate(); - entityManager.createQuery( "delete from RootEntity" ).executeUpdate(); - } ); + public void tearDown(SessionFactoryScope scope) { + scope.dropData(); } @Test - public void testNestedFetch(EntityManagerFactoryScope scope) { - RootEntity rootEntity = scope.fromTransaction( entityManager -> { - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - final CriteriaQuery cq = cb.createQuery( RootEntity.class ); - final Root fromRoot = cq.from( RootEntity.class ); - final Fetch fetchDepth1 = fromRoot.fetch( - "child1Entities", - JoinType.LEFT - ); - final Fetch fetchDepth2 = fetchDepth1.fetch( - "child2Entity", - JoinType.LEFT - ); - return entityManager.createQuery( cq.select( fromRoot ) ).getSingleResult(); + public void testNestedFetch(SessionFactoryScope scope) { + final SQLStatementInspector sqlCollector = scope.getCollectingStatementInspector(); + sqlCollector.clear(); + + final Customer customer = scope.fromTransaction( (session) -> { + final CriteriaBuilder cb = session.getCriteriaBuilder(); + final CriteriaQuery criteria = cb.createQuery( Customer.class ); + final Root fromRoot = criteria.from( Customer.class ); + final Fetch ordersFetch = fromRoot.fetch( "orders", JoinType.LEFT ); + final Fetch linesFetch = ordersFetch.fetch( "lines", JoinType.LEFT ); + final Fetch productFetch = linesFetch.fetch( "product", JoinType.LEFT ); + return session.createQuery( criteria.select( fromRoot ) ).getSingleResult(); } ); - //dependent relations should already be fetched and be available outside the transaction - assertThat( rootEntity.getChild1Entities().size() ).isEqualTo( 1 ); - final Child1Entity depth1Entity = rootEntity.getChild1Entities().iterator().next(); - final Child2Entity depth2Entity = depth1Entity.getChild2Entity(); - assertThat( depth2Entity ).isNotNull(); - assertThat( depth2Entity.getVal() ).isEqualTo( "222" ); + + // make sure that the fetches really got fetched... + assertThat( customer.orders ).hasSize( 1 ); + final Order order = customer.orders.iterator().next(); + assertThat( order.lines ).hasSize( 2 ); + assertThat( order.lines.stream().map( orderLine -> orderLine.product.name ) ) + .contains( "Sprocket", "Thingamajig" ); + + // should have happened by joins + assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); } - @Entity( name = "RootEntity" ) - public static class RootEntity { + @Entity + @Table(name="products") + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class Product { @Id - @GeneratedValue - private int id; - - @OneToMany( mappedBy = "rootEntity" ) - private Set child1Entities; + private Integer id; + private String name; - public Set getChild1Entities() { - return child1Entities; + public Product() { } - } - @Embeddable - public static class Chil1PK implements Serializable { - @ManyToOne( fetch = FetchType.LAZY ) - @JoinColumn( name = "rootId", referencedColumnName = "id", nullable = false ) - private RootEntity rootEntity; - - @ManyToOne( fetch = FetchType.LAZY ) - @JoinColumn( name = "child2Id", referencedColumnName = "id", nullable = false ) - private Child2Entity child2Entity; + public Product(Integer id, String name) { + this.id = id; + this.name = name; + } } - @Entity( name = "Child1Entity" ) - @IdClass( Chil1PK.class ) - public static class Child1Entity { + @Entity + @Table(name="customers") + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class Customer { @Id - @PrimaryKeyJoinColumn( name = "rootId", referencedColumnName = "id" ) - @ManyToOne( fetch = FetchType.LAZY ) - private RootEntity rootEntity; - - @Id - @PrimaryKeyJoinColumn( name = "child2Id", referencedColumnName = "id" ) - @ManyToOne( fetch = FetchType.LAZY ) - private Child2Entity child2Entity; - - public Child1Entity() { - } + private Integer id; + private String name; + @OneToMany( mappedBy = "customer" ) + private Set orders = new HashSet<>(); - public Child1Entity(RootEntity rootEntity, Child2Entity child2Entity) { - this.rootEntity = rootEntity; - this.child2Entity = child2Entity; + public Customer() { } - public Child2Entity getChild2Entity() { - return child2Entity; + public Customer(Integer id, String name) { + this.id = id; + this.name = name; } } - - @Entity( name = "Child2Entity" ) - public static class Child2Entity { + @Entity + @Table(name="orders") + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class Order { @Id - @GeneratedValue - private int id; - - @OneToMany( mappedBy = "child2Entity" ) - private Set child1Entities = new HashSet<>(); - - private String val; + private Integer id; + private String orderNumber; + @ManyToOne + @JoinColumn(name = "customer_fk") + private Customer customer; + @OneToMany( mappedBy = "order", cascade = CascadeType.ALL) + private Set lines = new HashSet<>(); + + public Order() { + } - public Child2Entity() { + public Order(Integer id, String orderNumber, Customer customer) { + this.id = id; + this.orderNumber = orderNumber; + this.customer = customer; + customer.orders.add( this ); } - public Child2Entity(String val) { - this.val = val; + public void addOrderLine(Product product, int quantity) { + lines.add( new OrderLine( this, product, quantity ) ); } + } - public String getVal() { - return val; + @Entity(name="OrderLine") + @Table(name="OrderLine") + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class OrderLine { + @Id + @GeneratedValue + private Integer id; + @ManyToOne + @JoinColumn(name="order_fk") + private Order order; + @ManyToOne + @JoinColumn(name="product_fk") + private Product product; + private int quantity; + + public OrderLine() { } - public Set getChild1Entities() { - return child1Entities; + public OrderLine(Order order, Product product, int quantity) { + this.order = order; + this.product = product; + this.quantity = quantity; } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/DynamicModelSingularAttributeJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/DynamicModelSingularAttributeJoinTest.java new file mode 100644 index 000000000000..043f4c7947e8 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/DynamicModelSingularAttributeJoinTest.java @@ -0,0 +1,77 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.jpa.criteria.paths; + +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.From; +import jakarta.persistence.criteria.Path; +import jakarta.persistence.criteria.Root; +import jakarta.persistence.metamodel.EntityType; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; + +/** + * Test query paths (both HQL and Criteria) with dynamic models + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@Jpa( + integrationSettings = {@Setting(name = AvailableSettings.JPA_METAMODEL_POPULATION, value = "enabled")}, + xmlMappings = {"org/hibernate/orm/test/jpa/criteria/paths/dynamic-model.hbm.xml"} +) +public class DynamicModelSingularAttributeJoinTest { + @Test + void testHql(EntityManagerFactoryScope scope) { + scope.inTransaction( (entityManager) -> { + entityManager.createQuery( "select d.id from Distribution d" ).getResultList(); + entityManager.createQuery( "select p.id from Policy p" ).getResultList(); + entityManager.createQuery( "select p.id from Distribution d join d.policy p" ).getResultList(); + } ); + } + + @Test + public void testCriteria(EntityManagerFactoryScope scope) { + final EntityType distributionType = scope.getEntityManagerFactory().getMetamodel().entity( "Distribution" ); + final EntityType policyType = scope.getEntityManagerFactory().getMetamodel().entity( "Policy" ); + + scope.inEntityManager( (entityManager) -> { + final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + + final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery( Integer.class ); + final Root root = criteriaQuery.from( distributionType ); + final Path distributionId = root.get( "id" ); + criteriaQuery.select( distributionId ); + + entityManager.createQuery( criteriaQuery ).getResultList(); + + } ); + + scope.inEntityManager( (entityManager) -> { + final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + + final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery( Integer.class ); + final Root root = criteriaQuery.from( policyType ); + final Path policyId = root.get( "id" ); + criteriaQuery.select( policyId ); + + entityManager.createQuery( criteriaQuery ).getResultList(); + } ); + + scope.inEntityManager( (entityManager) -> { + final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + + final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery( Integer.class ); + final Root root = criteriaQuery.from( distributionType ); + final From join = root.join( "policy" ); + final Path policyId = join.get( "id" ); + criteriaQuery.select( policyId ); + + entityManager.createQuery( criteriaQuery ).getResultList(); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/SingularAttributeJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/SingularAttributeJoinTest.java deleted file mode 100644 index 0921bf8001e8..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/SingularAttributeJoinTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.jpa.criteria.paths; - -import jakarta.persistence.TypedQuery; -import jakarta.persistence.criteria.CriteriaBuilder; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.From; -import jakarta.persistence.criteria.Path; - -import org.hibernate.cfg.AvailableSettings; - -import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; -import org.hibernate.testing.orm.junit.Jpa; -import org.hibernate.testing.orm.junit.Setting; - -import org.junit.jupiter.api.Test; - -/** - * @author Brad Koehn - */ -@Jpa( - integrationSettings = { @Setting(name = AvailableSettings.JPA_METAMODEL_POPULATION, value = "enabled") }, - xmlMappings = { "org/hibernate/orm/test/jpa/criteria/paths/PolicyAndDistribution.hbm.xml" } -) -public class SingularAttributeJoinTest { - - @Test - public void testEntityModeMapJoinCriteriaQuery(EntityManagerFactoryScope scope) { - scope.inEntityManager( - entityManager -> { - CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(); - jakarta.persistence.metamodel.EntityType distributionEntity = getEntityType(scope, "Distribution"); - From distributionFrom = criteriaQuery.from(distributionEntity); - From policyJoin = distributionFrom.join("policy"); - Path policyId = policyJoin.get("policyId"); - criteriaQuery.select(policyId); - TypedQuery typedQuery = entityManager.createQuery(criteriaQuery); - } - ); - } - - private jakarta.persistence.metamodel.EntityType getEntityType(EntityManagerFactoryScope scope, String entityName) { - for(jakarta.persistence.metamodel.EntityType entityType : scope.getEntityManagerFactory().getMetamodel().getEntities()) { - if (entityType.getName().equals("Distribution")) { - return entityType; - } - } - throw new IllegalStateException("Unable to find entity " + entityName); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/GroupBySelectCaseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/GroupBySelectCaseTest.java index 926e6cf438b6..c749700b20c1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/GroupBySelectCaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/GroupBySelectCaseTest.java @@ -4,45 +4,41 @@ */ package org.hibernate.orm.test.jpa.criteria.selectcase; -import java.util.List; import jakarta.persistence.Entity; import jakarta.persistence.Id; +import jakarta.persistence.Table; import jakarta.persistence.Tuple; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; - -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; import org.hibernate.orm.test.jpa.metadata.Person_; - +import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; -import org.junit.Test; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import java.util.List; -@JiraKey(value = "HHH-12230") -public class GroupBySelectCaseTest extends BaseEntityManagerFunctionalTestCase { +import static org.assertj.core.api.Assertions.assertThat; - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Person.class }; - } +@SuppressWarnings("JUnitMalformedDeclaration") +@JiraKey(value = "HHH-12230") +@DomainModel( annotatedClasses = GroupBySelectCaseTest.Person.class ) +@SessionFactory +public class GroupBySelectCaseTest { @Test - @JiraKey(value = "HHH-12230") - public void selectCaseInGroupByAndSelectExpression() { - - doInJPA( this::entityManagerFactory, entityManager -> { - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery query = cb.createTupleQuery(); - Root from = query.from( Person.class ); - - Predicate childPredicate = cb.between( from.get( Person_.AGE ), 0, 10 ); - Predicate teenagerPredicate = cb.between( from.get( Person_.AGE ), 11, 20 ); - CriteriaBuilder.Case selectCase = cb.selectCase(); + public void selectCaseInGroupByAndSelectExpression(SessionFactoryScope sessions) { + sessions.inTransaction( (entityManager) -> { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery query = cb.createTupleQuery(); + final Root from = query.from( Person.class ); + + final Predicate childPredicate = cb.between( from.get( Person_.AGE ), 0, 10 ); + final Predicate teenagerPredicate = cb.between( from.get( Person_.AGE ), 11, 20 ); + final CriteriaBuilder.Case selectCase = cb.selectCase(); selectCase.when( childPredicate, "child" ) .when( teenagerPredicate, "teenager" ) .otherwise( "adult" ); @@ -50,24 +46,22 @@ public void selectCaseInGroupByAndSelectExpression() { query.multiselect( selectCase ); query.groupBy( selectCase ); - List resultList = entityManager.createQuery( query ).getResultList(); - assertNotNull( resultList ); - assertTrue( resultList.isEmpty() ); + final List resultList = entityManager.createQuery( query ).getResultList(); + assertThat( resultList ).isNotNull(); + assertThat( resultList ).isEmpty(); } ); } @Test - @JiraKey(value = "HHH-12230") - public void selectCaseInOrderByAndSelectExpression() { - - doInJPA( this::entityManagerFactory, entityManager -> { - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery query = cb.createTupleQuery(); - Root from = query.from( Person.class ); - - Predicate childPredicate = cb.between( from.get( Person_.AGE ), 0, 10 ); - Predicate teenagerPredicate = cb.between( from.get( Person_.AGE ), 11, 20 ); - CriteriaBuilder.Case selectCase = cb.selectCase(); + public void selectCaseInOrderByAndSelectExpression(SessionFactoryScope sessions) { + sessions.inTransaction( (entityManager) -> { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery query = cb.createTupleQuery(); + final Root from = query.from( Person.class ); + + final Predicate childPredicate = cb.between( from.get( Person_.AGE ), 0, 10 ); + final Predicate teenagerPredicate = cb.between( from.get( Person_.AGE ), 11, 20 ); + final CriteriaBuilder.Case selectCase = cb.selectCase(); selectCase.when( childPredicate, "child" ) .when( teenagerPredicate, "teenager" ) .otherwise( "adult" ); @@ -75,18 +69,17 @@ public void selectCaseInOrderByAndSelectExpression() { query.multiselect( selectCase ); query.orderBy( cb.asc( selectCase ) ); - List resultList = entityManager.createQuery( query ).getResultList(); - assertNotNull( resultList ); - assertTrue( resultList.isEmpty() ); + final List resultList = entityManager.createQuery( query ).getResultList(); + assertThat( resultList ).isNotNull(); + assertThat( resultList ).isEmpty(); } ); } @Entity(name = "Person") + @Table(name="persons") public static class Person { - @Id private Long id; - private Integer age; } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/enhancement/TestLazyPropertyOnPreUpdate.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/enhancement/TestLazyPropertyOnPreUpdate.java index 83f42b77b351..2837079b6375 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/enhancement/TestLazyPropertyOnPreUpdate.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/enhancement/TestLazyPropertyOnPreUpdate.java @@ -4,69 +4,51 @@ */ package org.hibernate.orm.test.jpa.enhancement; -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - +import jakarta.persistence.Basic; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityManager; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Table; import org.hibernate.Hibernate; +import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.persister.entity.EntityPersister; - import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.transaction.TransactionUtil.JPATransactionVoidFunction; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import jakarta.persistence.Basic; -import jakarta.persistence.Entity; -import jakarta.persistence.EntityManager; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.PreUpdate; -import jakarta.persistence.Table; - -import java.util.Arrays; +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +/** + * Test the behavior of bytecode lazy attributes and {@link PreUpdate @PreUpdate} callbacks + */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey("HHH-7573") -@DomainModel( - annotatedClasses = { - TestLazyPropertyOnPreUpdate.EntityWithLazyProperty.class - } -) +@DomainModel( annotatedClasses = { TestLazyPropertyOnPreUpdate.EntityWithCallback.class } ) @SessionFactory @BytecodeEnhanced public class TestLazyPropertyOnPreUpdate { + private static final byte[] INITIAL_VALUE = new byte[] { 0x2A }; - private EntityWithLazyProperty entity; - + private static boolean UPDATE_IN_PRE_UPDATE; + private static final byte[] PRE_UPDATE_VALUE = new byte[] { 0x2A, 0x2A, 0x2A, 0x2A }; - @BeforeEach - public void prepare(SessionFactoryScope scope) throws Exception { - EntityPersister ep = scope.getSessionFactory().getMappingMetamodel().getEntityDescriptor( - EntityWithLazyProperty.class.getName() ); - assertTrue( ep.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ); - - byte[] testArray = new byte[] { 0x2A }; - - scope.inTransaction( em -> { - //persist the test entity.d - entity = new EntityWithLazyProperty(); - entity.setSomeField( "TEST" ); - entity.setLazyData( testArray ); - em.persist( entity ); - } ); - - checkLazyField( scope, entity, testArray ); - } + private EntityWithCallback entityUnderTest; /** - * Set a non lazy field, therefore the lazyData field will be LazyPropertyInitializer.UNFETCHED_PROPERTY - * for both state and newState so the field should not change. This should no longer cause a ClassCastException. + * Update the `name` field; the `lazyData` field will remain + * {@linkplain LazyPropertyInitializer#UNFETCHED_PROPERTY uninitialized}. */ @Test public void testNoUpdate(SessionFactoryScope scope) { @@ -75,43 +57,41 @@ public void testNoUpdate(SessionFactoryScope scope) { doInJPA( scope::getSessionFactory, new JPATransactionVoidFunction() { @Override public void accept(EntityManager em) { - entity = em.find( EntityWithLazyProperty.class, entity.id ); - entity.setSomeField( "TEST1" ); - assertFalse( Hibernate.isPropertyInitialized( entity, "lazyData" ) ); + entityUnderTest = em.find( EntityWithCallback.class, 1 ); + entityUnderTest.setName( "updated name" ); + assertFalse( Hibernate.isPropertyInitialized( entityUnderTest, "lazyData" ) ); } @Override public void afterTransactionCompletion() { - assertFalse( Hibernate.isPropertyInitialized( entity, "lazyData" ) ); + assertFalse( Hibernate.isPropertyInitialized( entityUnderTest, "lazyData" ) ); } } ); - checkLazyField( scope, entity, testArray ); + checkLazyField( scope, testArray ); } /** - * Set the updateLazyFieldInPreUpdate flag so that the lazy field is updated from within the - * PreUpdate annotated callback method. So state == LazyPropertyInitializer.UNFETCHED_PROPERTY and - * newState == EntityWithLazyProperty.PRE_UPDATE_VALUE. This should no longer cause a ClassCastException. + * Set UPDATE_FIELD_IN_CALLBACK so that `lazyField` is updated during the pre-update callback. */ @Test public void testPreUpdate(SessionFactoryScope scope) { + UPDATE_IN_PRE_UPDATE = true; doInJPA( scope::getSessionFactory, new JPATransactionVoidFunction() { @Override public void accept(EntityManager em) { - entity = em.find( EntityWithLazyProperty.class, entity.id ); - entity.setUpdateLazyFieldInPreUpdate( true ); - entity.setSomeField( "TEST2" ); - assertFalse( Hibernate.isPropertyInitialized( entity, "lazyData" ) ); + entityUnderTest = em.find( EntityWithCallback.class, 1 ); + entityUnderTest.setName( "updated name" ); + assertFalse( Hibernate.isPropertyInitialized( entityUnderTest, "lazyData" ) ); } @Override public void afterTransactionCompletion() { - assertTrue( Hibernate.isPropertyInitialized( entity, "lazyData" ) ); + assertTrue( Hibernate.isPropertyInitialized( entityUnderTest, "lazyData" ) ); } } ); - checkLazyField( scope, entity, EntityWithLazyProperty.PRE_UPDATE_VALUE ); + checkLazyField( scope, PRE_UPDATE_VALUE ); } /** @@ -121,70 +101,95 @@ public void afterTransactionCompletion() { */ @Test public void testPreUpdateOverride(SessionFactoryScope scope) { - byte[] testArray = new byte[] { 0x2A }; + UPDATE_IN_PRE_UPDATE = true; scope.inTransaction( em -> { - entity = em.find( EntityWithLazyProperty.class, entity.id ); - entity.setUpdateLazyFieldInPreUpdate( true ); - assertFalse( Hibernate.isPropertyInitialized( entity, "lazyData" ) ); - entity.setLazyData( testArray ); - assertTrue( Hibernate.isPropertyInitialized( entity, "lazyData" ) ); - entity.setSomeField( "TEST3" ); + entityUnderTest = em.find( EntityWithCallback.class, 1 ); + assertFalse( Hibernate.isPropertyInitialized( entityUnderTest, "lazyData" ) ); + entityUnderTest.setLazyData( INITIAL_VALUE ); + assertTrue( Hibernate.isPropertyInitialized( entityUnderTest, "lazyData" ) ); + entityUnderTest.setName( "updated name" ); } ); - checkLazyField( scope, entity, EntityWithLazyProperty.PRE_UPDATE_VALUE ); + checkLazyField( scope, PRE_UPDATE_VALUE ); } - private void checkLazyField(SessionFactoryScope scope, EntityWithLazyProperty entity, byte[] expected) { + private void checkLazyField(SessionFactoryScope scope, byte[] expected) { // reload the entity and check the lazy value matches what we expect. scope.inTransaction( em -> { - EntityWithLazyProperty testEntity = em.find( EntityWithLazyProperty.class, entity.id ); + EntityWithCallback testEntity = em.find( EntityWithCallback.class, 1 ); assertFalse( Hibernate.isPropertyInitialized( testEntity, "lazyData" ) ); - assertTrue( Arrays.equals( expected, testEntity.lazyData ) ); + assertArrayEquals( expected, testEntity.lazyData ); assertTrue( Hibernate.isPropertyInitialized( testEntity, "lazyData" ) ); } ); } - // --- // + @BeforeEach + public void createTestData(SessionFactoryScope scope) throws Exception { + EntityPersister ep = scope.getSessionFactory().getMappingMetamodel().getEntityDescriptor( EntityWithCallback.class ); + assertTrue( ep.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ); - /** - * Test entity with a lazy property which requires build time instrumentation. - * - * @author Martin Ball - */ - @Entity - @Table(name = "ENTITY_WITH_LAZY_PROPERTY") - static class EntityWithLazyProperty { - public static final byte[] PRE_UPDATE_VALUE = new byte[] { 0x2A, 0x2A, 0x2A, 0x2A }; + scope.inTransaction( em -> { + entityUnderTest = new EntityWithCallback( 1, "initial name", INITIAL_VALUE ); + em.persist( entityUnderTest ); + } ); - @Id - @GeneratedValue - private Long id; + checkLazyField( scope, INITIAL_VALUE ); + } + + @AfterEach + public void dropTestData(SessionFactoryScope scope) throws Exception { + scope.dropData(); + } + @Entity(name="EntityWithCallback") + @Table(name="entity_with_callback") + public static class EntityWithCallback { + @Id + private Integer id; + @Basic(fetch = FetchType.EAGER) + private String name; @Basic(fetch = FetchType.LAZY) private byte[] lazyData; - private String someField; - - private boolean updateLazyFieldInPreUpdate; + public EntityWithCallback() { + } - public void setLazyData(byte[] lazyData) { + public EntityWithCallback(Integer id, String name, byte[] lazyData) { + this.id = id; + this.name = name; this.lazyData = lazyData; } - public void setSomeField(String someField) { - this.someField = someField; + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; } - public void setUpdateLazyFieldInPreUpdate(boolean updateLazyFieldInPreUpdate) { - this.updateLazyFieldInPreUpdate = updateLazyFieldInPreUpdate; + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public byte[] getLazyData() { + return lazyData; + } + + public void setLazyData(byte[] lazyData) { + this.lazyData = lazyData; } @PreUpdate public void onPreUpdate() { //Allow the update of the lazy field from within the pre update to check that this does not break things. - if ( updateLazyFieldInPreUpdate ) { + if ( UPDATE_IN_PRE_UPDATE ) { this.lazyData = PRE_UPDATE_VALUE; } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Lockable.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Lockable.java index 61172f6e1ecc..45956b04de91 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Lockable.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Lockable.java @@ -9,8 +9,6 @@ import jakarta.persistence.Version; /** - * TODO : javadoc - * * @author Steve Ebersole */ @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/OptimisticLockTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/OptimisticLockTests.java new file mode 100644 index 000000000000..10a0b6fe2f52 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/OptimisticLockTests.java @@ -0,0 +1,61 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.jpa.lock; + +import jakarta.persistence.LockModeType; +import org.hibernate.engine.spi.ActionQueue; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.testing.jdbc.SQLStatementInspector; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = Lockable.class) +@SessionFactory(useCollectingStatementInspector = true) +public class OptimisticLockTests { + @Test + @JiraKey(value = "HHH-9419") + public void testNoVersionCheckAfterRemove(SessionFactoryScope sessions) { + final SQLStatementInspector sqlCollector = sessions.getCollectingStatementInspector(); + sqlCollector.clear(); + + final Lockable created = sessions.fromTransaction( (session) -> { + final Lockable entity = new Lockable( "name" ); + session.persist( entity ); + return entity; + } ); + assertThat( created.getVersion() ).isEqualTo( 0 ); + + final Lockable locked = sessions.fromTransaction( (session) -> { + final ActionQueue actionQueue = session.unwrap( SessionImplementor.class ).getActionQueue(); + assertThat( actionQueue.hasBeforeTransactionActions() ).isFalse(); + + final Lockable loaded = session.createQuery( "from Lockable", Lockable.class ) + .setLockMode( LockModeType.OPTIMISTIC ) + .getSingleResult(); + assertThat( loaded.getVersion() ).isEqualTo( 0 ); + assertThat( actionQueue.hasBeforeTransactionActions() ).isTrue(); + + sqlCollector.clear(); + session.remove( loaded ); + + return loaded; + } ); + + assertThat( locked.getVersion() ).isEqualTo( 0 ); + + // should be just the deletion + assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); + assertThat( sqlCollector.getSqlQueries().get( 0 ) ).startsWith( "delete from Lockable " ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/QueryLockingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/QueryLockingTest.java index 49471e70e216..3b4ff004eb5e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/QueryLockingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/QueryLockingTest.java @@ -288,31 +288,6 @@ public void testOptimisticOverall() { em.close(); } - @Test - @JiraKey(value = "HHH-9419") - public void testNoVersionCheckAfterRemove() { - EntityManager em = getOrCreateEntityManager(); - em.getTransaction().begin(); - Lockable lock = new Lockable( "name" ); - em.persist( lock ); - em.getTransaction().commit(); - em.close(); - Integer initial = lock.getVersion(); - assertNotNull( initial ); - - em = getOrCreateEntityManager(); - em.getTransaction().begin(); - Lockable reread = em.createQuery( "from Lockable", Lockable.class ) - .setLockMode( LockModeType.OPTIMISTIC ) - .getSingleResult(); - assertEquals( initial, reread.getVersion() ); - assertTrue( em.unwrap( SessionImpl.class ).getActionQueue().hasBeforeTransactionActions() ); - em.remove( reread ); - em.getTransaction().commit(); - em.close(); - assertEquals( initial, reread.getVersion() ); - } - @Test public void testOptimisticSpecific() { EntityManager em = getOrCreateEntityManager(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/MapIssueTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/MapIssueTest.java index a197550ce62a..6d18fb803eed 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/MapIssueTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ql/MapIssueTest.java @@ -5,32 +5,29 @@ package org.hibernate.orm.test.jpa.ql; import org.hibernate.dialect.PostgreSQLDialect; - import org.hibernate.orm.test.jpa.model.MapContent; import org.hibernate.orm.test.jpa.model.MapOwner; import org.hibernate.orm.test.jpa.model.Relationship; -import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.jdbc.SQLStatementInspector; import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.RequiresDialect; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.junit.jupiter.api.Test; +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-14279") -@DomainModel( - annotatedClasses = { - MapOwner.class, MapContent.class, Relationship.class - }) +@DomainModel( annotatedClasses = { MapOwner.class, MapContent.class, Relationship.class } ) @SessionFactory(useCollectingStatementInspector = true) public class MapIssueTest { @Test @RequiresDialect(value = PostgreSQLDialect.class, comment = "Requires support for using a correlated column in a join condition which H2 apparently does not support. For simplicity just run this on PostgreSQL") public void testWhereSubqueryMapKeyIsEntityWhereWithKey(SessionFactoryScope scope) { - scope.inTransaction( - s -> { - s.createQuery( "select r from Relationship r where exists (select 1 from MapOwner as o left join o.contents c with key(c) = r)" ).list(); + scope.inTransaction( (session) -> { + //noinspection deprecation + session.createQuery( "select r from Relationship r where exists (select 1 from MapOwner as o left join o.contents c with key(c) = r)" ).list(); } ); } @@ -39,98 +36,91 @@ public void testWhereSubqueryMapKeyIsEntityWhereWithKey(SessionFactoryScope scop public void testOnlyCollectionTableJoined(SessionFactoryScope scope) { SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); statementInspector.clear(); - scope.inTransaction( - s -> { - s.createQuery( "select 1 from MapOwner as o left join o.contents c where c.id is not null" ).list(); - statementInspector.assertExecutedCount( 1 ); - // Assert only the collection table is joined - statementInspector.assertNumberOfJoins( 0, 1 ); - } - ); + scope.inTransaction( (session) -> { + //noinspection deprecation + session.createQuery( "select 1 from MapOwner as o left join o.contents c where c.id is not null" ).list(); + statementInspector.assertExecutedCount( 1 ); + // Assert only the collection table is joined + statementInspector.assertNumberOfJoins( 0, 1 ); + } ); } @Test public void testMapKeyJoinIsNotOmitted(SessionFactoryScope scope) { SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); statementInspector.clear(); - scope.inTransaction( - s -> { - s.createQuery( "select c from MapOwner as o join o.contents c join c.relationship r where r.id is not null" ).list(); - statementInspector.assertExecutedCount( 1 ); - // Assert 3 joins, collection table, collection element and collection key (relationship) - statementInspector.assertNumberOfJoins( 0, 3 ); - } - ); + scope.inTransaction( (session) -> { + //noinspection deprecation + session.createQuery( "select c from MapOwner as o join o.contents c join c.relationship r where r.id is not null" ).list(); + statementInspector.assertExecutedCount( 1 ); + // Assert 3 joins, collection table, collection element and collection key (relationship) + statementInspector.assertNumberOfJoins( 0, 3 ); + } ); } @Test public void testMapKeyJoinIsOmitted2(SessionFactoryScope scope) { SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); statementInspector.clear(); - scope.inTransaction( - s -> { - s.createQuery( "select c from MapOwner as o join o.contents c where c.relationship.id is not null" ).list(); - statementInspector.assertExecutedCount( 1 ); - // Assert 2 joins, collection table and collection element. No need to join the relationship because it is not nullable - statementInspector.assertNumberOfJoins( 0, 2 ); - } - ); + scope.inTransaction( (session) -> { + //noinspection deprecation + session.createQuery( "select c from MapOwner as o join o.contents c where c.relationship.id is not null" ).list(); + statementInspector.assertExecutedCount( 1 ); + // Assert 2 joins, collection table and collection element. No need to join the relationship because it is not nullable + statementInspector.assertNumberOfJoins( 0, 2 ); + } ); } @Test public void testMapKeyDeReferenceDoesNotCauseJoin(SessionFactoryScope scope) { SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); statementInspector.clear(); - scope.inTransaction( - s -> { - s.createQuery( "select c from MapOwner as o left join o.contents c where key(c).id is not null" ).list(); - statementInspector.assertExecutedCount( 1 ); - // Assert 2 joins, collection table and collection element - statementInspector.assertNumberOfJoins( 0, 2 ); - } - ); + scope.inTransaction( (session) -> { + //noinspection deprecation + session.createQuery( "select c from MapOwner as o left join o.contents c where key(c).id is not null" ).list(); + statementInspector.assertExecutedCount( 1 ); + // Assert 2 joins, collection table and collection element + statementInspector.assertNumberOfJoins( 0, 2 ); + } ); } @Test public void testMapKeyJoinIsReused(SessionFactoryScope scope) { SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); statementInspector.clear(); - scope.inTransaction( - s -> { - s.createQuery( "select key(c), c from MapOwner as o left join o.contents c join c.relationship r where r.name is not null" ).list(); - statementInspector.assertExecutedCount( 1 ); - // Assert 3 joins, collection table, collection element and relationship - statementInspector.assertNumberOfJoins( 0, 3 ); - } - ); + scope.inTransaction( (s) -> { + //noinspection deprecation + s.createQuery( "select key(c), c from MapOwner as o left join o.contents c join c.relationship r where r.name is not null" ).list(); + statementInspector.assertExecutedCount( 1 ); + // Assert 3 joins, collection table, collection element and relationship + statementInspector.assertNumberOfJoins( 0, 3 ); + } ); } @Test public void testMapKeyJoinIsReusedForFurtherJoin(SessionFactoryScope scope) { SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); statementInspector.clear(); - scope.inTransaction( - s -> { - s.createQuery( "select key(c), c from MapOwner as o left join o.contents c join c.relationship r join r.self s where s.name is not null" ).list(); - statementInspector.assertExecutedCount( 1 ); - // Assert 3 joins, collection table, collection element, relationship and self - statementInspector.assertNumberOfJoins( 0, 4 ); - } - ); + scope.inTransaction( (session) -> { + //noinspection deprecation + session.createQuery( "select key(c), c from MapOwner as o left join o.contents c join c.relationship r join r.self s where s.name is not null" ).list(); + statementInspector.assertExecutedCount( 1 ); + // Assert 3 joins, collection table, collection element, relationship and self + statementInspector.assertNumberOfJoins( 0, 4 ); + } ); } @Test public void testMapKeyJoinIsReusedForFurtherJoinAndElementJoinIsProperlyOrdered(SessionFactoryScope scope) { SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); statementInspector.clear(); - scope.inTransaction( - s -> { - s.createQuery( "select key(c), c from MapOwner as o left join o.contents c join c.relationship r join r.self s join c.relationship2 where s.name is not null" ).list(); - statementInspector.assertExecutedCount( 1 ); - // Assert 3 joins, collection table, collection element, relationship, relationship2 and self - statementInspector.assertNumberOfJoins( 0, 5 ); - } - ); + scope.inTransaction( (session) -> { + //noinspection deprecation + session.createQuery( "select key(c), c from MapOwner as o left join o.contents c join c.relationship r join r.self s join c.relationship2 where s.name is not null" ).list(); + statementInspector.assertExecutedCount( 1 ); + // Assert 3 joins, collection table, collection element, relationship, relationship2 and self + statementInspector.assertNumberOfJoins( 0, 5 ); + } ); } @Test @@ -138,13 +128,12 @@ public void testMapKeyJoinIsReusedForFurtherJoinAndElementJoinIsProperlyOrdered( public void testSelectMapKeyFk(SessionFactoryScope scope) { SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); statementInspector.clear(); - scope.inTransaction( - s -> { - s.createQuery( "select key(c).id from MapOwner as o left join o.contents c" ).list(); - statementInspector.assertExecutedCount( 1 ); - // Assert that only the collection table and element table are joined - statementInspector.assertNumberOfJoins( 0, 2 ); - } - ); + scope.inTransaction( (session) -> { + //noinspection deprecation + session.createQuery( "select key(c).id from MapOwner as o left join o.contents c" ).list(); + statementInspector.assertExecutedCount( 1 ); + // Assert that only the collection table and element table are joined + statementInspector.assertNumberOfJoins( 0, 2 ); + } ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryTest.java index 2ea272f064e2..8b1a973eae60 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryTest.java @@ -4,25 +4,6 @@ */ package org.hibernate.orm.test.jpa.query; -import static org.assertj.core.api.Assertions.assertThat; -import static org.hibernate.jpa.HibernateHints.HINT_NATIVE_LOCK_MODE; -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; - -import java.util.List; - -import org.hibernate.LockMode; -import org.hibernate.Session; -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; -import org.hibernate.query.NativeQuery; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.orm.junit.JiraKey; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; @@ -33,6 +14,20 @@ import jakarta.persistence.Query; import jakarta.persistence.TypedQuery; import org.assertj.core.api.InstanceOfAssertFactories; +import org.hibernate.Session; +import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; +import org.hibernate.query.NativeQuery; +import org.hibernate.testing.orm.junit.JiraKey; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; /** * @author Andrea Boriero @@ -270,18 +265,6 @@ public void testNamedQueryAddedFromEntityNativeQueryUsedAsUntyped() { } ); } - @Test - @JiraKey(value = "HHH-14816") - public void testQueryHintLockMode() { - doInJPA( this::entityManagerFactory, entityManager -> { - Query query = entityManager.createNamedQuery( "NamedNativeQuery" ); - query.setHint( HINT_NATIVE_LOCK_MODE, "none" ); - query.setParameter( 1, GAME_TITLES[0] ); - assertEquals( LockMode.NONE, query.getHints().get( HINT_NATIVE_LOCK_MODE ) ); - } - ); - } - @Entity(name = "Game") @NamedQueries(@NamedQuery(name = "NamedQuery", query = "select g from Game g where title = ?1")) @NamedNativeQueries(@NamedNativeQuery(name = "NamedNativeQuery", query = "select * from Game g where title = ?")) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NativeQueryLockingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NativeQueryLockingTests.java new file mode 100644 index 000000000000..292037423fe6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NativeQueryLockingTests.java @@ -0,0 +1,99 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.jpa.query; + +import jakarta.persistence.LockModeType; +import jakarta.persistence.Query; +import org.hibernate.LockMode; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.jpa.HibernateHints; +import org.hibernate.query.sql.spi.NativeQueryImplementor; +import org.hibernate.testing.jdbc.SQLStatementInspector; +import org.hibernate.testing.orm.domain.gambit.SimpleEntity; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + + +import java.util.Locale; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = SimpleEntity.class) +@SessionFactory(useCollectingStatementInspector = true) +public class NativeQueryLockingTests { + final String QUERY_STRING = "select * from SIMPLE_ENTITY"; + + @Test + void testJpaLockMode(SessionFactoryScope sessions) { + // JPA says this is illegal + + sessions.inTransaction( (session) -> { + final Query query = session.createNativeQuery( QUERY_STRING, SimpleEntity.class ); + try { + query.setLockMode( LockModeType.PESSIMISTIC_WRITE ); + fail( "Expecting failure per JPA" ); + } + catch (IllegalStateException e) { + assertThat( e ).hasMessageContaining( "lock mode" ); + } + } ); + } + + @Test + @RequiresDialect( value = H2Dialect.class, comment = "This has more to do with Query internals than the DB; so avoid Dialect variances in generated SQL" ) + void testHibernateLockMode(SessionFactoryScope sessions) { + final SQLStatementInspector sqlCollector = sessions.getCollectingStatementInspector(); + sqlCollector.clear(); + + sessions.inTransaction( (session) -> { + final NativeQueryImplementor query = session.createNativeQuery( QUERY_STRING, SimpleEntity.class ); + query.setHibernateLockMode( LockMode.PESSIMISTIC_WRITE ); + query.list(); + + assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); + assertThat( sqlCollector.getSqlQueries().get( 0 ) ).endsWith( " for update" ); + } ); + } + + @Test + @RequiresDialect( value = H2Dialect.class, comment = "This has more to do with Query internals than the DB; so avoid Dialect variances in generated SQL" ) + void testLockModeHint(SessionFactoryScope sessions) { + final SQLStatementInspector sqlCollector = sessions.getCollectingStatementInspector(); + sqlCollector.clear(); + + sessions.inTransaction( (session) -> { + final Query query = session.createNativeQuery( QUERY_STRING, SimpleEntity.class ); + query.setHint( HibernateHints.HINT_NATIVE_LOCK_MODE, LockMode.PESSIMISTIC_WRITE ); + query.getResultList(); + + assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); + assertThat( sqlCollector.getSqlQueries().get( 0 ) ).endsWith( " for update" ); + } ); + } + + @Test + @RequiresDialect( value = H2Dialect.class, comment = "This has more to do with Query internals than the DB; so avoid Dialect variances in generated SQL" ) + void testLockModeHintLowercase(SessionFactoryScope sessions) { + final SQLStatementInspector sqlCollector = sessions.getCollectingStatementInspector(); + sqlCollector.clear(); + + sessions.inTransaction( (session) -> { + final Query query = session.createNativeQuery( QUERY_STRING, SimpleEntity.class ); + query.setHint( HibernateHints.HINT_NATIVE_LOCK_MODE, LockMode.PESSIMISTIC_WRITE.name().toLowerCase( Locale.ROOT ) ); + query.getResultList(); + + assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 ); + assertThat( sqlCollector.getSqlQueries().get( 0 ) ).endsWith( " for update" ); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/locking/LockExistingBytecodeProxyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/LockExistingBytecodeProxyTest.java index 690d9ec43aa6..692ab57b24ef 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/locking/LockExistingBytecodeProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/LockExistingBytecodeProxyTest.java @@ -4,8 +4,13 @@ */ package org.hibernate.orm.test.locking; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.Version; import org.hibernate.Hibernate; - import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.Jira; @@ -15,24 +20,15 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.Id; -import jakarta.persistence.LockModeType; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Version; +import static jakarta.persistence.LockModeType.PESSIMISTIC_FORCE_INCREMENT; +import static jakarta.persistence.LockModeType.PESSIMISTIC_WRITE; +import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -@DomainModel( - annotatedClasses = { - LockExistingBytecodeProxyTest.MainEntity.class, - LockExistingBytecodeProxyTest.ReferencedEntity.class, - } -) +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel( annotatedClasses = { + LockExistingBytecodeProxyTest.Book.class, + LockExistingBytecodeProxyTest.Page.class +}) @SessionFactory @BytecodeEnhanced @Jira( "https://hibernate.atlassian.net/browse/HHH-17828" ) @@ -41,84 +37,77 @@ public class LockExistingBytecodeProxyTest { @Test public void testFindAndLockAfterFind(SessionFactoryScope scope) { scope.inTransaction( session -> { - final MainEntity main = session.find( MainEntity.class, 1L ); - assertFalse( Hibernate.isInitialized( main.referenced ) ); - final ReferencedEntity lazyEntity = session.find( ReferencedEntity.class, 1L, LockModeType.PESSIMISTIC_WRITE ); - assertEquals( LockModeType.PESSIMISTIC_WRITE, session.getLockMode( lazyEntity ) ); - assertTrue( Hibernate.isInitialized( main.referenced ) ); - assertSame( lazyEntity, main.referenced ); + final Page page = session.find( Page.class, 1 ); + assertThat( Hibernate.isInitialized( page.book ) ).isFalse(); + + final Book book = session.find( Book.class, 1, PESSIMISTIC_WRITE ); + assertThat( book ).isSameAs( page.book ); + assertThat( session.getLockMode( book ) ).isEqualTo( PESSIMISTIC_WRITE ); + assertThat( Hibernate.isInitialized( book ) ).isTrue(); } ); } @Test public void testLockAfterFind(SessionFactoryScope scope) { scope.inTransaction( session -> { - final MainEntity main = session.find( MainEntity.class, 1L ); - assertFalse( Hibernate.isInitialized( main.referenced ) ); - session.lock( main.referenced, LockModeType.PESSIMISTIC_FORCE_INCREMENT ); - assertEquals( LockModeType.PESSIMISTIC_FORCE_INCREMENT, session.getLockMode( main.referenced ) ); - assertTrue( Hibernate.isInitialized( main.referenced ) ); + final Page page = session.find( Page.class, 1 ); + assertThat( Hibernate.isInitialized( page.book ) ).isFalse(); + + session.lock( page.book, PESSIMISTIC_FORCE_INCREMENT ); + assertThat( session.getLockMode( page.book ) ).isEqualTo( PESSIMISTIC_FORCE_INCREMENT ); + assertThat( Hibernate.isInitialized( page.book ) ).isTrue(); } ); } @BeforeEach - public void setUp(SessionFactoryScope scope) { + public void createTestData(SessionFactoryScope scope) { scope.inTransaction( session -> { - final ReferencedEntity e1 = new ReferencedEntity( 1L, "referenced" ); - session.persist( e1 ); - session.persist( new MainEntity( 1L, e1 ) ); + final Book book = new Book( 1, "My Story" ); + final Page page = new Page( 1, book ); + session.persist( book ); + session.persist( page ); } ); } @AfterEach - public void tearDown(SessionFactoryScope scope) { - scope.inTransaction( session -> { - session.createMutationQuery( "delete from MainEntity" ).executeUpdate(); - session.createMutationQuery( "delete from ReferencedEntity" ).executeUpdate(); - } ); + public void dropTestData(SessionFactoryScope scope) { + scope.dropData(); } - @Entity( name = "MainEntity" ) - public static class MainEntity { + @Entity(name="Book") + @Table(name="books") + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class Book { @Id - private Long id; - - @ManyToOne( fetch = FetchType.LAZY ) - private ReferencedEntity referenced; + private Integer id; + private String name; + @Version + private Long version; - protected MainEntity() { + public Book() { } - public MainEntity(long id, ReferencedEntity referenced) { + public Book(Integer id, String name) { this.id = id; - this.referenced = referenced; - } - - public ReferencedEntity getReferenced() { - return referenced; + this.name = name; } } - @Entity( name = "ReferencedEntity" ) - public static class ReferencedEntity { + @Entity(name="Page") + @Table(name="pages") + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class Page { @Id - private Long id; - - @Version - private Long version; - - private String name; + private Integer id; + @ManyToOne( fetch = FetchType.LAZY ) + private Book book; - protected ReferencedEntity() { + public Page() { } - public ReferencedEntity(long id, String name) { + public Page(Integer id, Book book) { this.id = id; - this.name = name; - } - - public long getVersion() { - return version; + this.book = book; } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/ByteMappingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/ByteMappingTests.java index 4036a1bee92e..02ce0c44968c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/ByteMappingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/ByteMappingTests.java @@ -13,6 +13,7 @@ import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping; import org.hibernate.metamodel.spi.MappingMetamodelImplementor; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.testing.orm.junit.DomainModel; @@ -30,8 +31,10 @@ * * @author Steve Ebersole */ +@SuppressWarnings("JUnitMalformedDeclaration") @DomainModel(annotatedClasses = ByteMappingTests.EntityOfBytes.class) @SessionFactory +@JiraKey(value = "HHH-14021") public class ByteMappingTests { @Test @@ -67,15 +70,13 @@ public void testMappings(SessionFactoryScope scope) { (session) -> session.persist(new EntityOfBytes(1, (byte) 3, (byte) 5)) ); scope.inTransaction( - (session) -> session.get(EntityOfBytes.class, 1) + (session) -> session.find(EntityOfBytes.class, 1) ); } @AfterEach public void dropData(SessionFactoryScope scope) { - scope.inTransaction( - (session) -> session.createMutationQuery("delete EntityOfBytes").executeUpdate() - ); + scope.dropData(); } @Entity(name = "EntityOfBytes") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/AttributeConverterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/AttributeConverterTest.java index 1a7ac11d69c5..bd6577dcd6c5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/AttributeConverterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/AttributeConverterTest.java @@ -399,48 +399,6 @@ public void testBasicTimestampUsage() { } } - @Test - @JiraKey(value = "HHH-14021") - public void testBasicByteUsage() { - Configuration cfg = new Configuration(); - ServiceRegistryUtil.applySettings( cfg.getStandardServiceRegistryBuilder() ); - cfg.addAttributeConverter( EnumToByteConverter.class, false ); - cfg.addAnnotatedClass( Tester4.class ); - cfg.setProperty( AvailableSettings.HBM2DDL_AUTO, "create-drop" ); - cfg.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" ); - - try (SessionFactory sf = cfg.buildSessionFactory()) { - Session session = sf.openSession(); - session.beginTransaction(); - session.persist( new Tester4( 1L, "George", 150, ConvertibleEnum.DEFAULT ) ); - session.getTransaction().commit(); - session.close(); - - sf.getStatistics().clear(); - session = sf.openSession(); - session.beginTransaction(); - session.get( Tester4.class, 1L ); - session.getTransaction().commit(); - session.close(); - assertEquals( 0, sf.getStatistics().getEntityUpdateCount() ); - - session = sf.openSession(); - session.beginTransaction(); - Tester4 t4 = (Tester4) session.get( Tester4.class, 1L ); - t4.convertibleEnum = ConvertibleEnum.VALUE; - session.getTransaction().commit(); - session.close(); - - session = sf.openSession(); - session.beginTransaction(); - t4 = session.get( Tester4.class, 1L ); - assertEquals( ConvertibleEnum.VALUE, t4.convertibleEnum ); - session.remove( t4 ); - session.getTransaction().commit(); - session.close(); - } - } - @Test @JiraKey(value = "HHH-8866") public void testEnumConverter() { @@ -562,8 +520,6 @@ public static class Tester4 { private String name; @Convert( converter = IntegerToVarcharConverter.class ) private Integer code; - @Convert( converter = EnumToByteConverter.class ) - private ConvertibleEnum convertibleEnum; public Tester4() { } @@ -573,13 +529,6 @@ public Tester4(Long id, String name, Integer code) { this.name = name; this.code = code; } - - public Tester4(Long id, String name, Integer code, ConvertibleEnum convertibleEnum) { - this.id = id; - this.name = name; - this.code = code; - this.convertibleEnum = convertibleEnum; - } } @Entity(name = "T5") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/elementCollection/CollectionElementConversionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/elementCollection/CollectionElementConversionTest.java index a170d7c2cb73..40d1576885db 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/elementCollection/CollectionElementConversionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter/elementCollection/CollectionElementConversionTest.java @@ -30,6 +30,7 @@ /** * @author Steve Ebersole */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-8529") @DomainModel( annotatedClasses = { CollectionElementConversionTest.Customer.class, CollectionElementConversionTest.ColorConverter.class } ) @SessionFactory diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/formula/SchemaSubstitutionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/formula/SchemaSubstitutionTests.java new file mode 100644 index 000000000000..404e164ac5d1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/formula/SchemaSubstitutionTests.java @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.mapping.formula; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.annotations.Formula; +import org.hibernate.cfg.MappingSettings; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.SelectableMapping; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.Jira; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@Jira( "https://hibernate.atlassian.net/browse/HHH-12227" ) +@RequiresDialect( value = H2Dialect.class, comment = "Not dialect specific" ) +@SuppressWarnings("JUnitMalformedDeclaration") +public class SchemaSubstitutionTests { + @Test + @ServiceRegistry( settings = @Setting( name = MappingSettings.DEFAULT_SCHEMA, value = "my_schema" ) ) + @DomainModel( annotatedClasses = Thing.class ) + void testWithSchema(DomainModelScope modelScope) { + try (SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) modelScope.getDomainModel().buildSessionFactory()) { + final EntityPersister persister = sessionFactory.getMappingMetamodel().getEntityDescriptor( Thing.class ); + final AttributeMapping attributeMapping = persister.findAttributeMapping( "externalName" ); + verifyFormula( attributeMapping, true ); + } + } + + @Test + @ServiceRegistry + @DomainModel( annotatedClasses = Thing.class ) + void testWithoutSchema(DomainModelScope modelScope) { + try (SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) modelScope.getDomainModel().buildSessionFactory()) { + final EntityPersister persister = sessionFactory.getMappingMetamodel().getEntityDescriptor( Thing.class ); + final AttributeMapping attributeMapping = persister.findAttributeMapping( "externalName" ); + verifyFormula( attributeMapping, false ); + } + } + + private void verifyFormula(AttributeMapping attributeMapping, boolean expectSchema) { + final SelectableMapping selectable = attributeMapping.getSelectable( 0 ); + assertThat( selectable.isFormula() ).isTrue(); + assertThat( selectable.getSelectionExpression() ).doesNotContain( "{h-schema}" ); + assertThat( selectable.getSelectionExpression().contains( "my_schema" ) ).isEqualTo( expectSchema ); + } + + @Entity(name="Thing") + @Table(name="things") + public static class Thing { + @Id + private Integer id; + private String name; + @Formula( "select name from {h-schema}externals" ) + private String externalName; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/hhh14276/NestedIdClassDerivedIdentifiersTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/hhh14276/NestedIdClassDerivedIdentifiersTest.java index 4ebb577ffec7..2bcb25949ba0 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/hhh14276/NestedIdClassDerivedIdentifiersTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/hhh14276/NestedIdClassDerivedIdentifiersTest.java @@ -4,49 +4,27 @@ */ package org.hibernate.orm.test.mapping.hhh14276; -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; - -import java.util.Map; - -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; -import org.hibernate.query.sqm.mutation.internal.inline.InlineMutationStrategy; - +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; import org.hibernate.orm.test.mapping.hhh14276.entity.PlayerStat; import org.hibernate.orm.test.mapping.hhh14276.entity.Score; import org.hibernate.testing.orm.junit.JiraKey; -import org.junit.Before; -import org.junit.Test; - -@JiraKey(value = "HHH-14276") -public class NestedIdClassDerivedIdentifiersTest extends BaseEntityManagerFunctionalTestCase { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - PlayerStat.class, - Score.class - }; - } - - @Override - protected void addConfigOptions(Map options) { - options.put( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, Boolean.TRUE ); - options.put( AvailableSettings.QUERY_MULTI_TABLE_MUTATION_STRATEGY, InlineMutationStrategy.class.getName() ); - } +import org.junit.jupiter.api.Test; - @Before - public void setUp() { - doInJPA( this::entityManagerFactory, em -> - { - // do nothing - } ); - } +import static org.hibernate.cfg.MappingSettings.GLOBALLY_QUOTED_IDENTIFIERS; +@JiraKey( value = "HHH-14276" ) +public class NestedIdClassDerivedIdentifiersTest { @Test - public void testNestedIdClassDerivedIdentifiers() { - doInJPA( this::entityManagerFactory, em -> - { - // do nothing - } ); + public void testMapping() { + final Configuration configuration = new Configuration() + .setProperty( GLOBALLY_QUOTED_IDENTIFIERS, Boolean.TRUE ) + .addAnnotatedClasses( PlayerStat.class, Score.class ); + + try (SessionFactory sessionFactory = configuration.buildSessionFactory()) { + sessionFactory.inTransaction( (session) -> { + // do nothing... + } ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/joined/JoinedSubclassDuplicateFieldsWithTreatTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/joined/JoinedSubclassDuplicateFieldsWithTreatTest.java index 1300306f62f8..ce81549b60fe 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/joined/JoinedSubclassDuplicateFieldsWithTreatTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/inheritance/joined/JoinedSubclassDuplicateFieldsWithTreatTest.java @@ -5,90 +5,67 @@ package org.hibernate.orm.test.mapping.inheritance.joined; import java.util.List; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Inheritance; -import jakarta.persistence.InheritanceType; + +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.domain.retail.CardPayment; +import org.hibernate.testing.orm.domain.retail.CashPayment; +import org.hibernate.testing.orm.domain.retail.DomesticVendor; +import org.hibernate.testing.orm.domain.retail.ForeignVendor; +import org.hibernate.testing.orm.domain.retail.Payment; +import org.hibernate.testing.orm.domain.retail.Vendor; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; -/** - * @author pholvs - */ -@DomainModel( - annotatedClasses = { - JoinedSubclassDuplicateFieldsWithTreatTest.Account.class, - JoinedSubclassDuplicateFieldsWithTreatTest.Deposit.class, - JoinedSubclassDuplicateFieldsWithTreatTest.Loan.class - } -) -@SessionFactory +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey( "HHH-11686" ) +@DomainModel(standardModels = StandardDomainModel.RETAIL) +@SessionFactory public class JoinedSubclassDuplicateFieldsWithTreatTest { - @Test - public void queryConstrainedSubclass(SessionFactoryScope scope) { + public void testRestrictedTreat(SessionFactoryScope scope) { + // SINGLE_TABLE scope.inTransaction( (session) -> { - Deposit deposit1 = new Deposit(); - deposit1.id = 1L; - deposit1.interest = 10; - - Loan loan1 = new Loan(); - loan1.id = 2L; - loan1.interest = 10; - - Deposit deposit2 = new Deposit(); - deposit2.id = 3L; - deposit2.interest = 20; - - Loan loan2 = new Loan(); - loan2.id = 4L; - loan2.interest = 30; - - session.persist(deposit1); - session.persist(loan1); - session.persist(deposit2); - session.persist(loan2); + final String qry = "from Vendor v where treat(v as DomesticVendor).name = 'Spacely'"; + final List vendors = session.createQuery( qry, Vendor.class ).getResultList(); + assertThat( vendors ).isEmpty(); } ); + // JOINED scope.inTransaction( (session) -> { - List accounts = session - .createQuery( - "select a from Account a where treat(a as Loan).interest = 10", - Account.class - ).getResultList(); - assertThat( accounts ).hasSize( 1 ); + final String qry = "from Payment p where treat(p as CardPayment).transactionId = 123"; + final List payments = session.createQuery( qry, Payment.class ).getResultList(); + assertThat( payments ).hasSize( 1 ); + assertThat( payments.get( 0 ) ).isInstanceOf( CardPayment.class ); } ); } - @Entity(name = "Account") - @Inheritance(strategy = InheritanceType.JOINED) - public static class Account - { - @Id - public Long id; - } - + @BeforeEach + void createTestData(SessionFactoryScope sessions) { + sessions.inTransaction( (session) -> { + // SINGLE_TABLE + final DomesticVendor acme = new DomesticVendor( 1, "Acme", "Acme, LLC" ); + final ForeignVendor spacely = new ForeignVendor( 2, "Spacely", "Spacely Space Sprockets, Inc" ); + session.persist( acme ); + session.persist( spacely ); - @Entity(name = "Deposit") - public static class Deposit extends Account { - @Column - public Integer interest; + // JOINED + final CardPayment cardPayment = new CardPayment( 1, 123, 123L, "USD" ); + final CashPayment cashPayment = new CashPayment( 2, 789L, "USD" ); + session.persist( cardPayment ); + session.persist( cashPayment ); + } ); } - @Entity(name = "Loan") - public static class Loan extends Account { - @Column - public Integer interest; - - @Column - public Integer rate; + @AfterEach + void dropTestData(SessionFactoryScope sessions) { + sessions.dropData(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/AbstractSchemaSubstitutionFormulaTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/AbstractSchemaSubstitutionFormulaTest.java deleted file mode 100644 index 86ec5436c3a0..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/AbstractSchemaSubstitutionFormulaTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.persister.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; - -import org.hibernate.annotations.Formula; -import org.hibernate.persister.entity.AbstractEntityPersister; - -import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.SessionFactory; -import org.hibernate.testing.orm.junit.SessionFactoryScope; - -import org.junit.jupiter.api.Test; - -import static org.junit.Assert.assertTrue; - -/** - * @author Mykhaylo Gnylorybov - */ -@DomainModel(annotatedClasses = { - AbstractSchemaSubstitutionFormulaTest.FooBar.class, - AbstractSchemaSubstitutionFormulaTest.Bar.class, - AbstractSchemaSubstitutionFormulaTest.Foo.class -}) -@SessionFactory -public abstract class AbstractSchemaSubstitutionFormulaTest { - - protected static final String SCHEMA_PLACEHOLDER = "h-schema"; - - @Test - public void test(SessionFactoryScope scope) { - final String className = FooBar.class.getName(); - final AbstractEntityPersister persister = (AbstractEntityPersister) scope.getSessionFactory() - .getMappingMetamodel() - .getEntityDescriptor( className ); - final String formula = persister.getSubclassPropertyFormulaTemplateClosure()[persister.getPropertyIndex( "isValid" )][0]; - validate( formula ); - - scope.inTransaction( session -> { - Foo foo = new Foo(); - foo.id = 1; - foo.name = "fooName"; - session.persist( foo ); - - Bar bar = new Bar(); - bar.id = 2; - bar.name = "barName"; - session.persist( bar ); - - FooBar fooBar = new FooBar(); - fooBar.id = 3; - fooBar.bar = bar; - fooBar.foo = foo; - - session.persist( fooBar ); - } ); - - scope.inTransaction( session -> { - FooBar entity = session.find( FooBar.class, 3 ); - assertTrue( "Invalid result of formula expression: ", entity.isValid ); - } ); - - - } - - abstract void validate(String formula); - - @Entity(name = "FOOBAR") - @Table(name = "FOOBAR") - public static class FooBar { - - @Id - @Column(name = "ID") - public Integer id; - - @ManyToOne - @JoinColumn(name = "FOO_ID") - public Foo foo; - - @ManyToOne - @JoinColumn(name = "BAR_ID") - public Bar bar; - - @Formula("CASE WHEN (\n" - + " EXISTS (\n" - + " SELECT *\n" - + " FROM {h-schema}Foo foo\n" - + " JOIN {h-schema}FooBar fooBar\n" - + " ON foo.ID = fooBar.FOO_ID" - + " WHERE foo.name IS NOT NULL\n" - + " )\n" - + " AND\n" - + " EXISTS (\n" - + " SELECT *\n" - + " FROM {h-schema}Bar bar\n" - + " JOIN {h-schema}FooBar fooBar\n" - + " ON bar.ID = fooBar.BAR_ID\n" - + " WHERE bar.name IS NOT NULL\n" - + " ))\n" - + " THEN 1\n" - + " ELSE 0\n" - + "END") - public Boolean isValid; - } - - @Entity(name = "FOO") - @Table(name = "FOO") - public static class Foo { - - @Id - @Column(name = "ID") - public Integer id; - - @Column(name = "name") - public String name; - } - - @Entity(name = "BAR") - @Table(name = "BAR") - public static class Bar { - - @Id - @Column(name = "ID") - public Integer id; - - @Column(name = "name") - public String name; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlNamespaceInjectionFunctionalTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlNamespaceInjectionFunctionalTests.java new file mode 100644 index 000000000000..b5cd8c24163b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlNamespaceInjectionFunctionalTests.java @@ -0,0 +1,106 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.persister.entity; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.SQLInsert; +import org.hibernate.annotations.SQLSelect; +import org.hibernate.annotations.SQLUpdate; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.testing.jdbc.SQLStatementInspector; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@ServiceRegistry(settings = @Setting( name= AvailableSettings.DEFAULT_SCHEMA, value = "my_schema" ) ) +@DomainModel(annotatedClasses = CustomSqlNamespaceInjectionFunctionalTests.CustomEntity.class) +@SessionFactory(useCollectingStatementInspector = true, createSecondarySchemas = true) +@RequiresDialect(H2Dialect.class) +public class CustomSqlNamespaceInjectionFunctionalTests { + @Test + void testUsage(SessionFactoryScope sessions) { + final SQLStatementInspector statementInspector = sessions.getCollectingStatementInspector(); + + // create one, verifying the executed INSERT + statementInspector.clear(); + final Integer generatedId = sessions.fromTransaction( (session) -> { + final CustomEntity entity = new CustomEntity( "Evets" ); + session.persist( entity ); + session.flush(); + return entity.id; + } ); + assertThat( statementInspector.getSqlQueries() ).hasSize( 1 ); + assertThat( statementInspector.getSqlQueries().get( 0 ) ) + .isEqualTo( "insert into my_schema.the_table (name) values (?)" ); + + // modify one, verifying the executed UPDATE. + // NOTE : because of the find we also get the @SQLSelect performed + statementInspector.clear(); + sessions.inTransaction( (session) -> { + final CustomEntity loaded = session.find( CustomEntity.class, generatedId ); + loaded.name = "Steve"; + } ); + assertThat( statementInspector.getSqlQueries() ).hasSize( 2 ); + assertThat( statementInspector.getSqlQueries().get( 0 ) ) + .isEqualTo( "select id, name from my_schema.the_table where id = ?" ); + assertThat( statementInspector.getSqlQueries().get( 1 ) ) + .isEqualTo( "update my_schema.the_table set name = ? where id = ?" ); + + // delete one, verifying the executed DELETE + // NOTE : because of the find we also get the @SQLSelect performed + statementInspector.clear(); + sessions.inTransaction( (session) -> { + final CustomEntity loaded = session.find( CustomEntity.class, generatedId ); + session.remove( loaded ); + } ); + assertThat( statementInspector.getSqlQueries() ).hasSize( 2 ); + assertThat( statementInspector.getSqlQueries().get( 0 ) ) + .isEqualTo( "select id, name from my_schema.the_table where id = ?" ); + assertThat( statementInspector.getSqlQueries().get( 1 ) ) + .isEqualTo( "delete from my_schema.the_table where id = ?" ); + } + + @AfterEach + void tearDown(SessionFactoryScope sessions) { + sessions.getSessionFactory().getSchemaManager().truncateMappedObjects(); + } + + @Entity(name = "CustomEntity") + @SQLSelect(sql = "select id, name from {h-schema}the_table where id = ?") + @SQLInsert(sql = "insert into {h-schema}the_table (name) values (?)") + @SQLDelete(sql = "delete from {h-schema}the_table where id = ?") + @SQLUpdate(sql = "update {h-schema}the_table set name = ? where id = ? ") + @Table(name="the_table") + public static class CustomEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + public Integer id; + private String name; + + public CustomEntity() { + } + + public CustomEntity(String name) { + this.name = name; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlNamespaceInjectionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlNamespaceInjectionTests.java new file mode 100644 index 000000000000..75fb490a94e1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlNamespaceInjectionTests.java @@ -0,0 +1,155 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.persister.entity; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import org.hibernate.LockMode; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.SQLInsert; +import org.hibernate.annotations.SQLSelect; +import org.hibernate.annotations.SQLUpdate; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.spi.MappingMetamodelImplementor; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.persister.entity.mutation.MutationCoordinator; +import org.hibernate.sql.model.MutationOperation; +import org.hibernate.sql.model.MutationOperationGroup; +import org.hibernate.sql.model.jdbc.JdbcMutationOperation; +import org.hibernate.testing.jdbc.SQLStatementInspector; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.cfg.JdbcSettings.DIALECT; +import static org.hibernate.cfg.MappingSettings.DEFAULT_CATALOG; +import static org.hibernate.cfg.MappingSettings.DEFAULT_SCHEMA; +import static org.hibernate.engine.jdbc.env.spi.NameQualifierSupport.BOTH; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@RequiresDialect( + value = H2Dialect.class, + comment = "Actual database being tested is irrelevant, so only run for the default" +) +@ServiceRegistry( settings = { + @Setting( name = DEFAULT_SCHEMA, value="my_schema" ), + @Setting( name = DEFAULT_CATALOG, value="my_catalog" ), + @Setting( name = DIALECT, value = "org.hibernate.orm.test.persister.entity.CustomSqlNamespaceInjectionTests$CustomDialect" ) +} ) +public class CustomSqlNamespaceInjectionTests { + @Test + @DomainModel(annotatedClasses = CustomSchemaEntity.class) + @SessionFactory(exportSchema = false, useCollectingStatementInspector = true) + void testSchemaReplacement(SessionFactoryScope sessionFactoryScope) { + verifyReplacements( sessionFactoryScope, CustomSchemaEntity.class, "my_schema.the_table" ); + } + + @Test + @DomainModel(annotatedClasses = CustomCatalogEntity.class) + @SessionFactory(exportSchema = false, useCollectingStatementInspector = true) + void testCatalogReplacement(SessionFactoryScope sessionFactoryScope) { + verifyReplacements( sessionFactoryScope, CustomCatalogEntity.class, "my_catalog.the_table" ); + } + + @Test + @DomainModel(annotatedClasses = CustomDomainEntity.class) + @SessionFactory(exportSchema = false, useCollectingStatementInspector = true) + void testDomainReplacement(SessionFactoryScope sessionFactoryScope) { + verifyReplacements( sessionFactoryScope, CustomDomainEntity.class, "my_catalog.my_schema.the_table" ); + } + + private void verifyReplacements( + SessionFactoryScope sessionFactoryScope, + Class entityClass, + String expectedTableName) { + final SessionFactoryImplementor sessionFactory = sessionFactoryScope.getSessionFactory(); + + final MappingMetamodelImplementor mappingMetamodel = sessionFactory.getMappingMetamodel(); + final EntityPersister persister = mappingMetamodel.getEntityDescriptor( entityClass ); + + verifySelectSql( sessionFactoryScope, persister, expectedTableName ); + verifyDmlSql( sessionFactoryScope, persister, expectedTableName ); + } + + private static void verifyDmlSql(SessionFactoryScope sessionFactoryScope, EntityPersister persister, String expectedTableName) { + verifyDmlSql( persister.getInsertCoordinator(), expectedTableName ); + verifyDmlSql( persister.getUpdateCoordinator(), expectedTableName ); + verifyDmlSql( persister.getDeleteCoordinator(), expectedTableName ); + } + + private static void verifyDmlSql(MutationCoordinator mutationCoordinator, String expectedTableName) { + final MutationOperationGroup mutationOperationGroup = mutationCoordinator.getStaticMutationOperationGroup(); + final MutationOperation mutationOperation = mutationOperationGroup.getSingleOperation(); + final String sql = ( (JdbcMutationOperation) mutationOperation ).getSqlString(); + assertThat( sql ).contains( expectedTableName ); + } + + private static void verifySelectSql(SessionFactoryScope sessionFactoryScope, EntityPersister persister, String expectedTableName) { + final SQLStatementInspector sqlStatementCollector = sessionFactoryScope.getCollectingStatementInspector(); + sqlStatementCollector.clear(); + + try { + sessionFactoryScope.inTransaction( (session) -> { + persister.load( 1, null, LockMode.NONE, session ); + } ); + } + catch (Exception ignore) { + } + + assertThat( sqlStatementCollector.getSqlQueries() ).hasSize( 1 ); + final String query = sqlStatementCollector.getSqlQueries().get( 0 ); + assertThat( query ).contains( expectedTableName ); + } + + @Entity(name = "CustomSchemaEntity") + @SQLSelect(sql = "select id, name from {h-schema}the_table where id = ?") + @SQLInsert(sql = "insert into {h-schema}the_table (name) values (?)") + @SQLDelete(sql = "delete from {h-schema}the_table where id = ?") + @SQLUpdate(sql = "update {h-schema}the_table set name = ? where id = ? ") + public static class CustomSchemaEntity { + @Id + public Integer id; + private String name; + } + + @Entity(name = "CustomCatalogEntity") + @SQLSelect(sql = "select id, name from {h-catalog}the_table where id = ?") + @SQLInsert(sql = "insert into {h-catalog}the_table (name) values (?)") + @SQLDelete(sql = "delete from {h-catalog}the_table where id = ?") + @SQLUpdate(sql = "update {h-catalog}the_table set name = ? where id = ? ") + public static class CustomCatalogEntity { + @Id + public Integer id; + private String name; + } + + @Entity(name = "CustomDomainEntity") + @SQLSelect(sql = "select id, name from {h-domain}the_table where id = ?") + @SQLInsert(sql = "insert into {h-domain}the_table (name) values (?)") + @SQLDelete(sql = "delete from {h-domain}the_table where id = ?") + @SQLUpdate(sql = "update {h-domain}the_table set name = ? where id = ? ") + public static class CustomDomainEntity { + @Id + public Integer id; + private String name; + } + + public static class CustomDialect extends H2Dialect { + @Override + public NameQualifierSupport getNameQualifierSupport() { + return BOTH; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingIdentityTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingIdentityTest.java deleted file mode 100644 index a977bc74b186..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingIdentityTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.persister.entity; - -import org.hibernate.annotations.ResultCheckStyle; -import org.hibernate.annotations.SQLDelete; -import org.hibernate.annotations.SQLInsert; -import org.hibernate.annotations.SQLSelect; -import org.hibernate.annotations.SQLUpdate; -import org.hibernate.dialect.H2Dialect; -import org.hibernate.persister.entity.AbstractEntityPersister; -import org.hibernate.sql.model.jdbc.JdbcMutationOperation; - -import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.RequiresDialect; -import org.hibernate.testing.orm.junit.SessionFactory; -import org.hibernate.testing.orm.junit.SessionFactoryScope; -import org.junit.jupiter.api.Test; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -/** - * @author Laabidi RAISSI - */ -@DomainModel(annotatedClasses = { - CustomSqlSchemaResolvingIdentityTest.CustomEntity.class, CustomSqlSchemaResolvingIdentityTest.Dummy.class -}) -@SessionFactory -@RequiresDialect(H2Dialect.class) -public class CustomSqlSchemaResolvingIdentityTest { - - @Test - public void testSchemaNotReplacedInCustomSQL(SessionFactoryScope scope) throws Exception { - - String className = CustomEntity.class.getName(); - - final AbstractEntityPersister persister = (AbstractEntityPersister) scope.getSessionFactory().getMappingMetamodel().getEntityDescriptor(className); - String insertQuery = ( (JdbcMutationOperation) persister.getInsertCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); - String updateQuery = ( (JdbcMutationOperation) persister.getUpdateCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); - String deleteQuery = ( (JdbcMutationOperation) persister.getDeleteCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); - - assertEquals( "Incorrect custom SQL for insert in Entity: " + className, - "INSERT INTO FOO (name) VALUES (?)", insertQuery ); - - assertEquals( "Incorrect custom SQL for delete in Entity: " + className, - "DELETE FROM FOO WHERE id = ?", deleteQuery ); - - assertEquals( "Incorrect custom SQL for update in Entity: " + className, - "UPDATE FOO SET name = ? WHERE id = ?", updateQuery ); - - CustomEntity _entitty = scope.fromTransaction( session -> { - CustomEntity entity = new CustomEntity(); - session.persist( entity ); - - return entity; - } ); - - scope.inTransaction( session -> { - CustomEntity entity = session.find( CustomEntity.class, 1 ); - assertNotNull(entity); - - entity.name = "Vlad"; - } ); - - scope.inTransaction( session -> { - CustomEntity entity = session.find( CustomEntity.class, _entitty.id ); - session.remove( entity ); - } ); - - scope.inTransaction( session -> { - CustomEntity entity = session.find( CustomEntity.class, _entitty.id ); - assertNull(entity); - } ); - } - - @Entity(name = "CardWithCustomSQL") - @SQLSelect(sql = "SELECT id, name FROM {h-schema}FOO WHERE id = ?") - @SQLInsert(sql = "INSERT INTO {h-schema}FOO (name) VALUES (?)") - @SQLDelete(sql = "DELETE FROM {h-schema}FOO WHERE id = ?", check = ResultCheckStyle.COUNT) - @SQLUpdate(sql = "UPDATE {h-schema}FOO SET name = ? WHERE id = ? ") - public static class CustomEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - public Integer id; - - private String name; - } - - @Entity(name = "Dummy") - @Table(name = "FOO") - public static class Dummy { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - public Integer id; - - private String name; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingTest.java deleted file mode 100644 index b4f9661d5be3..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/CustomSqlSchemaResolvingTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.persister.entity; - -import org.hibernate.annotations.ResultCheckStyle; -import org.hibernate.annotations.SQLDelete; -import org.hibernate.annotations.SQLInsert; -import org.hibernate.annotations.SQLSelect; -import org.hibernate.annotations.SQLUpdate; -import org.hibernate.persister.entity.AbstractEntityPersister; -import org.hibernate.sql.model.jdbc.JdbcMutationOperation; - -import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.SessionFactory; -import org.hibernate.testing.orm.junit.SessionFactoryScope; -import org.junit.jupiter.api.Test; - -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -/** - * @author Laabidi RAISSI - */ -@DomainModel(annotatedClasses = { - CustomSqlSchemaResolvingTest.CustomEntity.class, CustomSqlSchemaResolvingTest.Dummy.class -}) -@SessionFactory -public class CustomSqlSchemaResolvingTest { - - @Test - public void testSchemaNotReplacedInCustomSQL(SessionFactoryScope scope) throws Exception { - - String className = CustomEntity.class.getName(); - - final AbstractEntityPersister persister = (AbstractEntityPersister) scope.getSessionFactory().getMappingMetamodel().getEntityDescriptor(className); - String insertQuery = ( (JdbcMutationOperation) persister.getInsertCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); - String updateQuery = ( (JdbcMutationOperation) persister.getUpdateCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); - String deleteQuery = ( (JdbcMutationOperation) persister.getDeleteCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString(); - - assertEquals( "Incorrect custom SQL for insert in Entity: " + className, - "INSERT INTO FOO (name, id) VALUES (?, ?)", insertQuery ); - - assertEquals( "Incorrect custom SQL for delete in Entity: " + className, - "DELETE FROM FOO WHERE id = ?", deleteQuery ); - - assertEquals( "Incorrect custom SQL for update in Entity: " + className, - "UPDATE FOO SET name = ? WHERE id = ?", updateQuery ); - - scope.inTransaction( session -> { - CustomEntity entity = new CustomEntity(); - entity.id = 1; - session.persist( entity ); - } ); - - scope.inTransaction( session -> { - CustomEntity entity = session.find( CustomEntity.class, 1 ); - assertNotNull(entity); - - entity.name = "Vlad"; - } ); - - scope.inTransaction( session -> { - CustomEntity entity = session.find( CustomEntity.class, 1 ); - session.remove( entity ); - } ); - - scope.inTransaction( session -> { - CustomEntity entity = session.find( CustomEntity.class, 1 ); - assertNull(entity); - } ); - } - - @Entity(name = "CardWithCustomSQL") - @SQLSelect(sql = "SELECT id, name FROM {h-schema}FOO WHERE id = ?") - @SQLInsert(sql = "INSERT INTO {h-schema}FOO (name, id) VALUES (?, ?)") - @SQLDelete(sql = "DELETE FROM {h-schema}FOO WHERE id = ?", check = ResultCheckStyle.COUNT) - @SQLUpdate(sql = "UPDATE {h-schema}FOO SET name = ? WHERE id = ? ") - public static class CustomEntity { - @Id - public Integer id; - - private String name; - } - - @Entity(name = "Dummy") - @Table(name = "FOO") - public static class Dummy { - @Id - public Integer id; - - private String name; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/FormulaTemplateEmptySchemaSubstitutionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/FormulaTemplateEmptySchemaSubstitutionTest.java deleted file mode 100644 index 41b84fa6e5b6..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/FormulaTemplateEmptySchemaSubstitutionTest.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.persister.entity; - -import org.hibernate.dialect.H2Dialect; - - -import org.hibernate.testing.orm.junit.RequiresDialect; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * @author Mykhaylo Gnylorybov - */ -@RequiresDialect(H2Dialect.class) -public class FormulaTemplateEmptySchemaSubstitutionTest extends AbstractSchemaSubstitutionFormulaTest { - - @Override - void validate(String formula) { - assertTrue( "Formula should not contain {} characters", formula.matches( "^[^{}]+$" ) ); - assertFalse( "Formula should not contain hibernate placeholder", formula.contains( SCHEMA_PLACEHOLDER ) ); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/FormulaTemplateSchemaSubstitutionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/FormulaTemplateSchemaSubstitutionTest.java deleted file mode 100644 index 25fe12b07a69..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/persister/entity/FormulaTemplateSchemaSubstitutionTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.persister.entity; - -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.dialect.H2Dialect; - - -import org.hibernate.testing.orm.junit.RequiresDialect; -import org.hibernate.testing.orm.junit.ServiceRegistry; -import org.hibernate.testing.orm.junit.Setting; - -import static org.junit.Assert.assertEquals; - -@RequiresDialect(H2Dialect.class) -@ServiceRegistry(settings = { - @Setting( name = AvailableSettings.DEFAULT_SCHEMA, value = FormulaTemplateSchemaSubstitutionTest.CUSTOM_SCHEMA), - @Setting( name = AvailableSettings.HBM2DDL_CREATE_SCHEMAS, value = "true") -}) -public class FormulaTemplateSchemaSubstitutionTest extends AbstractSchemaSubstitutionFormulaTest { - - static final String CUSTOM_SCHEMA = "CUSTOM_SCHEMA"; - - @Override - void validate(String formula) { - assertEquals( "Formula should not contain {} characters", - 4, formula.split( CUSTOM_SCHEMA + ".", -1 ).length - 1 - ); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/internal/hhh13151/TreatedEntityFetchTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/internal/hhh13151/TreatedEntityFetchTest.java index 7bec0d5633f2..f57f804e75f7 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/internal/hhh13151/TreatedEntityFetchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/internal/hhh13151/TreatedEntityFetchTest.java @@ -4,70 +4,48 @@ */ package org.hibernate.orm.test.query.criteria.internal.hhh13151; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.cfg.Configuration; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Before; -import org.junit.Test; - import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Root; - -import java.util.List; - -import static junit.framework.TestCase.assertTrue; - -public class TreatedEntityFetchTest extends BaseCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[]{ - SubEntity.class, - SuperEntity.class, - SideEntity.class - }; - } - - @Override - protected void configure(Configuration configuration) { - super.configure( configuration ); - - configuration.setProperty( AvailableSettings.SHOW_SQL, true ); - configuration.setProperty( AvailableSettings.FORMAT_SQL, true ); - // configuration.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" ); +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +@DomainModel( annotatedClasses = {SubEntity.class, SuperEntity.class, SideEntity.class} ) +@SessionFactory +@JiraKey( "HHH-13151" ) +@SuppressWarnings("JUnitMalformedDeclaration") +public class TreatedEntityFetchTest { + @Test + public void testTreatedFetching(SessionFactoryScope sessions) throws Exception { + final SubEntity result = (SubEntity) sessions.fromTransaction( (session) -> { + final CriteriaBuilder cb = session.getCriteriaBuilder(); + final CriteriaQuery criteria = cb.createQuery( SuperEntity.class ); + final Root root = criteria.from( SuperEntity.class ); + cb.treat( root, SubEntity.class ).fetch( "subField" ); + + return session.createQuery( criteria ).getResultList().get( 0 ); + } ); + + final SideEntity subField = result.getSubField(); + assertThat( subField.getName() ).isNotNull(); } - @Before - public void prepareEntities() { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - s.persist( new SubEntity().setSubField( new SideEntity( "testName" ) ) ); - tx.commit(); - s.close(); + @BeforeEach + public void createTestData(SessionFactoryScope sessions) { + sessions.inTransaction( (session) -> { + session.persist( new SubEntity().setSubField( new SideEntity( "testName" ) ) ); + } ); } - @Test - public void hhh13151Test() throws Exception { - Session s = openSession(); - - // Prepare Query - CriteriaBuilder cb = s.getCriteriaBuilder(); - CriteriaQuery criteria = cb.createQuery( SuperEntity.class ); - Root root = criteria.from( SuperEntity.class ); - cb.treat( root, SubEntity.class ).fetch( "subField" ); - - // Execute - Transaction tx = s.beginTransaction(); - List result = s.createQuery( criteria ).getResultList(); - tx.commit(); - s.close(); - - // Check results - SideEntity subField = ( (SubEntity) result.get( 0 ) ).getSubField(); - String name = subField.getName(); - assertTrue( name != null ); + @AfterEach + public void dropTestData(SessionFactoryScope sessions) { + sessions.dropData(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/TransactionTimeoutTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/TransactionTimeoutTests.java new file mode 100644 index 000000000000..e5b50f656fcd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/TransactionTimeoutTests.java @@ -0,0 +1,65 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.resource.transaction; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.PersistenceException; +import jakarta.persistence.Table; +import org.hibernate.Transaction; +import org.hibernate.TransactionException; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * Test behavior of transaction timeouts + * + * @author Steve Ebersole + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = TransactionTimeoutTests.Person.class) +@SessionFactory +public class TransactionTimeoutTests { + @Test + void testJdbcTxn(SessionFactoryScope sessions) { + sessions.inSession( (session) -> { + final Transaction transaction = session.getTransaction(); + // timeout in 2 seconds + transaction.setTimeout( 2 ); + + // start the transaction and sleep for 3 seconds to exceed the transaction timeout + transaction.begin(); + try { + Thread.sleep( 3 * 1000 ); + } + catch (InterruptedException e) { + throw new RuntimeException( "Thread#sleep error", e ); + } + try { + // perform an operation against the db and try to commit the transaction + session.createSelectionQuery( "from Person", Person.class ).list(); + transaction.commit(); + fail( "Transaction should have timed out" ); + } + catch (PersistenceException e) { + assertThat( e ).isInstanceOf( TransactionException.class ); + assertThat( e ).hasMessageContaining( "transaction timeout expired" ); + } + } ); + } + + @Entity(name="Person") + @Table(name="persons") + public static class Person { + @Id + private Integer id; + private String name; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/jta/JpaComplianceAlreadyStartedTransactionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/jta/JpaComplianceAlreadyStartedTransactionTest.java index 8e7bc38d9dc5..ed6ec5304db1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/jta/JpaComplianceAlreadyStartedTransactionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/jta/JpaComplianceAlreadyStartedTransactionTest.java @@ -4,62 +4,70 @@ */ package org.hibernate.orm.test.resource.transaction.jta; -import java.util.Map; -import jakarta.transaction.Status; import jakarta.transaction.TransactionManager; - -import org.hibernate.Session; import org.hibernate.Transaction; -import org.hibernate.cfg.AvailableSettings; - -import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.jta.TestingJtaBootstrap; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.Before; -import org.junit.Test; +import org.hibernate.testing.jta.TestingJtaPlatformImpl; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.hibernate.testing.orm.junit.SettingConfiguration; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hibernate.cfg.JpaComplianceSettings.JPA_TRANSACTION_COMPLIANCE; +import static org.junit.jupiter.api.Assertions.fail; /** + * Same as {@linkplain NonJpaComplianceAlreadyStartedTransactionTest}, but here with JPA compliance enabled + * * @author Andrea Boriero */ @JiraKey(value = "HHH-13076") -public class JpaComplianceAlreadyStartedTransactionTest extends BaseNonConfigCoreFunctionalTestCase { +@ServiceRegistry( + settingConfigurations = @SettingConfiguration( configurer = TestingJtaBootstrap.class ), + settings = { + @Setting( name = JPA_TRANSACTION_COMPLIANCE, value = "true" ) + } +) +@DomainModel +@SessionFactory +@SuppressWarnings("JUnitMalformedDeclaration") +public class JpaComplianceAlreadyStartedTransactionTest { private TransactionManager tm; - @Override - protected void addSettings(Map settings) { - super.addSettings( settings ); - TestingJtaBootstrap.prepare( settings ); - settings.put( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" ); - settings.put( AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" ); - } - - @Before + @BeforeEach public void setUp() { tm = JtaPlatformStandardTestingImpl.INSTANCE.transactionManager(); } - @Test(expected = IllegalStateException.class) - public void anIllegalStateExceptionShouldBeThrownWhenBeginTxIsCalledWithAnAlreadyActiveTX() throws Exception { - try (Session s = openSession()) { - tm.begin(); - Transaction tx = null; - try { - // A call to begin() with an active Tx should cause an IllegalStateException - tx = s.getTransaction(); - tx.begin(); - } - catch (Exception e) { - if ( tx != null && tx.isActive() ) { - tx.rollback(); + @Test + public void testBeginWithinActiveTransaction(SessionFactoryScope sessions) throws Exception { + TestingJtaPlatformImpl.inNoopJtaTransaction( tm, () -> { + sessions.inSession( (session) -> { + Transaction tx = null; + try { + // A call to begin() with an active Tx should cause an IllegalStateException + tx = session.getTransaction(); + tx.begin(); + fail( "Expecting an IllegalStateException" ); } - throw e; - } - } - catch (Exception e) { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.rollback(); - } - throw e; - } + catch (IllegalStateException expected) { + } + finally { + if ( tx != null ) { + try { + tx.rollback(); + } + catch (Exception ignore) { + } + } + } + } ); + } ); } + } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/jta/NonJpaComplianceAlreadyStartedTransactionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/jta/NonJpaComplianceAlreadyStartedTransactionTest.java index 5b27adf226d6..0e0fbe8743c8 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/jta/NonJpaComplianceAlreadyStartedTransactionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/resource/transaction/jta/NonJpaComplianceAlreadyStartedTransactionTest.java @@ -4,90 +4,65 @@ */ package org.hibernate.orm.test.resource.transaction.jta; -import java.util.Map; -import org.hibernate.Session; +import jakarta.transaction.TransactionManager; import org.hibernate.Transaction; -import org.hibernate.cfg.AvailableSettings; - import org.hibernate.testing.jta.TestingJtaBootstrap; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.hibernate.testing.jta.TestingJtaPlatformImpl; +import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; -import org.junit.Before; -import org.junit.Test; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.SettingConfiguration; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.transaction.Status; -import jakarta.transaction.TransactionManager; +import static org.junit.jupiter.api.Assertions.fail; /** + * Same as {@linkplain JpaComplianceAlreadyStartedTransactionTest}, but here with JPA compliance disabled + * * @author Andrea Boriero */ @JiraKey("HHH-13076") -public class NonJpaComplianceAlreadyStartedTransactionTest extends BaseNonConfigCoreFunctionalTestCase { +@ServiceRegistry( + settingConfigurations = @SettingConfiguration( configurer = TestingJtaBootstrap.class ) +) +@DomainModel +@SessionFactory +@SuppressWarnings("JUnitMalformedDeclaration") +public class NonJpaComplianceAlreadyStartedTransactionTest { private TransactionManager tm; - @Override - protected void addSettings(Map settings) { - super.addSettings( settings ); - TestingJtaBootstrap.prepare( settings ); - settings.put( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" ); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { TestEntity.class }; - } - - @Before + @BeforeEach public void setUp() { tm = JtaPlatformStandardTestingImpl.INSTANCE.transactionManager(); } @Test - public void noIllegalStateExceptionShouldBeThrownWhenBeginTxIsCalledWithAnAlreadyActiveTx() throws Exception { - tm.begin(); - try (Session s = openSession()) { - Transaction tx = s.getTransaction(); - tx.begin(); - try { - s.persist( new TestEntity( "ABC" ) ); - tx.commit(); - } - catch (Exception e) { - if ( tx.isActive() ) { - tx.rollback(); + public void testBeginWithinActiveTransaction(SessionFactoryScope sessions) throws Exception { + TestingJtaPlatformImpl.inNoopJtaTransaction( tm, () -> { + sessions.inSession( (session) -> { + Transaction tx = null; + try { + // A call to begin() with an active Tx should cause an IllegalStateException + tx = session.getTransaction(); + tx.begin(); } - throw e; - } - } - try { - tm.commit(); - } - catch (Exception e) { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.rollback(); - } - throw e; - } - } - - - @Entity(name = "TestEntity") - public static class TestEntity { - @Id - @GeneratedValue - private Long id; - - private String stringAttribute; - - public TestEntity() { - } - - public TestEntity(String stringAttribute) { - this.stringAttribute = stringAttribute; - } + catch (IllegalStateException unexpected) { + fail( "Unexpected failure", unexpected ); + } + finally { + if ( tx != null ) { + try { + tx.rollback(); + } + catch (Exception ignore) { + } + } + } + } ); + } ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/SchemaExportTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/SchemaExportTest.java index 377e9cd9992c..deb3d1cc1abc 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/SchemaExportTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/SchemaExportTest.java @@ -30,7 +30,6 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; /** * @author Gail Badner @@ -104,25 +103,6 @@ public void testBothType() { assertEquals( 0, schemaExport.getExceptions().size() ); } - @Test - public void testGenerateDdlToFile() { - final SchemaExport schemaExport = new SchemaExport(); - - File outFile = new File("schema.ddl"); - schemaExport.setOutputFile( outFile.getPath() ); - - // do not script to console or export to database - schemaExport.execute( EnumSet.of( TargetType.SCRIPT ), SchemaExport.Action.DROP, metadata ); - if ( doesDialectSupportDropTableIfExist() && schemaExport.getExceptions().size() > 0 ) { - assertEquals( 2, schemaExport.getExceptions().size() ); - } - assertTrue( outFile.exists() ); - - //check file is not empty - assertTrue( outFile.length() > 0 ); - outFile.delete(); - } - @Test public void testCreateAndDrop() { final SchemaExport schemaExport = new SchemaExport(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/insert/Message.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/insert/Message.java deleted file mode 100644 index 786a1e7af538..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/insert/Message.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.stateless.insert; - -/** - * @author mukhanov@gmail.com - */ -public class Message { - - private String id; - private String subject; - private String content; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getSubject() { - return subject; - } - - public void setSubject(String subject) { - this.subject = subject; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/insert/MessageRecipient.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/insert/MessageRecipient.java deleted file mode 100644 index e6e839201a8d..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/insert/MessageRecipient.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.stateless.insert; - -/** - * @author mukhanov@gmail.com - */ -public class MessageRecipient { - - private String id; - private String email; - private Message message; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public Message getMessage() { - return message; - } - - public void setMessage(Message message) { - this.message = message; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/insert/StatelessSessionInsertTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/insert/StatelessSessionInsertTest.java index 81363e2740f4..2aa5207a655b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/insert/StatelessSessionInsertTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/insert/StatelessSessionInsertTest.java @@ -4,55 +4,83 @@ */ package org.hibernate.orm.test.stateless.insert; -import org.hibernate.cfg.MappingSettings; - +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import org.hibernate.StatelessSession; import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.ServiceRegistry; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; -import org.hibernate.testing.orm.junit.Setting; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; /** - * @author mukhanov@gmail.com + * Simple "smoke" test of {@linkplain StatelessSession#insert} with associations */ -@ServiceRegistry(settings = @Setting(name = MappingSettings.TRANSFORM_HBM_XML, value = "true")) -@DomainModel(xmlMappings = "org/hibernate/orm/test/stateless/insert/Mappings.hbm.xml") +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = { + StatelessSessionInsertTest.Department.class, + StatelessSessionInsertTest.Employee.class, +}) @SessionFactory public class StatelessSessionInsertTest { @Test public void testInsertWithForeignKey(SessionFactoryScope scope) { - Message msg = new Message(); - scope.inTransaction( - session -> { - final String messageId = "message_id"; - msg.setId( messageId ); - msg.setContent( "message_content" ); - msg.setSubject( "message_subject" ); - session.persist( msg ); - } - ); - - scope.inStatelessTransaction( - statelessSession -> { - MessageRecipient signature = new MessageRecipient(); - signature.setId( "recipient" ); - signature.setEmail( "recipient@hibernate.org" ); - signature.setMessage( msg ); - statelessSession.insert( signature ); - } - ); + final Department department = scope.fromTransaction( (session) -> { + final Department dept = new Department( 1, "Marketing" ); + session.persist( dept ); + return dept; + } ); + + scope.inStatelessTransaction( (statelessSession) -> { + final Employee employee = new Employee( 1, "John Jacobs", department ); + statelessSession.insert( employee ); + } ); } @AfterEach public void cleanup(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - session.createQuery( "delete MessageRecipient" ).executeUpdate(); - session.createQuery( "delete Message" ).executeUpdate(); - } - ); + scope.dropData(); + } + + @Entity + @Table(name = "departments") + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class Department { + @Id + private Integer id; + private String name; + + public Department() { + } + + public Department(Integer id, String name) { + this.id = id; + this.name = name; + } + } + + @Entity + @Table(name = "employees") + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + public static class Employee { + @Id + private Integer id; + private String name; + @ManyToOne + @JoinColumn(name = "msg_fk") + private Department department; + + public Employee() { + } + + public Employee(Integer id, String name, Department department) { + this.id = id; + this.name = name; + this.department = department; + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stream/basic/BasicStreamTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stream/basic/BasicStreamTest.java index 2c540556b463..d23191f27607 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/stream/basic/BasicStreamTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stream/basic/BasicStreamTest.java @@ -4,17 +4,6 @@ */ package org.hibernate.orm.test.stream.basic; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Stream; - -import org.hibernate.engine.spi.SessionImplementor; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.SessionFactory; -import org.hibernate.testing.orm.junit.SessionFactoryScope; -import org.junit.jupiter.api.Test; - import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; @@ -22,6 +11,17 @@ import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Root; +import org.hibernate.internal.util.MutableInteger; +import org.hibernate.query.spi.QueryImplementor; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.stream.Stream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; @@ -31,97 +31,128 @@ /** * @author Steve Ebersole */ -@DomainModel( - annotatedClasses = BasicStreamTest.MyEntity.class -) +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel( annotatedClasses = BasicStreamTest.MyEntity.class ) @SessionFactory public class BasicStreamTest { + @BeforeEach + void createTestData(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + MyEntity e = new MyEntity(); + e.id = 1; + e.name = "Test"; + session.persist( e ); + } ); + } + + @AfterEach + void dropTestData(SessionFactoryScope scope) { + scope.dropData(); + } + @Test - public void basicStreamTest(SessionFactoryScope scope) { - - scope.inTransaction( - session -> { - // mainly we want to make sure that closing the Stream releases the ScrollableResults too - assertThat( ( (SessionImplementor) session ).getJdbcCoordinator() - .getLogicalConnection() - .getResourceRegistry() - .hasRegisteredResources(), is( false ) ); - final Stream stream = session.createQuery( "from MyEntity", MyEntity.class ).stream(); - try { - stream.forEach( System.out::println ); - assertThat( session.getJdbcCoordinator() - .getLogicalConnection() - .getResourceRegistry() - .hasRegisteredResources(), is( true ) ); - } - finally { - stream.close(); - assertThat( session.getJdbcCoordinator() - .getLogicalConnection() - .getResourceRegistry() - .hasRegisteredResources(), is( false ) ); - } - - } - ); + public void testBasicStreamHandling(SessionFactoryScope scope) { + // make sure that closing the Stream releases the ScrollableResults too + scope.inTransaction( (session) -> { + // at start, we should have no registered resources + assertThat( session.getJdbcCoordinator() + .getLogicalConnection() + .getResourceRegistry() + .hasRegisteredResources(), is( false ) ); + + final Stream stream = session.createQuery( "from MyEntity", MyEntity.class ).stream(); + //noinspection TryFinallyCanBeTryWithResources + try { + stream.forEach( System.out::println ); + // we should have registered resources here as the underlying ScrollableResults is still open + assertThat( session.getJdbcCoordinator() + .getLogicalConnection() + .getResourceRegistry() + .hasRegisteredResources(), is( true ) ); + } + finally { + stream.close(); + // after an explicit close, we should have no registered resources + assertThat( session.getJdbcCoordinator() + .getLogicalConnection() + .getResourceRegistry() + .hasRegisteredResources(), is( false ) ); + } + + } ); } @Test - @JiraKey(value = "HHH-10824") - public void testQueryStream(SessionFactoryScope scope) { - - scope.inTransaction( - session -> { - MyEntity e = new MyEntity(); - e.id = 1; - e.name = "Test"; - session.persist( e ); - } - ); - - scope.inSession( - session -> { - // Test stream query without type. - try (Stream stream = session.createQuery( "From MyEntity" ).stream()) { - Object result = stream.findFirst().orElse( null ); - assertTyping( MyEntity.class, result ); - } - - // Test stream query with type. - try (final Stream stream = session.createQuery( "From MyEntity", MyEntity.class ) - .stream()) { - assertTyping( MyEntity.class, stream.findFirst().orElse( null ) ); - } - - // Test stream query using forEach - try (Stream stream = session.createQuery( "From MyEntity", MyEntity.class ) - .stream()) { - stream.forEach( i -> { - assertTyping( MyEntity.class, i ); - } ); - } - - try (Stream stream = session.createQuery( "SELECT me.id, me.name FROM MyEntity me" ) - .stream()) { - stream.forEach( i -> { - assertTyping( Integer.class, i[0] ); - assertTyping( String.class, i[1] ); - } ); - } - } - ); + public void testStreamAutoClosing(SessionFactoryScope scope) { + // same as #testBasicStreamHandling but using try-with-resources + + final MutableInteger onCloseCount = new MutableInteger(); + + scope.inTransaction( (session) -> { + // at start, we should have no registered resources + assertThat( session.getJdbcCoordinator() + .getLogicalConnection() + .getResourceRegistry() + .hasRegisteredResources(), is( false ) ); + assertThat( onCloseCount.get(), equalTo( 0 ) ); + + final QueryImplementor query = session.createQuery( "from MyEntity", MyEntity.class ); + try ( final Stream stream = query.stream().onClose( onCloseCount::increment ) ) { + stream.forEach( System.out::println ); + + // we should have registered resources here as the underlying ScrollableResults is still open + assertThat( session.getJdbcCoordinator() + .getLogicalConnection() + .getResourceRegistry() + .hasRegisteredResources(), is( true ) ); + assertThat( onCloseCount.get(), equalTo( 0 ) ); + } + + assertThat( session.getJdbcCoordinator() + .getLogicalConnection() + .getResourceRegistry() + .hasRegisteredResources(), is( false ) ); + assertThat( onCloseCount.get(), equalTo( 1 ) ); + } ); } @Test - @JiraKey(value = "HHH-11743") - public void testTupleStream(SessionFactoryScope scope) { - scope.inTransaction( session -> { - MyEntity entity = new MyEntity(); - entity.id = 2; - entity.name = "an entity"; - session.persist( entity ); + @JiraKey(value = "HHH-10824") + public void testQueryStreamTyping(SessionFactoryScope scope) { + // Test untyped query stream + scope.inTransaction( (session) -> { + try (Stream stream = session.createQuery( "from MyEntity" ).stream()) { + Object result = stream.findFirst().orElse( null ); + assertTyping( MyEntity.class, result ); + } + } ); + + // Test typed query stream + scope.inTransaction( (session) -> { + try (final Stream stream = session.createQuery( "from MyEntity", MyEntity.class ).stream()) { + assertTyping( MyEntity.class, stream.findFirst().orElse( null ) ); + } + } ); + + // Test stream query using forEach + scope.inTransaction( (session) -> { + try (Stream stream = session.createQuery( "from MyEntity", MyEntity.class ).stream()) { + stream.forEach( i -> { + assertTyping( MyEntity.class, i ); + } ); + } + } ); + + // Test stream query with Object[] result + scope.inTransaction( (session) -> { + try (Stream stream = session.createQuery( "SELECT me.id, me.name from MyEntity me" ).stream()) { + stream.forEach( i -> { + assertTyping( Integer.class, i[0] ); + assertTyping( String.class, i[1] ); + } ); + } } ); //test tuple stream using criteria @@ -144,45 +175,6 @@ public void testTupleStream(SessionFactoryScope scope) { } ); } - @Test - public void basicStreamTestWithExplicitOnClose(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - AtomicInteger onCloseCount = new AtomicInteger(); - - // mainly we want to make sure that closing the Stream releases the ScrollableResults too - assertThat( session.getJdbcCoordinator() - .getLogicalConnection() - .getResourceRegistry() - .hasRegisteredResources(), is( false ) ); - - assertThat( onCloseCount.get(), equalTo( 0 ) ); - - try (final Stream stream = session.createQuery( "from MyEntity", MyEntity.class ) - .stream() - .onClose( - onCloseCount::incrementAndGet )) { - - - assertThat( onCloseCount.get(), equalTo( 0 ) ); - - stream.forEach( System.out::println ); - assertThat( session.getJdbcCoordinator() - .getLogicalConnection() - .getResourceRegistry() - .hasRegisteredResources(), is( true ) ); - } - - assertThat( session.getJdbcCoordinator() - .getLogicalConnection() - .getResourceRegistry() - .hasRegisteredResources(), is( false ) ); - - assertThat( onCloseCount.get(), equalTo( 1 ) ); - } - ); - } - @Entity(name = "MyEntity") @Table(name = "MyEntity") public static class MyEntity { diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/jpa/criteria/paths/PolicyAndDistribution.hbm.xml b/hibernate-core/src/test/resources/org/hibernate/orm/test/jpa/criteria/paths/dynamic-model.hbm.xml similarity index 61% rename from hibernate-core/src/test/resources/org/hibernate/orm/test/jpa/criteria/paths/PolicyAndDistribution.hbm.xml rename to hibernate-core/src/test/resources/org/hibernate/orm/test/jpa/criteria/paths/dynamic-model.hbm.xml index 82c1c7a9c65c..0e9e6c55643a 100644 --- a/hibernate-core/src/test/resources/org/hibernate/orm/test/jpa/criteria/paths/PolicyAndDistribution.hbm.xml +++ b/hibernate-core/src/test/resources/org/hibernate/orm/test/jpa/criteria/paths/dynamic-model.hbm.xml @@ -10,16 +10,12 @@ "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> - - - - + + - - - - - + + + diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/stateless/insert/Mappings.hbm.xml b/hibernate-core/src/test/resources/org/hibernate/orm/test/stateless/insert/Mappings.hbm.xml deleted file mode 100644 index f1ebd00304c0..000000000000 --- a/hibernate-core/src/test/resources/org/hibernate/orm/test/stateless/insert/Mappings.hbm.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/jta/TestingJtaBootstrap.java b/hibernate-testing/src/main/java/org/hibernate/testing/jta/TestingJtaBootstrap.java index d633cbd0a585..06959951b8fb 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/jta/TestingJtaBootstrap.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/jta/TestingJtaBootstrap.java @@ -9,12 +9,15 @@ import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.testing.orm.junit.SettingConfiguration; import org.hibernate.testing.util.ServiceRegistryUtil; +import static org.hibernate.cfg.TransactionSettings.TRANSACTION_COORDINATOR_STRATEGY; + /** * @author Steve Ebersole */ -public final class TestingJtaBootstrap { +public final class TestingJtaBootstrap implements SettingConfiguration.Configurer { public static final TestingJtaBootstrap INSTANCE = new TestingJtaBootstrap(); public static void prepare(Map configValues) { @@ -28,7 +31,7 @@ public static void prepare(Map configValues) { } public static void prepare(StandardServiceRegistryBuilder registryBuilder) { - registryBuilder.applySetting( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" ); + registryBuilder.applySetting( TRANSACTION_COORDINATOR_STRATEGY, "jta" ); registryBuilder.applySetting( AvailableSettings.JTA_PLATFORM, TestingJtaPlatformImpl.INSTANCE ); registryBuilder.applySetting( AvailableSettings.CONNECTION_PROVIDER, JtaAwareConnectionProviderImpl.class.getName() ); registryBuilder.applySetting( @@ -44,6 +47,12 @@ public static StandardServiceRegistryBuilder prepare() { return registryBuilder; } - private TestingJtaBootstrap() { + public TestingJtaBootstrap() { + } + + @Override + public void applySettings(StandardServiceRegistryBuilder registryBuilder) { + registryBuilder.applySetting( TRANSACTION_COORDINATOR_STRATEGY, "jta" ); + prepare( registryBuilder ); } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/jta/TestingJtaPlatformImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/jta/TestingJtaPlatformImpl.java index 7734b3c8d579..0409e6f65bf5 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/jta/TestingJtaPlatformImpl.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/jta/TestingJtaPlatformImpl.java @@ -4,7 +4,9 @@ */ package org.hibernate.testing.jta; +import jakarta.transaction.NotSupportedException; import jakarta.transaction.Status; +import jakarta.transaction.SystemException; import jakarta.transaction.TransactionManager; import jakarta.transaction.TransactionSynchronizationRegistry; import jakarta.transaction.UserTransaction; @@ -85,6 +87,51 @@ public static void tryCommit() throws Exception { } } + public static void inNoopJtaTransaction(TransactionManager tm, Runnable action) throws Exception { + tm.begin(); + action.run(); + tm.rollback(); + } + + public static void inJtaTransaction(TransactionManager tm, Runnable action) throws Exception { + inJtaTransaction( tm, -1, action ); + } + + public static void inJtaTransaction(TransactionManager tm, int timeout, Runnable action) throws Exception { + // account for the timeout, if one was requested + if ( timeout > 0 ) { + try { + tm.setTransactionTimeout( timeout ); + } + catch (SystemException e) { + throw new RuntimeException( "Unable to set requested JTA timeout", e ); + } + } + + try { + tm.begin(); + } + catch (NotSupportedException | SystemException e) { + throw new RuntimeException( "TransactionManager#begin exception", e ); + } + + try { + action.run(); + + tm.commit(); + } + catch (Exception e) { + try { + tm.rollback(); + } + catch (SystemException ex) { + throw new RuntimeException( ex ); + } + + throw e; + } + } + @Override protected TransactionManager locateTransactionManager() { return transactionManager; diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/retail/CashPayment.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/retail/CashPayment.java index 05007a6fa60a..3c5b96d9ca43 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/retail/CashPayment.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/retail/CashPayment.java @@ -4,6 +4,7 @@ */ package org.hibernate.testing.orm.domain.retail; +import javax.money.Monetary; import javax.money.MonetaryAmount; import jakarta.persistence.Entity; @@ -18,4 +19,8 @@ public CashPayment() { public CashPayment(Integer id, MonetaryAmount amount) { super( id, amount ); } + + public CashPayment(Integer id, Long amount, String currencyCode) { + super( id, Monetary.getDefaultAmountFactory().setNumber( amount ).setCurrency( currencyCode ).create() ); + } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistry.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistry.java index e94cd366acb0..baa02e4124be 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistry.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistry.java @@ -76,6 +76,8 @@ SettingProvider[] settingProviders() default {}; + SettingConfiguration[] settingConfigurations() default {}; + /** * A Hibernate Service registration */ diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryExtension.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryExtension.java index a4cb86890cf7..d9fa74ced39c 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryExtension.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryExtension.java @@ -259,6 +259,8 @@ private static void configureJavaServices(BootstrapServiceRegistry bsrAnn, Boots private static void configureServices(ServiceRegistry serviceRegistryAnn, StandardServiceRegistryBuilder ssrb) { try { + applyConfigurationSets( serviceRegistryAnn, ssrb ); + for ( Setting setting : serviceRegistryAnn.settings() ) { ssrb.applySetting( setting.name(), setting.value() ); } @@ -287,6 +289,19 @@ private static void configureServices(ServiceRegistry serviceRegistryAnn, Standa } } + private static void applyConfigurationSets(ServiceRegistry serviceRegistryAnn, StandardServiceRegistryBuilder ssrb) { + final SettingConfiguration[] settingConfigurations = serviceRegistryAnn.settingConfigurations(); + for ( int i = 0; i < settingConfigurations.length; i++ ) { + try { + final SettingConfiguration.Configurer configurer = settingConfigurations[i].configurer().getDeclaredConstructor().newInstance(); + configurer.applySettings( ssrb ); + } + catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new RuntimeException( e ); + } + } + } + // @Override // public void afterAll(ExtensionContext context) { // log.tracef( "#afterAll(%s)", context.getDisplayName() ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java index c6cc74150ecd..4b68248a2e31 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java @@ -409,5 +409,14 @@ public void inStatelessTransaction(StatelessSession session, Consumer action) { void inStatelessSession(Consumer action); void inStatelessTransaction(Consumer action); void inStatelessTransaction(StatelessSession session, Consumer action); + + void dropData(); } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SettingConfiguration.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SettingConfiguration.java new file mode 100644 index 000000000000..d5ae0998b285 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SettingConfiguration.java @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.testing.orm.junit; + +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; + +/** + * @author Steve Ebersole + */ +public @interface SettingConfiguration { + Class configurer(); + + interface Configurer { + void applySettings(StandardServiceRegistryBuilder registryBuilder); + } +}