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.

1 Like

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.

I have a similar issue when i do a join and a join fetch like (i use hibernate 6.4.4)

JOIN start.point startPoint
JOIN FETCH startPoint.stopPoint startStop

I fail at the assert in the generateFetch of ToOneAttributeMapping.java

@Override
	public EntityFetch generateFetch(
			FetchParent fetchParent,
			NavigablePath fetchablePath,
			FetchTiming fetchTiming,
			boolean selected,
			String resultVariable,
			DomainResultCreationState creationState) {

		final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
		final FromClauseAccess fromClauseAccess = sqlAstCreationState.getFromClauseAccess();

		final TableGroup parentTableGroup = fromClauseAccess.getTableGroup( fetchParent.getNavigablePath() );

		final NavigablePath parentNavigablePath = fetchablePath.getParent();
		assert parentNavigablePath.equals( fetchParent.getNavigablePath() )
				|| fetchParent.getNavigablePath() instanceof TreatedNavigablePath
				&& parentNavigablePath.equals( fetchParent.getNavigablePath().getRealParent() );

The weird thing is that this seems to work fine when actually running the application but it fails in a @SpringBootTest with MockMvc

i could actually reproduce the issue using the hibernate unittest template and created an issue here [HHH-18086] - Hibernate JIRA

2 Likes

We’re currently migrating our project’s Spring Boot to 3.1.1 (with Hibernate to 6.2.5) and are facing this problem everywhere.

Unfortunately, we extensively rely on this aliasing within our JPQL queries. Has anyone figured out another way to make this work?