Hibernate 6.6 enum literal is considered field literal instead

The following Spring Boot query:

@Query("""
      SELECT new com.acme.PaymentReferenceItem(com.acme.PaymentReferenceItem$Type.TRANSACTION, e.id, e.reference) \
      FROM Transaction e WHERE e.reference IN :references UNION ALL \
      SELECT new com.acme.PaymentReferenceItem(com.acme.PaymentReferenceItem$Type.DIRECT_DEBIT, e.id, e.reference) \
      FROM DirectDebit e WHERE e.reference IN :references UNION ALL \
      SELECT new com.acme.PaymentReferenceItem(com.acme.PaymentReferenceItem$Type.DIRECT_DEBIT_GROUP, e.id, e.reference) \
      FROM DirectDebitGroup e WHERE e.reference IN :references
      """)
  Set<PaymentReferenceItem> findExistingReferences(Set<String> references);

where the enum is

public record PaymentReferenceItem(Type type, Long id, String reference) {
  public enum Type {
    TRANSACTION, DIRECT_DEBIT_GROUP, DIRECT_DEBIT
  }
}

Worked as expected on 6.5.3. The PaymentReferenceItem$Type was considered a SqmEnumLiteral while doing conversion.

But now with Hibernate 6.6.2 it causes the exception Could not determine ValueMapping for SqmExpression: org.hibernate.query.sqm.tree.expression.SqmFieldLiteral on BaseSqmToSqlAstConverter.

I tried debugging but couldn’t figure out why it’s no longer considered a SqmEnumLiteral. Any ideas?

Hello @samba, your query looks fine to me, especially since you say it worked in a previous version - could you please also try with the more recent 6.6.3?

If the issue persists, this is probably caused by a bug - please try to create a reproducer with our test case template and if you are able to reproduce the issue, create a new ticket in our issue tracker and attach that reproducer.

Thanks for your reply @mbladel . Tried with 6.6.3 but had the same issue. Seems to happen consistently where a literal enum is used with a constructor in HQL, like SELECT new com.acme.MyClass(com.acme.MyEnum.VALUE, e.arg2, e.arg3...) FROM MyEntity e.

For completeness I’ll add the stacktrace that I missed in my original post:

Caused by: org.hibernate.query.sqm.sql.ConversionException: Could not determine ValueMapping for SqmExpression: org.hibernate.query.sqm.tree.expression.SqmFieldLiteral@3da82e6a
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.determineValueMapping(BaseSqmToSqlAstConverter.java:6088)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.determineValueMapping(BaseSqmToSqlAstConverter.java:5965)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitFieldLiteral(BaseSqmToSqlAstConverter.java:7361)
	at org.hibernate.query.sqm.tree.expression.SqmFieldLiteral.accept(SqmFieldLiteral.java:139)
	at org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationArgument.accept(SqmDynamicInstantiationArgument.java:57)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitDynamicInstantiation(BaseSqmToSqlAstConverter.java:1656)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitDynamicInstantiation(BaseSqmToSqlAstConverter.java:454)
	at org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation.accept(SqmDynamicInstantiation.java:254)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitSelection(BaseSqmToSqlAstConverter.java:2270)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitSelectClause(BaseSqmToSqlAstConverter.java:2212)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQuerySpec(BaseSqmToSqlAstConverter.java:2083)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQuerySpec(BaseSqmToSqlAstConverter.java:454)
	at org.hibernate.query.sqm.tree.select.SqmQuerySpec.accept(SqmQuerySpec.java:124)
	at org.hibernate.query.sqm.spi.BaseSemanticQueryWalker.visitQueryPart(BaseSemanticQueryWalker.java:245)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQueryPart(BaseSqmToSqlAstConverter.java:1943)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitSelectStatement(BaseSqmToSqlAstConverter.java:1629)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitSelectStatement(BaseSqmToSqlAstConverter.java:454)
	at org.hibernate.query.sqm.tree.select.SqmSelectStatement.accept(SqmSelectStatement.java:238)
	at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.translate(BaseSqmToSqlAstConverter.java:800)
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.buildCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:482)
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:388)
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:362)
	at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:380)
	at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:143)
	at org.hibernate.query.Query.getResultList(Query.java:120)

We have unfortunately the exact same problem, blocking our upgrade to Spring Boot 3.4.0 :frowning:

We use the exact same construct like the original author

Same issue here. Worked around by adding a secondary constructor that accepts a String instead of the enum, but this seems less than optimal.

Once again, please create an issue in our tracker and attach a simple reproducer test case so that someone from the Hibernate team can take a look and try to fix this issue, thanks.

Here is simple test case

@DomainModel(annotatedClasses = Transaction.class)
@SessionFactory
public class Test10672 {

	@Test
	void test(SessionFactoryScope scope) {
		scope.fromSession( em ->
				em.createQuery( """
								SELECT new org.hibernate.bugs.PaymentReferenceItem(org.hibernate.bugs.PaymentReferenceItem$Type.TRANSACTION, e.id, e.reference) \
								FROM Transaction e WHERE e.reference IN :references""", PaymentReferenceItem.class )
						.setParameter( "references", List.of( "abc" ) )
						.getResultList() );
	}
}

@Entity
class Transaction {
	@Id
	Long id;
	String reference;

}

record PaymentReferenceItem(Type type, Long id, String reference) {
	public enum Type {
		TRANSACTION, DIRECT_DEBIT_GROUP, DIRECT_DEBIT
	}
}

I’ve simplified example above (DTO class is not needed to make it fail) and created possible solution proposal - Jira issue HHH-18894 and pull request #9342

1 Like