Query logging in Hibernate 6 causes an Exception when a query contains a % (LIKE qerry)

I encounter this exception, if a querry is logged which contains a % symbel for a LIKE querry.

Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.lang.Integer eu.rentall.application.repository.AgpInternalOrderRepository.resetInternalOrderFromProcessing(java.lang.Long)
	at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:100)

Caused by: java.util.UnknownFormatConversionException: Conversion = '''
	at java.base/java.util.Formatter.parse(Formatter.java:2750)
	at java.base/java.util.Formatter.format(Formatter.java:2671)
	at java.base/java.util.Formatter.format(Formatter.java:2625)
	at java.base/java.lang.String.format(String.java:4143)
	at org.jboss.logging.Slf4jLocationAwareLogger.doLogf(Slf4jLocationAwareLogger.java:81)
	at org.jboss.logging.Logger.logf(Logger.java:2445)
	at org.jboss.logging.DelegatingBasicLogger.debugf(DelegatingBasicLogger.java:344)
	at org.hibernate.query.hql.internal.StandardHqlTranslator.translate(StandardHqlTranslator.java:75)
	at org.hibernate.internal.AbstractSharedSessionContract.lambda$interpretHql$2(AbstractSharedSessionContract.java:744)
	at org.hibernate.query.internal.QueryInterpretationCacheStandardImpl.createHqlInterpretation(QueryInterpretationCacheStandardImpl.java:141)

I upgraded to Spring Boot 3.1.0 and now also upgraded Hibernate to 6.2.5.Final.
I also use org.slf4j:2.0.7 with org.jboss.logging:3.5.0Final as its implementation.
The log framework is ch.qos.logback:1.4.7.

For querry-logging org.hibernate.query.hql.internal.StandardHqlTranslator#translate is being called.

@Override
public <R> SqmStatement<R> translate(String query, Class<R> expectedResultType) {
	HqlLogging.QUERY_LOGGER.debugf( "HQL : " + query );
	...
}

After debugging through all this code I found the problem is the use of HqlLogging.QUERY_LOGGER.debugf instead of HqlLogging.QUERY_LOGGER.debug.

The difference between those two meathos is this line in org.jboss.logging.Slf4jLocationAwareLogger:

// doLog(..)
final String text = parameters == null || parameters.length == 0 ? String.valueOf(message) : MessageFormat.format(String.valueOf(message), parameters);

// doLogf(..)
final String text = parameters == null ? String.format(format) : String.format(format, parameters);

Since StandardHqlTranslator does not provide parameters, parameters is set to the empty array.
therefore String.format(format, parameters) is called which considers % a format expression.

Solution:
org.hibernate.query.hql.internal.StandardHqlTranslator#translate should bechanged to call:
HqlLogging.QUERY_LOGGER.debug( "HQL : " + query );

Hey there, thanks for the bug report. I created [HHH-16831] - Hibernate JIRA for this which you can watch.

I believe you are missing the point in the bug ticket.

In this particular case no formatting is expected and no parameters are provided.

The problem is, that in this implementation of debugf(..), String.format(..) is called even if there are no parameters.

So either the % needs to be escaped (risky, becasue other logger implementations may have other format placeholders) or debug(..) (without the f) is used for this case, since it would not attempt to apply parameters which do not exist anyway.

As a temporary workaround I would like to provide a custom implementation of org.hibernate.query.hql.HqlTranslator with the outlined fix.

The org.hibernate.query.spi.QueryEngineOptions interface even defines a method:
HqlTranslator getCustomHqlTranslator(); which is extended by SessionFactoryOptions.

However I have yet to find a way, how I can provide those options to Hibernate so it will use my implemantation.

Any help on getting this to work, would be greatly appreciated.

I’m not. The point is that string concatenation shouldn’t happen for the string format part, but it should always use template parameters i.e. %s. See the fix here: HHH-16831 Replace string concat with proper string format for logging by beikov · Pull Request #6842 · hibernate/hibernate-orm · GitHub

You are right. Your aproach is better.
Since the query is now an argument to be applied to the pattern (instead of it becomming part of the pattern) it does not matter what characters it contains. I didn’t see that before.

Oh, and thanks for the swift response and fix.