diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/path/AbstractJoinImpl.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/path/AbstractJoinImpl.java index ba7c33cf8e..57fe90526b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/path/AbstractJoinImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/path/AbstractJoinImpl.java @@ -19,7 +19,7 @@ import org.hibernate.query.criteria.internal.FromImplementor; import org.hibernate.query.criteria.internal.JoinImplementor; import org.hibernate.query.criteria.internal.PathSource; import org.hibernate.query.criteria.internal.compile.RenderingContext; -import org.hibernate.query.criteria.internal.predicate.AbstractPredicateImpl; +import org.hibernate.query.criteria.internal.predicate.PredicateImplementor; /** * Convenience base class for various {@link javax.persistence.criteria.Join} implementations. @@ -83,7 +83,7 @@ public abstract class AbstractJoinImpl .append( getAlias() ); if ( suppliedJoinCondition != null ) { tableExpression.append( " with " ) - .append( ( (AbstractPredicateImpl) suppliedJoinCondition ).render( renderingContext ) ); + .append( ( (PredicateImplementor) suppliedJoinCondition ).render( renderingContext ) ); } return tableExpression.toString(); } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Book.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Book.java new file mode 100644 index 0000000000..3d9a67243a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Book.java @@ -0,0 +1,52 @@ +/* + * 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.jpa.test.criteria; + +import java.util.List; +import java.util.Set; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +/** + * @author Chris Cranford + */ +@Entity +public class Book { + @Id + @GeneratedValue + private Integer id; + + @OneToMany + private Set stores; + + public Book() { + + } + + public Book(Set stores) { + this.stores = stores; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Set getStores() { + return stores; + } + + public void setStores(Set stores) { + this.stores = stores; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java index e5f4ca5f35..0e75a54ba6 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java @@ -7,13 +7,16 @@ package org.hibernate.jpa.test.criteria; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; +import java.util.HashSet; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; +import javax.persistence.criteria.SetJoin; import javax.persistence.metamodel.EntityType; import org.hibernate.dialect.H2Dialect; @@ -62,7 +65,9 @@ public class QueryBuilderTest extends BaseEntityManagerFunctionalTestCase { Phone.class, Product.class, ShelfLife.class, - Spouse.class + Spouse.class, + Book.class, + Store.class }; } @@ -311,4 +316,35 @@ public class QueryBuilderTest extends BaseEntityManagerFunctionalTestCase { em.createQuery( criteria ).getResultList(); } ); } + + @Test + @TestForIssue(jiraKey = "HHH-12314") + public void testJoinUsingNegatedPredicate() { + // Write test data + doInJPA( this::entityManagerFactory, entityManager -> { + final Store store = new Store(); + store.setName( "Acme Books" ); + store.setAddress( "123 Main St" ); + entityManager.persist( store ); + + final Book book = new Book(); + book.setStores( new HashSet<>( Arrays.asList( store ) ) ); + entityManager.persist( book ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery query = cb.createQuery( Book.class ); + final Root bookRoot = query.from( Book.class ); + + SetJoin storeJoin = bookRoot.join( Book_.stores ); + storeJoin.on( cb.isNotNull( storeJoin.get( Store_.address ) ) ); + + // Previously failed due to ClassCastException + // org.hibernate.query.criteria.internal.predicate.NegatedPredicateWrapper + // cannot be cast to + // org.hibernate.query.criteria.internal.predicate.AbstractPredicateImpl + entityManager.createQuery( query ).getResultList(); + } ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Store.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Store.java new file mode 100644 index 0000000000..6b8bb1dd8f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Store.java @@ -0,0 +1,47 @@ +/* + * 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.jpa.test.criteria; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Chris Cranford + */ +@Entity +public class Store { + @Id + @GeneratedValue + private Integer id; + private String name; + private String address; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } +}