How to fix JPA or Hibernate BasicAttributeMapping cannot be cast to class TableGroupJoinProducer Snippet
Updated: May 18, 2024
Coding Example
User.java
@Entity
@Table(name = "user")
public class User {
@Id
@Column(name = "id", nullable = false)
private Long id;
@Size(max = 255)
@Column(name = "first_name")
private String firstName;
@Size(max = 255)
@Column(name = "last_name")
private String lastName;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<Role> roles;
}
UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> {
@Query("""
FROM User user
// The issue occurs because the query incorrectly joins the "lastName" column instead of the intended "role" entity association.
JOIN user.lastName
""")
List<User> userDetail();
}
Error.log
java.lang.ClassCastException: class org.hibernate.metamodel.mapping.internal.BasicAttributeMapping cannot be cast to class org.hibernate.sql.ast.tree.from.TableGroupJoinProducer (org.hibernate.metamodel.mapping.internal.BasicAttributeMapping and org.hibernate.sql.ast.tree.from.TableGroupJoinProducer are in unnamed module of loader 'app')
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeAttributeJoin(BaseSqmToSqlAstConverter.java:3317) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeExplicitJoin(BaseSqmToSqlAstConverter.java:3234) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.lambda$consumeExplicitJoins$43(BaseSqmToSqlAstConverter.java:3205) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at java.base/java.util.ArrayList.forEach(ArrayList.java:1597) ~[na:na]
at org.hibernate.query.sqm.tree.domain.AbstractSqmFrom.visitSqmJoins(AbstractSqmFrom.java:260) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeExplicitJoins(BaseSqmToSqlAstConverter.java:3201) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeJoins(BaseSqmToSqlAstConverter.java:2864) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeFromClauseRoot(BaseSqmToSqlAstConverter.java:2822) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at java.base/java.util.ArrayList.forEach(ArrayList.java:1597) ~[na:na]
at org.hibernate.query.sqm.tree.from.SqmFromClause.visitRoots(SqmFromClause.java:80) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitFromClause(BaseSqmToSqlAstConverter.java:2573) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQuerySpec(BaseSqmToSqlAstConverter.java:2055) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQuerySpec(BaseSqmToSqlAstConverter.java:440) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.tree.select.SqmQuerySpec.accept(SqmQuerySpec.java:127) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.spi.BaseSemanticQueryWalker.visitQueryPart(BaseSemanticQueryWalker.java:218) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQueryPart(BaseSqmToSqlAstConverter.java:1915) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitSelectStatement(BaseSqmToSqlAstConverter.java:1600) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitSelectStatement(BaseSqmToSqlAstConverter.java:440) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.tree.select.SqmSelectStatement.accept(SqmSelectStatement.java:228) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.translate(BaseSqmToSqlAstConverter.java:776) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.buildCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:402) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:327) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:303) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:509) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:427) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.hibernate.query.Query.getResultList(Query.java:120) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final]
at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:129) ~[spring-data-jpa-3.2.5.jar:3.2.5]
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:92) ~[spring-data-jpa-3.2.5.jar:3.2.5]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:149) ~[spring-data-jpa-3.2.5.jar:3.2.5]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:137) ~[spring-data-jpa-3.2.5.jar:3.2.5]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170) ~[spring-data-commons-3.2.5.jar:3.2.5]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158) ~[spring-data-commons-3.2.5.jar:3.2.5]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:164) ~[spring-data-commons-3.2.5.jar:3.2.5]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143) ~[spring-data-commons-3.2.5.jar:3.2.5]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.6.jar:6.1.6]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:70) ~[spring-data-commons-3.2.5.jar:3.2.5]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.6.jar:6.1.6]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-6.1.6.jar:6.1.6]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:392) ~[spring-tx-6.1.6.jar:6.1.6]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-6.1.6.jar:6.1.6]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.6.jar:6.1.6]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-6.1.6.jar:6.1.6]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.6.jar:6.1.6]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135) ~[spring-data-jpa-3.2.5.jar:3.2.5]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.6.jar:6.1.6]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-6.1.6.jar:6.1.6]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.6.jar:6.1.6]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223) ~[spring-aop-6.1.6.jar:6.1.6]
at jdk.proxy4/jdk.proxy4.$Proxy166.listUser(Unknown Source) ~[na:na]
at com.onlineappzone.demo.service.UserServiceImpl.userDetail(UserServiceImpl.java:43) ~[classes/:na]
at com.onlineappzone.demo.controller.UserController.userDetail(UserController.java:27) ~[classes/:na]
Solution
One easy way to solve this problem is to make sure you’re joining the correct entity together. In the query, instead of joining with a column like “user.lastName,” join with the Role table, like “user.role”.
UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> {
@Query("""
FROM User user
JOIN user.role
""")
List<User> userDetail();
}