From bfc5fc8a76134ce8dad73b4659115407f52649f4 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Thu, 16 Jan 2025 15:52:32 +0200 Subject: [PATCH] Make methods of reachable hibernate services reflectively queryable Relates to https://github.com/quarkusio/quarkus/issues/41995 Closes https://github.com/quarkusio/quarkus/issues/45525 --- .../orm/deployment/HibernateOrmProcessor.java | 7 ++++ .../RegisterServicesForReflectionFeature.java | 35 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/graal/RegisterServicesForReflectionFeature.java diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java index c321a78029e1c..2c518fbd575d5 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java @@ -97,6 +97,7 @@ import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.deployment.builditem.LiveReloadBuildItem; import io.quarkus.deployment.builditem.LogCategoryBuildItem; +import io.quarkus.deployment.builditem.NativeImageFeatureBuildItem; import io.quarkus.deployment.builditem.ServiceStartBuildItem; import io.quarkus.deployment.builditem.SystemPropertyBuildItem; import io.quarkus.deployment.builditem.TransformedClassesBuildItem; @@ -125,6 +126,7 @@ import io.quarkus.hibernate.orm.runtime.boot.xml.RecordableXmlMapping; import io.quarkus.hibernate.orm.runtime.config.DialectVersions; import io.quarkus.hibernate.orm.runtime.dev.HibernateOrmDevIntegrator; +import io.quarkus.hibernate.orm.runtime.graal.RegisterServicesForReflectionFeature; import io.quarkus.hibernate.orm.runtime.integration.HibernateOrmIntegrationStaticDescriptor; import io.quarkus.hibernate.orm.runtime.migration.MultiTenancyStrategy; import io.quarkus.hibernate.orm.runtime.proxies.PreGeneratedProxies; @@ -160,6 +162,11 @@ public final class HibernateOrmProcessor { private static final String INTEGRATOR_SERVICE_FILE = "META-INF/services/org.hibernate.integrator.spi.Integrator"; + @BuildStep + NativeImageFeatureBuildItem registerServicesForReflection() { + return new NativeImageFeatureBuildItem(RegisterServicesForReflectionFeature.class); + } + @BuildStep void registerHibernateOrmMetadataForCoreDialects( BuildProducer producer) { diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/graal/RegisterServicesForReflectionFeature.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/graal/RegisterServicesForReflectionFeature.java new file mode 100644 index 0000000000000..089f9e439543c --- /dev/null +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/graal/RegisterServicesForReflectionFeature.java @@ -0,0 +1,35 @@ +package io.quarkus.hibernate.orm.runtime.graal; + +import java.util.HashSet; +import java.util.Set; + +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeReflection; + +/** + * Makes methods of reachable hibernate services accessible through {@link Class#getMethods()}. + * + * See Github issue #45525. + */ +public class RegisterServicesForReflectionFeature implements Feature { + + @Override + public String getDescription() { + return "Makes methods of reachable hibernate services accessible through getMethods()`"; + } + + // The {@code duringAnalysis} method is invoked multiple times and increases the set of reachable types, thus we + // need to invoke {@link DuringAnalysisAccess#requireAnalysisIteration()} each time we register new methods. + private static final int ANTICIPATED_SERVICES = 100; + private static final Set> registeredClasses = new HashSet<>(ANTICIPATED_SERVICES); + + @Override + public void duringAnalysis(DuringAnalysisAccess access) { + for (Class service : access.reachableSubtypes(org.hibernate.service.Service.class)) { + if (registeredClasses.add(service)) { + RuntimeReflection.registerAllMethods(service); + access.requireAnalysisIteration(); + } + } + } +}