Custom types not working since HHH-14335 (introduced in 5.4.25)

Hello

We have been testing the newest Spring Boot version (2.4.1) that bumps Hibernate to version 5.4.25.
We also use Jadira User Types to register custom types for Joda Time classes.
Since 5.4.25 it seems that the custom types are no longer working as espected.
We tried debugging this issue, and it seems to be tied to the fix for HHH-14335.

Our findings are as follows:

  1. During initialization, the SPI classes are found:
	  at org.jadira.usertype.dateandtime.joda.integrator.UserTypeJodaTimeHibernateIntegrator.<clinit>(UserTypeJodaTimeHibernateIntegrator.java:44)
      [...]
	  at org.hibernate.boot.registry.classloading.internal.AggregatedServiceLoader$ClassPathAndModulePathAggregatedServiceLoader.collectServiceIfNotDuplicate(AggregatedServiceLoader.java:276)
	  at org.hibernate.boot.registry.classloading.internal.AggregatedServiceLoader$ClassPathAndModulePathAggregatedServiceLoader.loadAll(AggregatedServiceLoader.java:201)
	  at org.hibernate.boot.registry.classloading.internal.AggregatedServiceLoader$ClassPathAndModulePathAggregatedServiceLoader.getAll(AggregatedServiceLoader.java:187)
	  at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.loadJavaServices(ClassLoaderServiceImpl.java:251)
	  at org.hibernate.integrator.internal.IntegratorServiceImpl.<init>(IntegratorServiceImpl.java:40)
	  at org.hibernate.boot.registry.BootstrapServiceRegistryBuilder.build(BootstrapServiceRegistryBuilder.java:224)
	  at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.buildBootstrapServiceRegistry(EntityManagerFactoryBuilderImpl.java:452)
	  at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:208)
	  at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:168)
  1. There appears to be a metadata validation step that will eagerly initialize all types:
	  at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:484)
	  at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:466)
	  at org.hibernate.mapping.Property.isValid(Property.java:227)
	  at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:624)
	  at org.hibernate.mapping.RootClass.validate(RootClass.java:267)
	  at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:354)
	  at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:465)
	  at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259)

The heuristicType call on org.hibernate.mapping.SimpleValue.getType() returns org.hibernate.type.SerializableType, which is incorrect.
However, critically, in 5.4.24 and earlier versions, this result was not cached.

  1. User types are then loaded from the SPI classes:
	  at org.jadira.usertype.dateandtime.joda.integrator.UserTypeJodaTimeHibernateIntegrator.getUserTypes(UserTypeJodaTimeHibernateIntegrator.java:97)
	  at org.jadira.usertype.spi.shared.AbstractUserTypeHibernateIntegrator.autoRegisterUsertypes(AbstractUserTypeHibernateIntegrator.java:135)
	  at org.jadira.usertype.spi.shared.AbstractUserTypeHibernateIntegrator.integrate(AbstractUserTypeHibernateIntegrator.java:203)
	  at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:282)
	  at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:469)

Before the fix for HHH-14335 the types were not cached, so this was not problematic, since later the type would be recreated as a org.hibernate.type.CustomType on SimpleValue.

  1. Later org.hibernate.mapping.SimpleValue.getType() gets called again:
	  at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:484)
	  at org.hibernate.tuple.PropertyFactory.buildEntityBasedAttribute(PropertyFactory.java:159)
	  at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:231)
	  at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:609)
	  at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:128)
	  [...]
	  at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:96)
	  at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:77)
	  at org.hibernate.metamodel.internal.MetamodelImpl.initialize(MetamodelImpl.java:181)
	  at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:301)
	  at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:469)
	  at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259)

On version 5.4.24, the heuristicType call returns the correct type: org.hibernate.type.CustomType
Whereas on version 5.4.25 and later the call does not happen at all, since the earlier incorrect type is cached.

I’m unsure about the protocol here. Should I try to open a ticket directly on hibernate.atlassian.net?

(Edited to change stacktraces to be more readable)

Thanks for the report. I created [HHH-14408] SPI provided user types are not applied - Hibernate JIRA for this.