diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java index 82c9aafbf8..2b517ff0ed 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java @@ -465,10 +465,10 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces final PersistenceContext persistenceContext = session.getPersistenceContext(); final Object proxy = getProxy( persistenceContext ); - // Special case map proxy to avoid stack overflows // We know that a map proxy will always be of "the right type" so just use that object - if ( proxy != null && ( proxy instanceof MapProxy || concreteDescriptor.isInstance( proxy ) ) ) { + if ( proxy != null && ( proxy instanceof MapProxy + || entityDescriptor.getJavaTypeDescriptor().getJavaTypeClass().isInstance( proxy ) ) ) { entityInstance = proxy; } else { diff --git a/hibernate-core/src/test/java/org/hibernate/test/discriminator/Address.java b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Address.java similarity index 90% rename from hibernate-core/src/test/java/org/hibernate/test/discriminator/Address.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Address.java index d25ceacba8..7a91856dc6 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/discriminator/Address.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Address.java @@ -6,7 +6,7 @@ */ //$Id: Address.java 4373 2004-08-18 09:18:34Z oneovthafew $ -package org.hibernate.test.discriminator; +package org.hibernate.orm.test.discriminator; /** diff --git a/hibernate-core/src/test/java/org/hibernate/test/discriminator/Customer.java b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Customer.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/test/discriminator/Customer.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Customer.java index 93bd76c14b..6ee480e3e1 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/discriminator/Customer.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Customer.java @@ -6,7 +6,7 @@ */ //$Id: Customer.java 4373 2004-08-18 09:18:34Z oneovthafew $ -package org.hibernate.test.discriminator; +package org.hibernate.orm.test.discriminator; /** diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/DiscriminatorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/DiscriminatorTest.java new file mode 100755 index 0000000000..3cce0ecc31 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/DiscriminatorTest.java @@ -0,0 +1,315 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.discriminator; + +import java.math.BigDecimal; +import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.hibernate.Hibernate; +import org.hibernate.proxy.HibernateProxy; + +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 static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * @author Gavin King + */ +@DomainModel( + xmlMappings = "org/hibernate/orm/test/discriminator/Person.hbm.xml" +) +@SessionFactory +public class DiscriminatorTest { + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( + session -> + session.createQuery( "delete from Person" ).executeUpdate() + ); + } + + @Test + public void testDiscriminatorSubclass(SessionFactoryScope scope) { + scope.inTransaction( + s -> { + Employee mark = new Employee(); + mark.setName( "Mark" ); + mark.setTitle( "internal sales" ); + mark.setSex( 'M' ); + mark.setAddress( "buckhead" ); + mark.setZip( "30305" ); + mark.setCountry( "USA" ); + + Customer joe = new Customer(); + joe.setName( "Joe" ); + joe.setAddress( "San Francisco" ); + joe.setZip( "XXXXX" ); + joe.setCountry( "USA" ); + joe.setComments( "Very demanding" ); + joe.setSex( 'M' ); + joe.setSalesperson( mark ); + + Person yomomma = new Person(); + yomomma.setName( "mum" ); + yomomma.setSex( 'F' ); + + s.save( yomomma ); + s.save( mark ); + s.save( joe ); + + try { + s.createQuery( "from java.io.Serializable" ).list(); + fail( "Expected IllegalAccessException" ); + } + catch (Exception e) { + assertThat( e, instanceOf( IllegalArgumentException.class ) ); + } + + assertThat( s.createQuery( "from Person" ).list().size(), is( 3 ) ); + assertThat( s.createQuery( "from Person p where p.class = Person" ).list().size(), is( 1 ) ); + assertThat( s.createQuery( "from Person p where p.class = Customer" ).list().size(), is( 1 ) ); + s.clear(); + + List customers = s.createQuery( "from Customer c left join fetch c.salesperson" ).list(); + for ( Customer c : customers ) { + assertTrue( Hibernate.isInitialized( c.getSalesperson() ) ); + assertThat( c.getSalesperson().getName(), is( "Mark" ) ); + } + assertThat( customers.size(), is( 1 ) ); + s.clear(); + + customers = s.createQuery( "from Customer" ).list(); + for ( Customer c : customers ) { + assertFalse( Hibernate.isInitialized( c.getSalesperson() ) ); + assertThat( c.getSalesperson().getName(), is( "Mark" ) ); + } + assertThat( customers.size(), is( 1 ) ); + s.clear(); + + + mark = s.get( Employee.class, mark.getId() ); + joe = s.get( Customer.class, joe.getId() ); + + mark.setZip( "30306" ); + assertThat( s.createQuery( "from Person p where p.address.zip = '30306'" ).list().size(), is( 1 ) ); + s.delete( mark ); + s.delete( joe ); + s.delete( yomomma ); + assertTrue( s.createQuery( "from Person" ).list().isEmpty() ); + } + ); + } + + @Test + public void testAccessAsIncorrectSubclass(SessionFactoryScope scope) { + Employee employee = new Employee(); + scope.inTransaction( + s -> { + employee.setName( "Steve" ); + employee.setSex( 'M' ); + employee.setTitle( "grand poobah" ); + s.save( employee ); + } + ); + + Customer c = null; + scope.fromTransaction( + s -> s.get( Customer.class, employee.getId() ) + ); + assertNull( c ); + + scope.inTransaction( + s -> { + Employee e = s.get( Employee.class, employee.getId() ); + Customer customer = s.get( Customer.class, employee.getId() ); + assertNotNull( e ); + assertNull( customer ); + } + ); + + scope.inTransaction( + session -> session.delete( employee ) + ); + } + + @Test + public void testQuerySubclassAttribute(SessionFactoryScope scope) { + scope.inTransaction( + s -> { + Person p = new Person(); + p.setName( "Emmanuel" ); + p.setSex( 'M' ); + s.persist( p ); + Employee q = new Employee(); + q.setName( "Steve" ); + q.setSex( 'M' ); + q.setTitle( "Mr" ); + q.setSalary( new BigDecimal( 1000 ) ); + s.persist( q ); + + List result = s.createQuery( "from Person where salary > 100" ).list(); + assertEquals( result.size(), 1 ); + assertSame( result.get( 0 ), q ); + + result = s.createQuery( "from Person where salary > 100 or name like 'E%'" ).list(); + assertEquals( result.size(), 2 ); + + CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); + CriteriaQuery criteria = criteriaBuilder.createQuery( Person.class ); + Root root = criteria.from( Person.class ); + criteria.where( criteriaBuilder.gt( root.get( "salary" ), new BigDecimal( 100 ) ) ); + result = s.createQuery( criteria ).list(); +// result = s.createCriteria(Person.class) +// .add( Property.forName( "salary").gt( new BigDecimal( 100) ) ) +// .list(); + assertEquals( result.size(), 1 ); + assertSame( result.get( 0 ), q ); + + //TODO: make this work: + /*result = s.createQuery("select salary from Person where salary > 100").list(); + assertEquals( result.size(), 1 ); + assertEquals( result.get(0), new BigDecimal(1000) );*/ + + s.delete( p ); + s.delete( q ); + + } + ); + } + + @Test + public void testLoadSuperclassProxyPolymorphicAccess(SessionFactoryScope scope) { + Employee e = new Employee(); + scope.inTransaction( + s -> { + e.setName( "Steve" ); + e.setSex( 'M' ); + e.setTitle( "grand poobah" ); + s.save( e ); + } + ); + + scope.inTransaction( + s -> { + // load the superclass proxy. + Person pLoad = s.load( Person.class, e.getId() ); + assertTrue( pLoad instanceof HibernateProxy ); + Person pGet = s.get( Person.class, e.getId() ); + Person pQuery = (Person) s.createQuery( "from Person where id = :id" ) + .setParameter( "id", e.getId() ) + .uniqueResult(); + CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); + CriteriaQuery criteria = criteriaBuilder.createQuery( Person.class ); + Root root = criteria.from( Person.class ); + criteria.where( criteriaBuilder.equal( root.get( "id" ), e.getId() ) ); + Person pCriteria = s.createQuery( criteria ).uniqueResult(); +// Person pCriteria = ( Person ) s.createCriteria( Person.class ) +// .add( Restrictions.idEq( new Long( e.getId() ) ) ) +// .uniqueResult(); + // assert that executing the queries polymorphically returns the same proxy + assertSame( pLoad, pGet ); + assertSame( pLoad, pQuery ); + assertSame( pLoad, pCriteria ); + + // assert that the proxy is not an instance of Employee + assertFalse( pLoad instanceof Employee ); + } + ); + + scope.inTransaction( + s -> { + // load the superclass proxy. + Person pLoad = s.load( Person.class, e.getId() ); + assertTrue( pLoad instanceof HibernateProxy ); + Person pGet = s.get( Person.class, e.getId() ); + Person pQuery = (Person) s.createQuery( "from Person where id = :id" ) + .setParameter( "id", e.getId() ) + .uniqueResult(); + CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); + CriteriaQuery criteria = criteriaBuilder.createQuery( Employee.class ); + Root root = criteria.from( Employee.class ); + criteria.where( criteriaBuilder.equal( root.get( "id" ), e.getId() ) ); + Employee pCriteria = s.createQuery( criteria ).uniqueResult(); +// Person pCriteria = ( Person ) s.createCriteria( Person.class ) +// .add( Restrictions.idEq( new Long( e.getId() ) ) ) +// .uniqueResult(); + // assert that executing the queries polymorphically returns the same proxy + assertSame( pLoad, pGet ); + assertSame( pLoad, pQuery ); + assertNotSame( pLoad, pCriteria ); + + // assert that the proxy is not an instance of Employee + assertFalse( pLoad instanceof Employee ); + } + ); + + scope.inTransaction( + s -> s.delete( e ) + ); + } + + @Test + public void testLoadSuperclassProxyEvictPolymorphicAccess(SessionFactoryScope scope) { + Employee e = new Employee(); + scope.inTransaction( + s -> { + e.setName( "Steve" ); + e.setSex( 'M' ); + e.setTitle( "grand poobah" ); + s.save( e ); + } + ); + + scope.inTransaction( + s -> { + // load the superclass proxy. + Person pLoad = s.load( Person.class, e.getId() ); + assertTrue( pLoad instanceof HibernateProxy ); + // evict the proxy + s.evict( pLoad ); + Employee pGet = (Employee) s.get( Person.class, e.getId() ); + Employee pQuery = (Employee) s.createQuery( "from Person where id = :id" ) + .setParameter( "id", e.getId() ) + .uniqueResult(); + CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); + CriteriaQuery criteria = criteriaBuilder.createQuery( Person.class ); + Root root = criteria.from( Person.class ); + criteria.where( criteriaBuilder.equal( root.get( "id" ), e.getId() ) ); + + Employee pCriteria = (Employee) s.createQuery( criteria ).uniqueResult(); +// Employee pCriteria = ( Employee ) s.createCriteria( Person.class ) +// .add( Restrictions.idEq( new Long( e.getId() ) ) ) +// .uniqueResult(); + // assert that executing the queries polymorphically returns the same Employee instance + assertSame( pGet, pQuery ); + assertSame( pGet, pCriteria ); + } + ); + + scope.inTransaction( + s -> s.delete( e ) + ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/discriminator/Employee.java b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Employee.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/test/discriminator/Employee.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Employee.java index df546f5ab3..abfac5a194 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/discriminator/Employee.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Employee.java @@ -6,7 +6,7 @@ */ //$Id: Employee.java 4373 2004-08-18 09:18:34Z oneovthafew $ -package org.hibernate.test.discriminator; +package org.hibernate.orm.test.discriminator; import java.math.BigDecimal; /** diff --git a/hibernate-core/src/test/java/org/hibernate/test/discriminator/PartTimeEmployee.java b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/PartTimeEmployee.java similarity index 93% rename from hibernate-core/src/test/java/org/hibernate/test/discriminator/PartTimeEmployee.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/PartTimeEmployee.java index 4f86a59f0e..9167996dac 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/discriminator/PartTimeEmployee.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/PartTimeEmployee.java @@ -6,7 +6,7 @@ */ //$Id: Employee.java 4373 2004-08-18 09:18:34Z oneovthafew $ -package org.hibernate.test.discriminator; +package org.hibernate.orm.test.discriminator; import java.math.BigDecimal; /** diff --git a/hibernate-core/src/test/java/org/hibernate/test/discriminator/Person.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Person.hbm.xml similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/test/discriminator/Person.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Person.hbm.xml index c4736d9cb6..9a6e354ae7 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/discriminator/Person.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/discriminator/Person.hbm.xml @@ -18,7 +18,7 @@ -->