diff --git a/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/CDISEJtaPlatform.java b/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/CDISEJtaPlatform.java
index b7281067411..62288da5681 100644
--- a/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/CDISEJtaPlatform.java
+++ b/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/CDISEJtaPlatform.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2021 Oracle and/or its affiliates.
+ * Copyright (c) 2019, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,15 +15,23 @@
*/
package io.helidon.integrations.cdi.hibernate;
+import java.lang.System.Logger;
import java.util.Objects;
+import java.util.Properties;
import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
+import jakarta.persistence.spi.PersistenceUnitInfo;
import jakarta.transaction.TransactionManager;
import jakarta.transaction.UserTransaction;
import org.hibernate.engine.jndi.spi.JndiService;
import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;
+import static java.lang.System.Logger.Level.DEBUG;
+import static org.hibernate.cfg.AvailableSettings.CONNECTION_HANDLING;
+import static org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION;
+
/**
* An {@link AbstractJtaPlatform} that is an {@link ApplicationScoped}
* CDI managed bean that supplies {@link TransactionManager} and
@@ -35,74 +43,114 @@
*/
@ApplicationScoped
public class CDISEJtaPlatform extends AbstractJtaPlatform {
- private final TransactionManager transactionManager;
- private final UserTransaction userTransaction;
+ private static final Logger LOGGER = System.getLogger(CDISEJtaPlatform.class.getName());
+
+ private static final long serialVersionUID = 1L;
+
+ private transient TransactionManager transactionManager;
+
+ private transient UserTransaction userTransaction;
+
+ /**
+ * Creates a new {@link CDISEJtaPlatform}.
+ *
+ * @deprecated Required by the
+ * CDI specification and not intended for end-user use.
+ */
+ @Deprecated
+ CDISEJtaPlatform() {
+ super();
+ this.transactionManager = null;
+ this.userTransaction = null;
+ }
- private static final long serialVersionUID = 1L;
+ /**
+ * Creates a new {@link CDISEJtaPlatform}.
+ *
+ * @param transactionManager the {@link TransactionManager} to use;
+ * must not be {@code null}
+ *
+ * @param userTransaction the {@link UserTransaction} to use; must
+ * not be {@code null}
+ *
+ * @exception NullPointerException if either {@code
+ * transactionManager} or {@code userTransaction} is {@code null}
+ */
+ @Inject
+ public CDISEJtaPlatform(TransactionManager transactionManager,
+ UserTransaction userTransaction) {
+ super();
+ this.transactionManager = Objects.requireNonNull(transactionManager);
+ this.userTransaction = Objects.requireNonNull(userTransaction);
+ }
- /**
- * Creates a new {@link CDISEJtaPlatform}.
- *
- * @param transactionManager the {@link TransactionManager} to use;
- * must not be {@code null}
- *
- * @param userTransaction the {@link UserTransaction} to use; must
- * not be {@code null}
- *
- * @exception NullPointerException if either {@code
- * transactionManager} or {@code userTransaction} is {@code null}
- */
- @Inject
- public CDISEJtaPlatform(final TransactionManager transactionManager,
- final UserTransaction userTransaction) {
- super();
- this.transactionManager = Objects.requireNonNull(transactionManager);
- this.userTransaction = Objects.requireNonNull(userTransaction);
- }
+ /**
+ * Throws an {@link UnsupportedOperationException} when invoked.
+ *
+ * @return (not applicable)
+ *
+ * @exception UnsupportedOperationException when invoked
+ */
+ @Override
+ protected JndiService jndiService() {
+ throw new UnsupportedOperationException();
+ }
- /**
- * Throws an {@link UnsupportedOperationException} when invoked.
- *
- * @return (not applicable)
- *
- * @exception UnsupportedOperationException when invoked
- */
- @Override
- protected JndiService jndiService() {
- throw new UnsupportedOperationException();
- }
+ /**
+ * Returns the {@link UserTransaction} instance supplied at
+ * {@linkplain #CDISEJtaPlatform(TransactionManager,
+ * UserTransaction) construction time}.
+ *
+ *
This method never returns {@code null}.
+ *
+ * @return a non-{@code null} {@link UserTransaction}
+ *
+ * @see #CDISEJtaPlatform(TransactionManager, UserTransaction)
+ */
+ @Override
+ protected UserTransaction locateUserTransaction() {
+ return this.userTransaction;
+ }
- /**
- * Returns the {@link UserTransaction} instance supplied at
- * {@linkplain #CDISEJtaPlatform(TransactionManager,
- * UserTransaction) construction time}.
- *
- * This method never returns {@code null}.
- *
- * @return a non-{@code null} {@link UserTransaction}
- *
- * @see #CDISEJtaPlatform(TransactionManager, UserTransaction)
- */
- @Override
- protected UserTransaction locateUserTransaction() {
- return this.userTransaction;
- }
+ /**
+ * Returns the {@link TransactionManager} instance supplied at
+ * {@linkplain #CDISEJtaPlatform(TransactionManager,
+ * UserTransaction) construction time}.
+ *
+ * This method never returns {@code null}.
+ *
+ * @return a non-{@code null} {@link TransactionManager}
+ *
+ * @see #CDISEJtaPlatform(TransactionManager, UserTransaction)
+ */
+ @Override
+ protected TransactionManager locateTransactionManager() {
+ return this.transactionManager;
+ }
- /**
- * Returns the {@link TransactionManager} instance supplied at
- * {@linkplain #CDISEJtaPlatform(TransactionManager,
- * UserTransaction) construction time}.
- *
- * This method never returns {@code null}.
- *
- * @return a non-{@code null} {@link TransactionManager}
- *
- * @see #CDISEJtaPlatform(TransactionManager, UserTransaction)
- */
- @Override
- protected TransactionManager locateTransactionManager() {
- return this.transactionManager;
- }
+ /**
+ * Customizes the supplied {@link PersistenceUnitInfo}, when it is fired as a CDI event by, for example, the {@code
+ * io.helidon.integrations.cdi.jpa.PersistenceExtension} portable extension, by ensuring that certain important
+ * Hibernate properties are always set on the persistence unit.
+ *
+ * @param pui the {@link PersistenceUnitInfo} to customize; must not be {@code null}
+ *
+ * @exception NullPointerException if {@code pui} is {@code null}
+ *
+ * @see
+ * org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode#DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION
+ */
+ private static void customizePersistenceUnitInfo(@Observes PersistenceUnitInfo pui) {
+ Properties p = pui.getProperties();
+ if (p != null && p.getProperty(CONNECTION_HANDLING) == null && p.get(CONNECTION_HANDLING) == null) {
+ if (LOGGER.isLoggable(DEBUG)) {
+ LOGGER.log(DEBUG, "Setting " + CONNECTION_HANDLING + " property to "
+ + DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION
+ + " on persistence unit " + pui.getPersistenceUnitName());
+ }
+ p.setProperty(CONNECTION_HANDLING, DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION.toString());
+ }
+ }
}
diff --git a/integrations/cdi/hibernate-cdi/src/main/java/module-info.java b/integrations/cdi/hibernate-cdi/src/main/java/module-info.java
index f3a6b9b7753..d0b0ac43d11 100644
--- a/integrations/cdi/hibernate-cdi/src/main/java/module-info.java
+++ b/integrations/cdi/hibernate-cdi/src/main/java/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2021 Oracle and/or its affiliates.
+ * Copyright (c) 2020, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,12 +23,14 @@
*
* @see io.helidon.integrations.cdi.hibernate.CDISEJtaPlatform
*/
+@SuppressWarnings({"requires-automatic", "requires-transitive-automatic"})
module io.helidon.integrations.cdi.hibernate {
- requires jakarta.transaction;
- requires java.sql;
- requires jakarta.inject;
- requires jakarta.cdi;
- requires org.hibernate.orm.core;
+
+ requires transitive jakarta.cdi;
+ requires transitive jakarta.inject;
+ requires jakarta.persistence;
+ requires transitive jakarta.transaction;
+ requires transitive org.hibernate.orm.core;
exports io.helidon.integrations.cdi.hibernate;
diff --git a/integrations/cdi/jpa-cdi/src/main/java/io/helidon/integrations/cdi/jpa/PersistenceExtension.java b/integrations/cdi/jpa-cdi/src/main/java/io/helidon/integrations/cdi/jpa/PersistenceExtension.java
index 31767003a1d..33944c708e3 100644
--- a/integrations/cdi/jpa-cdi/src/main/java/io/helidon/integrations/cdi/jpa/PersistenceExtension.java
+++ b/integrations/cdi/jpa-cdi/src/main/java/io/helidon/integrations/cdi/jpa/PersistenceExtension.java
@@ -55,6 +55,7 @@
import jakarta.annotation.Priority;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.context.spi.CreationalContext;
+import jakarta.enterprise.event.Event;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.Any;
import jakarta.enterprise.inject.CreationException;
@@ -151,6 +152,9 @@ public final class PersistenceExtension implements Extension {
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
+ private static final TypeLiteral> EVENT_PERSISTENCEUNITINFOBEAN_TYPELITERAL =
+ new TypeLiteral<>() {};
+
private static final Logger LOGGER = Logger.getLogger(PersistenceExtension.class.getName());
@@ -997,7 +1001,7 @@ private void processPersistenceXmls(AfterBeanDiscovery event,
}
Supplier extends DataSourceProvider> dataSourceProviderSupplier =
() -> bm.createInstance().select(DataSourceProvider.class).get();
- PersistenceUnitInfo solePui = null;
+ PersistenceUnitInfoBean solePui = null;
Supplier extends ClassLoader> tempClassLoaderSupplier =
classLoader instanceof URLClassLoader ucl ? () -> new URLClassLoader(ucl.getURLs()) : () -> classLoader;
for (int puCount = 0; persistenceXmlUrls.hasMoreElements();) {
@@ -1032,6 +1036,7 @@ private void processPersistenceXmls(AfterBeanDiscovery event,
if (unitName == null || unitName.isBlank()) {
unitName = DEFAULT_PERSISTENCE_UNIT_NAME;
}
+ Named qualifier = NamedLiteral.of(unitName);
// Provide support for, e.g.:
// @Inject
// @Named("test")
@@ -1040,8 +1045,8 @@ private void processPersistenceXmls(AfterBeanDiscovery event,
.beanClass(PersistenceUnitInfoBean.class)
.addTransitiveTypeClosure(PersistenceUnitInfoBean.class)
.scope(Singleton.class)
- .qualifiers(NamedLiteral.of(unitName))
- .createWith(cc -> pui);
+ .qualifiers(qualifier)
+ .produceWith(i -> producePersistenceUnitInfoBean(i, pui, qualifier));
addPersistenceProviderBeanIfAbsent(event, pui, providers);
if (puCount == 0) {
solePui = pui;
@@ -1056,17 +1061,18 @@ private void processPersistenceXmls(AfterBeanDiscovery event,
assert soleUnitName != null;
assert !soleUnitName.isBlank();
if (!soleUnitName.equals(DEFAULT_PERSISTENCE_UNIT_NAME)) {
- PersistenceUnitInfo pui = solePui;
+ PersistenceUnitInfoBean pui = solePui;
// Provide support for, e.g.:
// @Inject
// @Named("__DEFAULT__"))
// private PersistenceUnitInfo persistenceUnitInfo;
+ Named qualifier = NamedLiteral.of(DEFAULT_PERSISTENCE_UNIT_NAME);
event.addBean()
.beanClass(PersistenceUnitInfoBean.class)
.addTransitiveTypeClosure(PersistenceUnitInfoBean.class)
.scope(Singleton.class)
- .qualifiers(NamedLiteral.of(DEFAULT_PERSISTENCE_UNIT_NAME))
- .createWith(cc -> pui);
+ .qualifiers(qualifier)
+ .produceWith(i -> producePersistenceUnitInfoBean(i, pui, qualifier));
}
}
}
@@ -1087,6 +1093,7 @@ private void processImplicitPersistenceUnits(AfterBeanDiscovery event, Iterable<
}
}
}
+ Named qualifier = NamedLiteral.of(unitName);
// Provide support for, e.g.:
// @Inject
// @Named("test")
@@ -1095,8 +1102,8 @@ private void processImplicitPersistenceUnits(AfterBeanDiscovery event, Iterable<
.beanClass(PersistenceUnitInfoBean.class)
.addTransitiveTypeClosure(PersistenceUnitInfoBean.class)
.scope(Singleton.class)
- .qualifiers(NamedLiteral.of(unitName))
- .createWith(cc -> pui);
+ .qualifiers(qualifier)
+ .produceWith(i -> producePersistenceUnitInfoBean(i, pui, qualifier));
addPersistenceProviderBeanIfAbsent(event, pui, providers);
if (puCount == 0) {
solePui = pui;
@@ -1112,6 +1119,7 @@ private void processImplicitPersistenceUnits(AfterBeanDiscovery event, Iterable<
assert !soleUnitName.isBlank();
if (!soleUnitName.equals(DEFAULT_PERSISTENCE_UNIT_NAME)) {
PersistenceUnitInfoBean pui = solePui;
+ Named qualifier = NamedLiteral.of(DEFAULT_PERSISTENCE_UNIT_NAME);
// Provide support for, e.g.:
// @Inject
// @Named("__DEFAULT__")
@@ -1120,8 +1128,8 @@ private void processImplicitPersistenceUnits(AfterBeanDiscovery event, Iterable<
.beanClass(PersistenceUnitInfoBean.class)
.addTransitiveTypeClosure(PersistenceUnitInfoBean.class)
.scope(Singleton.class)
- .qualifiers(NamedLiteral.of(DEFAULT_PERSISTENCE_UNIT_NAME))
- .createWith(cc -> pui);
+ .qualifiers(qualifier)
+ .produceWith(i -> producePersistenceUnitInfoBean(i, pui, qualifier));
}
}
}
@@ -1316,6 +1324,14 @@ private static void disposeJtaExtendedEntityManager(JtaExtendedEntityManager em,
containerManagedSelectionQualifiers);
}
+ private static PersistenceUnitInfoBean producePersistenceUnitInfoBean(Instance