[BUG?] Criteria API not working since 6.4.0 and 6.4.1 because of missing `if()` in `wrap()` method

Since Hibernate 6.4.0 (including 6.4.1) exception is thrown on code that was working well with 6.3.2.
Couldn’t find anything about it in migration guide.

[ERROR] (AfterApplicationReadyServiceImpl.java:107)
Exception while trying to fetch currency rates:
Could not convert ‘java.util.Currency’ to ‘java.util.Currency’
using ‘org.hibernate.type.descriptor.java.CurrencyJavaType’ to wrap

// code snippet from `updateCurrencyRates()
// called from `AfterApplicationReadyServiceImpl`
final CustomCurrency currency = this.currencyRepository.getByIso4217( "CHF" );

The question: Is there anything I should change / update?

Previously I’ve been using QueryDSL but the project is dead and that’s why I switched to Criteria API which is less readable and uses large amounts of bloating code.


CustomCurrency.java

@Entity
public class CustomCurrency implements Serializable {
	private static final long  serialVersionUID = 3059291965021465724L;
	@Id private Integer id;
	private java.util.Currency javaCurrency;
	private Boolean            isReference = Boolean.FALSE;
	private Boolean            isDefault   = Boolean.FALSE;
}

CurrencyRepositoryImpl.java

public class CurrencyRepositoryImpl {

	public CustomCurrency findByIso4217(final String iso4217code) {

		final CriteriaBuilder               criteriaBuilder = this.entityManager.getCriteriaBuilder();
		final CriteriaQuery<CustomCurrency> criteriaQuery   = criteriaBuilder.createQuery(CustomCurrency.class);
		final Root<CustomCurrency>          root            = criteriaQuery.from(CustomCurrency.class);
		final Path<CustomCurrency>          path            = root.get("javaCurrency");
		final java.util.Currency            javaCurrency    = java.util.Currency.getInstance(iso4217code);
		final Predicate                     predicate       = criteriaBuilder.equal(path, javaCurrency);
		criteriaQuery.where(predicate);
		final TypedQuery<CustomCurrency>    typedQuery      = this.entityManager.createQuery(criteriaQuery);

		// exception is thrown while executing `getResultList()`
		final List<CustomCurrency> results = typedQuery.getResultList();

		if (results.isEmpty()) {
			return null;
		}

		if (results.size() > 1) {
			Log.error("Too many results ({})", Integer.valueOf(results.size()));
			return null;
		}

		return results.get(0);
	}

}

AfterApplicationReadyServiceImpl.java

@Service
public class AfterApplicationReadyServiceImpl
					implements AfterApplicationReadyService
{

	@Transactional(readOnly = false)
	@Override
	public void afterStartup() throws InterruptedException {
		this.currencyUpdaterService.updateCurrencyRates();
	}

}

After setting few breakpoints and going through code step by step, I can say this is the point of failure:

org.hibernate.sql.exec.spi.JdbcParameterBindings

public interface JdbcParameterBindings {

	// ...

	default int registerParametersForEachJdbcValue(
			Object value,
			int offset,
			Bindable bindable,
			JdbcParametersList jdbcParameters,
			SharedSessionContractImplementor session
	) {
		final Object valueToBind;

		if ( bindable instanceof BasicValuedMapping ) {

			// exception is thrown here
			valueToBind =
				( (BasicValuedMapping) bindable )
					.getJdbcMapping()
					.getMappedJavaType()
					.wrap( value, session );

		else {
			valueToBind = value;
		}

		return bindable.forEachJdbcValue(
				valueToBind,
				offset,
				jdbcParameters,
				session.getFactory().getTypeConfiguration(),
				this::createAndAddBinding,
				session
		);
	}

	// ...

}

Ok, I found a bug!

org.hibernate.type.descriptor.java.CurrencyJavaType

value enters here as java.util.Currency and there is no if for that case

@Override
public <X> Currency wrap(X value, WrapperOptions options) {
	if ( value == null ) {
		return null;
	}

	if( value instanceof String ) {
		return Currency.getInstance( (String) value );
	}

	throw unknownWrap( value.getClass() );
}

Yeah, that’s a bug. We recently had a similar bug reported for the LocaleJavaType: [HHH-17466] - Hibernate JIRA
Would you mind creating a new JIRA and providing a PR for this? I guess you can mostly copy-paste what has happened in HHH-17466 Exception on query: Could not convert 'java.util.Locale' to 'java.util.Locale' using 'org.hibernate.type.descriptor.java.LocaleJavaType' to wrap by yrodiere · Pull Request #7575 · hibernate/hibernate-orm · GitHub for Locale.

Thank you! JIRA created (HHH-17574), please feel free to point out if something is missing.