HHH-8802 - Class cast exception thrown when trying to access Embedded type relationship path in Tuple
(cherry picked from commit 2e6811f413
)
This commit is contained in:
parent
282a7b1afc
commit
3d89f9e771
|
@ -9,7 +9,10 @@ package org.hibernate.jpa.criteria.path;
|
|||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.metamodel.Attribute;
|
||||
import javax.persistence.metamodel.Bindable;
|
||||
import javax.persistence.metamodel.ManagedType;
|
||||
import javax.persistence.metamodel.PluralAttribute;
|
||||
import javax.persistence.metamodel.SingularAttribute;
|
||||
import javax.persistence.metamodel.Type;
|
||||
|
||||
import org.hibernate.jpa.criteria.CriteriaBuilderImpl;
|
||||
import org.hibernate.jpa.criteria.CriteriaSubqueryImpl;
|
||||
|
@ -36,13 +39,17 @@ public class SingularAttributeJoin<O,X> extends AbstractJoinImpl<O,X> {
|
|||
SingularAttribute<? super O, ?> joinAttribute,
|
||||
JoinType joinType) {
|
||||
super( criteriaBuilder, javaType, pathSource, joinAttribute, joinType );
|
||||
this.model = (Bindable<X>) (
|
||||
Attribute.PersistentAttributeType.EMBEDDED == joinAttribute.getPersistentAttributeType()
|
||||
? joinAttribute
|
||||
: javaType != null
|
||||
? criteriaBuilder.getEntityManagerFactory().getMetamodel().managedType( javaType )
|
||||
: joinAttribute.getType()
|
||||
);
|
||||
if ( Attribute.PersistentAttributeType.EMBEDDED == joinAttribute.getPersistentAttributeType() ) {
|
||||
this.model = (Bindable<X>) joinAttribute;
|
||||
}
|
||||
else {
|
||||
if ( javaType != null ) {
|
||||
this.model = (Bindable<X>) criteriaBuilder.getEntityManagerFactory().getMetamodel().managedType( javaType );
|
||||
}
|
||||
else {
|
||||
this.model = (Bindable<X>) joinAttribute.getType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,6 +78,34 @@ public class SingularAttributeJoin<O,X> extends AbstractJoinImpl<O,X> {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ManagedType<? super X> locateManagedType() {
|
||||
if ( getModel().getBindableType() == Bindable.BindableType.ENTITY_TYPE ) {
|
||||
return (ManagedType<? super X>) getModel();
|
||||
}
|
||||
else if ( getModel().getBindableType() == Bindable.BindableType.SINGULAR_ATTRIBUTE ) {
|
||||
final Type joinedAttributeType = ( (SingularAttribute) getAttribute() ).getType();
|
||||
if ( !ManagedType.class.isInstance( joinedAttributeType ) ) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot further dereference attribute join [" + getPathIdentifier() + "] as its type is not a ManagedType"
|
||||
);
|
||||
}
|
||||
return (ManagedType<? super X>) joinedAttributeType;
|
||||
}
|
||||
else if ( getModel().getBindableType() == Bindable.BindableType.PLURAL_ATTRIBUTE ) {
|
||||
final Type elementType = ( (PluralAttribute) getAttribute() ).getElementType();
|
||||
if ( !ManagedType.class.isInstance( elementType ) ) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot further dereference attribute join [" + getPathIdentifier() + "] (plural) as its element type is not a ManagedType"
|
||||
);
|
||||
}
|
||||
return (ManagedType<? super X>) elementType;
|
||||
}
|
||||
|
||||
return super.locateManagedType();
|
||||
}
|
||||
|
||||
public Bindable<X> getModel() {
|
||||
return model;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.criteria.components.joins;
|
||||
|
||||
import java.util.List;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Tuple;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.metamodel.SingularAttribute;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class ComponentJoinTest extends BaseEntityManagerFunctionalTestCase {
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Entity.class, EmbeddedType.class, ManyToOneType.class };
|
||||
}
|
||||
|
||||
public static final String THEVALUE = "thevalue";
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
EntityManager entityManager = entityManagerFactory().createEntityManager();
|
||||
entityManager.getTransaction().begin();
|
||||
ManyToOneType manyToOneType = new ManyToOneType( THEVALUE );
|
||||
EmbeddedType embeddedType = new EmbeddedType( manyToOneType );
|
||||
Entity entity = new Entity( embeddedType );
|
||||
entityManager.persist( entity );
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
EntityManager entityManager = entityManagerFactory().createEntityManager();
|
||||
entityManager.getTransaction().begin();
|
||||
entityManager.createQuery( "delete Entity" ).executeUpdate();
|
||||
entityManager.createQuery( "delete ManyToOneType" ).executeUpdate();
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();
|
||||
}
|
||||
|
||||
interface JoinBuilder {
|
||||
Join<EmbeddedType,ManyToOneType> buildJoinToManyToOneType(Join<Entity, EmbeddedType> source);
|
||||
}
|
||||
|
||||
private void doTest(JoinBuilder joinBuilder) {
|
||||
EntityManager entityManager = getOrCreateEntityManager();
|
||||
entityManager.getTransaction().begin();
|
||||
|
||||
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Tuple> criteriaQuery = builder.createTupleQuery();
|
||||
Root<Entity> root = criteriaQuery.from( Entity.class );
|
||||
Join<Entity, EmbeddedType> join = root.join( "embeddedType", JoinType.LEFT );
|
||||
|
||||
// left join to the manyToOne on the embeddable with a string property
|
||||
Path<String> path = joinBuilder.buildJoinToManyToOneType( join ).get( "value" );
|
||||
|
||||
// select the path in the tuple
|
||||
criteriaQuery.select( builder.tuple( path ) );
|
||||
|
||||
List<Tuple> results = entityManager.createQuery( criteriaQuery ).getResultList();
|
||||
Tuple result = results.iterator().next();
|
||||
|
||||
assertEquals( THEVALUE, result.get(0) );
|
||||
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResultWithStringPropertyDerivedPath() {
|
||||
doTest(
|
||||
new JoinBuilder() {
|
||||
@Override
|
||||
public Join<EmbeddedType, ManyToOneType> buildJoinToManyToOneType(Join<Entity, EmbeddedType> source) {
|
||||
return source.join( "manyToOneType", JoinType.LEFT );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getResultWithMetamodelDerivedPath() {
|
||||
doTest(
|
||||
new JoinBuilder() {
|
||||
@Override
|
||||
public Join<EmbeddedType, ManyToOneType> buildJoinToManyToOneType(Join<Entity, EmbeddedType> source) {
|
||||
final SingularAttribute<EmbeddedType, ManyToOneType> attr =
|
||||
(SingularAttribute<EmbeddedType, ManyToOneType>) entityManagerFactory().getMetamodel()
|
||||
.managedType( EmbeddedType.class )
|
||||
.getDeclaredSingularAttribute( "manyToOneType" );
|
||||
return source.join( attr, JoinType.LEFT );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
package org.hibernate.jpa.test.criteria.components.joins;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
/**
|
||||
* @author Matt Todd
|
||||
*/
|
||||
@Embeddable
|
||||
public class EmbeddedType {
|
||||
@ManyToOne(cascade = CascadeType.ALL)
|
||||
private ManyToOneType manyToOneType;
|
||||
|
||||
public EmbeddedType() {
|
||||
}
|
||||
|
||||
public EmbeddedType(ManyToOneType manyToOneType) {
|
||||
this.manyToOneType = manyToOneType;
|
||||
}
|
||||
|
||||
public ManyToOneType getManyToOneType() {
|
||||
return manyToOneType;
|
||||
}
|
||||
|
||||
public void setManyToOneType(ManyToOneType manyToOneType) {
|
||||
this.manyToOneType = manyToOneType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.criteria.components.joins;
|
||||
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@javax.persistence.Entity
|
||||
public class Entity {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@Embedded
|
||||
private EmbeddedType embeddedType;
|
||||
|
||||
public Entity() {
|
||||
// for jpa
|
||||
}
|
||||
|
||||
public Entity(EmbeddedType embeddedType) {
|
||||
this.embeddedType = embeddedType;
|
||||
}
|
||||
|
||||
public EmbeddedType getEmbeddedType() {
|
||||
return embeddedType;
|
||||
}
|
||||
|
||||
public void setEmbeddedType(EmbeddedType embeddedType) {
|
||||
this.embeddedType = embeddedType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.criteria.components.joins;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Matt Todd
|
||||
*/
|
||||
@Entity
|
||||
public class ManyToOneType {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Long id;
|
||||
private String value;
|
||||
|
||||
public ManyToOneType() {
|
||||
}
|
||||
|
||||
public ManyToOneType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue