hibernate-reactive
hibernate-reactive copied to clipboard
V2.0 Alpha does not use Classloader Service from Service Registry
With v1 this works fine through the registered classloader service, but with v2 it throws an exception when building the session factory:
val configuration = Configuration()
configuration
.setProperty(
Settings.JAKARTA_PERSISTENCE_PROVIDER,
"org.hibernate.reactive.provider.ReactivePersistenceProvider",
)
.setProperty(Settings.DIALECT, "org.hibernate.dialect.PostgreSQL10Dialect")
.setProperty(Settings.URL, databaseConfig.url)
.setProperty(Settings.USER, databaseConfig.username)
.setProperty(Settings.PASS, databaseConfig.password)
.setProperty(Settings.SHOW_SQL, pluginManager.isDevelopment.toString())
.setProperty(Settings.FORMAT_SQL, pluginManager.isDevelopment.toString())
val classloaders = mutableSetOf<ClassLoader>()
for (extension in pluginManager.getExtensions(HibernateConfiguration::class.java)) {
logger.info("Processing extension $extension")
for (clz in extension.annotatedClasses()) {
logger.info("Adding class $clz")
classloaders.add(clz.classLoader)
configuration.addAnnotatedClass(clz)
}
}
val serviceRegistry = hibernateServiceRegistry(configuration, classloaders)
val jpaSessionFactory = configuration.buildSessionFactory(serviceRegistry)
logger.info("JPA SessionFactory initialised")
return jpaSessionFactory.unwrap(Mutiny.SessionFactory::class.java)
private fun hibernateServiceRegistry(
configuration: Configuration,
classloaders: Set<ClassLoader>,
): ServiceRegistry {
// since every plugin has its own classloader and Hibernate needs access to classes inside
// the plugins, the classloader service needs manual composition based on all upstream
// classloaders
val classLoaderService = ClassLoaderServiceImpl(classloaders, TcclLookupPrecedence.BEFORE)
val builder =
ReactiveServiceRegistryBuilder()
.addService(ClassLoaderService::class.java, classLoaderService)
// see
// https://hibernate.org/reactive/documentation/1.0/reference/html_single/#_vert_x_instance_service
// it avoids Hibernate Reactive having to instantiate its own Vert.x
.addService(
VertxInstance::class.java,
VertxInstance { vertx },
)
.applySettings(configuration.properties)
return builder.build()
}
Exception in thread "main" org.hibernate.MappingException: entity class not found: com.marcusilgner.plugin1.models.Model1
at org.hibernate.mapping.PersistentClass.getMappedClass(PersistentClass.java:174)
at org.hibernate.boot.model.internal.BinderHelper.getPropertyOverriddenByMapperOrMapsId(BinderHelper.java:868)
at org.hibernate.boot.model.internal.PropertyBinder.bindBasic(PropertyBinder.java:993)
at org.hibernate.boot.model.internal.PropertyBinder.bindProperty(PropertyBinder.java:867)
at org.hibernate.boot.model.internal.PropertyBinder.buildProperty(PropertyBinder.java:765)
at org.hibernate.boot.model.internal.PropertyBinder.processElementAnnotations(PropertyBinder.java:686)
at org.hibernate.boot.model.internal.EntityBinder.processIdPropertiesIfNotAlready(EntityBinder.java:961)
at org.hibernate.boot.model.internal.EntityBinder.handleIdentifier(EntityBinder.java:302)
at org.hibernate.boot.model.internal.EntityBinder.bindEntityClass(EntityBinder.java:228)
at org.hibernate.boot.model.internal.AnnotationBinder.bindClass(AnnotationBinder.java:417)
at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:255)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:271)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:314)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:121)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:442)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:93)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:863)
at com.marcusilgner.Boot.buildJpaSessionFactory(Boot.kt:155)
Full reproducer at https://github.com/milgner/hibernate-reactive-2-classloader-repro/
I recently re-factored some things in the project to use the latest regular Hibernate and the corresponding classloader registration changed as follows:
private fun hibernateServiceRegistry(
configuration: Configuration,
- classloaders: Set<ClassLoader>,
+ classloaders: Collection<ClassLoader>,
): ServiceRegistry {
// since every plugin has its own classloader and Hibernate needs access to classes inside
// the plugins, the classloader service needs manual composition based on all upstream
// classloaders
- val classLoaderService =
- ClassLoaderServiceImpl(classloaders, TcclLookupPrecedence.BEFORE)
- val builder =
- ReactiveServiceRegistryBuilder()
- .addService(ClassLoaderService::class.java, classLoaderService)
- .applySettings(configuration.properties)
- return builder.build()
+
+ val bootstrapRegistryBuilder = BootstrapServiceRegistryBuilder()
+ classloaders.forEach(bootstrapRegistryBuilder::applyClassLoader)
+ val standardRegistryBuilder = StandardServiceRegistryBuilder(bootstrapRegistryBuilder.build())
+ return standardRegistryBuilder.applySettings(configuration.properties).build()
}
Basically I had to use a custom bootstrap registry builder, add all the classloaders and then use the resulting bootstrap registry to create the standard service registry.
Edit: shortened code snippet for clarity / brevity