Getting AssertionError in ToOneAttributeMapping.createTableGroupJoin

Hey!

I am facing very weird issue. I have this Spring JpaRepository method:

  @Query(
    """
    from Screenshot s
    join fetch s.keyScreenshotReferences ksr
    join fetch ksr.key k
    where s in :screenshots
  """
  )
  fun getScreenshotsWithReferences(screenshots: Collection<Screenshot>): List<Screenshot>

The Screenshot entity looks like this:

@Entity
@Table(indexes = [Index(name = "screenshot_location_idx", columnList = "location")])
class Screenshot : StandardAuditModel() {
...
  @OneToMany(mappedBy = "screenshot", orphanRemoval = true)
  var keyScreenshotReferences: MutableList<KeyScreenshotReference> = mutableListOf()
...

The KeyScreenshotReference looks like this:

@Entity
@IdClass(KeyScreenshotReferenceId::class)
class KeyScreenshotReference {
  @ManyToOne(optional = false)
  @Id
  lateinit var key: Key

  @ManyToOne(optional = false)
  @Id
  lateinit var screenshot: Screenshot
...
}

And Key entity like this:

@Entity
class Key() : StandardAuditModel() {
...
  @OneToMany(mappedBy = "key", orphanRemoval = true)
  var keyScreenshotReferences: MutableList<KeyScreenshotReference> = mutableListOf()

I am geeting this assetion error:

Caused by: java.lang.AssertionError
	at org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping.createTableGroupJoin(ToOneAttributeMapping.java:1853)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeAttributeJoin(BaseSqmToSqlAstConverter.java:3322)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeExplicitJoin(BaseSqmToSqlAstConverter.java:3239)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.lambda$consumeExplicitJoins$42(BaseSqmToSqlAstConverter.java:3210)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.hibernate.query.sqm.tree.domain.AbstractSqmFrom.visitSqmJoins(AbstractSqmFrom.java:260)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeExplicitJoins(BaseSqmToSqlAstConverter.java:3206)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeAttributeJoin(BaseSqmToSqlAstConverter.java:3393)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeExplicitJoin(BaseSqmToSqlAstConverter.java:3239)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.lambda$consumeExplicitJoins$42(BaseSqmToSqlAstConverter.java:3210)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.hibernate.query.sqm.tree.domain.AbstractSqmFrom.visitSqmJoins(AbstractSqmFrom.java:260)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeExplicitJoins(BaseSqmToSqlAstConverter.java:3206)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeJoins(BaseSqmToSqlAstConverter.java:2881)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.consumeFromClauseRoot(BaseSqmToSqlAstConverter.java:2820)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.hibernate.query.sqm.tree.from.SqmFromClause.visitRoots(SqmFromClause.java:80)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitFromClause(BaseSqmToSqlAstConverter.java:2571)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQuerySpec(BaseSqmToSqlAstConverter.java:2053)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQuerySpec(BaseSqmToSqlAstConverter.java:439)
	at org.hibernate.query.sqm.tree.select.SqmQuerySpec.accept(SqmQuerySpec.java:125)
	at org.hibernate.query.sqm.spi.BaseSemanticQueryWalker.visitQueryPart(BaseSemanticQueryWalker.java:218)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQueryPart(BaseSqmToSqlAstConverter.java:1913)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitSelectStatement(BaseSqmToSqlAstConverter.java:1598)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitSelectStatement(BaseSqmToSqlAstConverter.java:439)
	at org.hibernate.query.sqm.tree.select.SqmSelectStatement.accept(SqmSelectStatement.java:225)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.translate(BaseSqmToSqlAstConverter.java:775)
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.buildCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:345)
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:270)
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:246)
	at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:509)
	at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:427)
	at org.hibernate.query.Query.getResultList(Query.java:120)
	at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:129)
	at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:92)
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:148)
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:136)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:164)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)

The related part of createTableGroupJoin function body from Hibernate code is:

	@Override
	public TableGroupJoin createTableGroupJoin(
			NavigablePath navigablePath,
			TableGroup lhs,
			String explicitSourceAlias,
			SqlAliasBase explicitSqlAliasBase,
			SqlAstJoinType requestedJoinType,
			boolean fetched,
			boolean addsPredicate,
			SqlAstCreationState creationState) {
		// Make sure the lhs is never a plural table group directly, but always a table group for a part
		// This is vital for the map key property check that comes next
		assert !( lhs instanceof PluralTableGroup );
...

I’ve also tried to debug it to find out the cause. The navigablePath param passed into createTableGroupJoin is io.tolgee.model.Screenshot(s).keyScreenshotReferences(ksr).{element}.{id}.key(k).

When I remove the joining of Screenshot -> keyCodeReferences it works. So as a workaround I replaced all the joins required filtering by creating subqueries and joining Key -> keyCodeReferences and filtering Screenshot.id in all other queries. But in this case I need to join fetch, so can’t simply replace it.

Thanks for any help!

I am using Hibernate 6.3.1, but it’s also reproducible on 6.2.9. It worked fine in 5.x.

This looks like a bug. Please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) that reproduces the issue.