11package io .quarkus .hibernate .orm .deployment ;
22
3+ import java .lang .annotation .Annotation ;
34import java .util .ArrayList ;
45import java .util .Arrays ;
56import java .util .List ;
89import java .util .stream .Collectors ;
910
1011import jakarta .enterprise .context .ApplicationScoped ;
11- import jakarta .enterprise .inject .Any ;
1212import jakarta .enterprise .inject .Default ;
13- import jakarta .enterprise .inject .Instance ;
1413import jakarta .inject .Singleton ;
1514import jakarta .persistence .AttributeConverter ;
1615import jakarta .transaction .TransactionManager ;
1716
1817import org .hibernate .Session ;
1918import org .hibernate .SessionFactory ;
2019import org .hibernate .StatelessSession ;
21- import org .jboss .jandex .AnnotationInstance ;
2220import org .jboss .jandex .AnnotationTarget .Kind ;
2321import org .jboss .jandex .AnnotationValue ;
2422import org .jboss .jandex .ClassType ;
2523import org .jboss .jandex .DotName ;
2624import org .jboss .jandex .FieldInfo ;
27- import org .jboss .jandex .ParameterizedType ;
2825import org .jboss .jandex .Type ;
2926
30- import io .agroal .api .AgroalDataSource ;
3127import io .quarkus .agroal .spi .JdbcDataSourceBuildItem ;
28+ import io .quarkus .arc .Arc ;
29+ import io .quarkus .arc .ArcContainer ;
30+ import io .quarkus .arc .InstanceHandle ;
3231import io .quarkus .arc .deployment .AdditionalBeanBuildItem ;
3332import io .quarkus .arc .deployment .AnnotationsTransformerBuildItem ;
3433import io .quarkus .arc .deployment .BeanDefiningAnnotationBuildItem ;
34+ import io .quarkus .arc .deployment .ObserverRegistrationPhaseBuildItem ;
3535import io .quarkus .arc .deployment .SyntheticBeanBuildItem ;
3636import io .quarkus .arc .deployment .SyntheticBeanBuildItem .ExtendedBeanConfigurator ;
3737import io .quarkus .arc .deployment .UnremovableBeanBuildItem ;
4747import io .quarkus .deployment .annotations .ExecutionTime ;
4848import io .quarkus .deployment .annotations .Record ;
4949import io .quarkus .deployment .builditem .CombinedIndexBuildItem ;
50+ import io .quarkus .gizmo .MethodDescriptor ;
51+ import io .quarkus .gizmo .ResultHandle ;
5052import io .quarkus .hibernate .orm .PersistenceUnit ;
5153import io .quarkus .hibernate .orm .runtime .HibernateOrmRecorder ;
5254import io .quarkus .hibernate .orm .runtime .HibernateOrmRuntimeConfig ;
5658import io .quarkus .hibernate .orm .runtime .RequestScopedStatelessSessionHolder ;
5759import io .quarkus .hibernate .orm .runtime .TransactionSessions ;
5860import io .quarkus .hibernate .orm .runtime .cdi .QuarkusArcBeanContainer ;
61+ import io .quarkus .runtime .ShutdownEvent ;
5962
6063@ BuildSteps (onlyIf = HibernateOrmEnabled .class )
6164public class HibernateOrmCdiProcessor {
@@ -131,7 +134,6 @@ public void transform(TransformationContext transformationContext) {
131134 @ BuildStep
132135 @ Record (ExecutionTime .RUNTIME_INIT )
133136 void generateJpaConfigBean (HibernateOrmRecorder recorder ,
134- Capabilities capabilities ,
135137 HibernateOrmRuntimeConfig hibernateOrmRuntimeConfig ,
136138 BuildProducer <SyntheticBeanBuildItem > syntheticBeanBuildItemBuildProducer ) {
137139 ExtendedBeanConfigurator configurator = SyntheticBeanBuildItem
@@ -140,28 +142,45 @@ void generateJpaConfigBean(HibernateOrmRecorder recorder,
140142 .scope (Singleton .class )
141143 .unremovable ()
142144 .setRuntimeInit ()
143- .supplier (recorder .jpaConfigSupplier (hibernateOrmRuntimeConfig ))
144- .destroyer (JPAConfig .Destroyer .class );
145-
146- // Add a synthetic dependency from JPAConfig to any datasource/pool,
147- // so that JPAConfig is destroyed before the datasource/pool.
148- // The alternative would be adding an application destruction observer
149- // (@Observes @BeforeDestroyed(ApplicationScoped.class)) to JPAConfig,
150- // but that would force initialization of JPAConfig upon application shutdown,
151- // which may cause cascading failures if the shutdown happened before JPAConfig was initialized.
152- if (capabilities .isPresent (Capability .HIBERNATE_REACTIVE )) {
153- configurator .addInjectionPoint (ParameterizedType .create (DotName .createSimple (Instance .class ),
154- new Type [] { ClassType .create (DotName .createSimple ("io.vertx.sqlclient.Pool" )) }, null ),
155- AnnotationInstance .builder (Any .class ).build ());
156- } else {
157- configurator .addInjectionPoint (ParameterizedType .create (DotName .createSimple (Instance .class ),
158- new Type [] { ClassType .create (DotName .createSimple (AgroalDataSource .class )) }, null ),
159- AnnotationInstance .builder (Any .class ).build ());
160- }
145+ .supplier (recorder .jpaConfigSupplier (hibernateOrmRuntimeConfig ));
161146
162147 syntheticBeanBuildItemBuildProducer .produce (configurator .done ());
163148 }
164149
150+ @ BuildStep
151+ @ Record (ExecutionTime .RUNTIME_INIT )
152+ void generateJpaConfigBeanObserver (
153+ HibernateOrmRecorder recorder ,
154+ ObserverRegistrationPhaseBuildItem observerRegistrationPhase ,
155+ BuildProducer <ObserverRegistrationPhaseBuildItem .ObserverConfiguratorBuildItem > observerConfigurationRegistry ) {
156+ observerConfigurationRegistry .produce (
157+ new ObserverRegistrationPhaseBuildItem .ObserverConfiguratorBuildItem (observerRegistrationPhase .getContext ()
158+ .configure ()
159+ .beanClass (DotName .createSimple ("io.quarkus.hibernate.orm.runtime.JPAConfig" ))
160+ .observedType (ShutdownEvent .class )
161+ .notify (mc -> {
162+ // Essentially do the following:
163+ // Arc.container().instance( JPAConfig.class ).get().shutdown();
164+ ResultHandle arcContainer = mc .invokeStaticMethod (
165+ MethodDescriptor .ofMethod (Arc .class , "container" , ArcContainer .class ));
166+ ResultHandle jpaConfigInstance = mc .invokeInterfaceMethod (
167+ MethodDescriptor .ofMethod (ArcContainer .class , "instance" , InstanceHandle .class ,
168+ Class .class , Annotation [].class ),
169+ arcContainer ,
170+ mc .loadClassFromTCCL (JPAConfig .class ),
171+ mc .newArray (Annotation .class , 0 ));
172+ ResultHandle jpaConfig = mc .invokeInterfaceMethod (
173+ MethodDescriptor .ofMethod (InstanceHandle .class , "get" , Object .class ),
174+ jpaConfigInstance );
175+
176+ mc .invokeVirtualMethod (
177+ MethodDescriptor .ofMethod (JPAConfig .class , "shutdown" , void .class ),
178+ jpaConfig );
179+
180+ mc .returnValue (null );
181+ })));
182+ }
183+
165184 // These beans must be initialized at runtime because their initialization
166185 // depends on runtime configuration (to activate/deactivate a persistence unit)
167186 @ Record (ExecutionTime .RUNTIME_INIT )
0 commit comments