diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 07d4a9d2f28..663a5bad3f1 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -65,7 +65,8 @@ 32.0.1-jre 2.1.212 1.3 - 6.1.7.Final + 6.1 + ${version.lib.hibernate.family}.7.Final 7.0.2.Final 5.0.1 1.5.18 diff --git a/etc/javadoc/hibernate/element-list b/etc/javadoc/hibernate/element-list new file mode 100644 index 00000000000..5cbe2e7755f --- /dev/null +++ b/etc/javadoc/hibernate/element-list @@ -0,0 +1,427 @@ +org.hibernate +org.hibernate.action.internal +org.hibernate.action.spi +org.hibernate.agroal.internal +org.hibernate.annotations +org.hibernate.boot +org.hibernate.boot.archive.internal +org.hibernate.boot.archive.scan.internal +org.hibernate.boot.archive.scan.spi +org.hibernate.boot.archive.spi +org.hibernate.boot.cfgxml.internal +org.hibernate.boot.cfgxml.spi +org.hibernate.boot.internal +org.hibernate.boot.jaxb +org.hibernate.boot.jaxb.cfg.spi +org.hibernate.boot.jaxb.hbm.internal +org.hibernate.boot.jaxb.hbm.spi +org.hibernate.boot.jaxb.hbm.transform +org.hibernate.boot.jaxb.internal +org.hibernate.boot.jaxb.internal.stax +org.hibernate.boot.jaxb.mapping +org.hibernate.boot.jaxb.mapping.marshall +org.hibernate.boot.jaxb.spi +org.hibernate.boot.model +org.hibernate.boot.model.convert.internal +org.hibernate.boot.model.convert.spi +org.hibernate.boot.model.naming +org.hibernate.boot.model.process.internal +org.hibernate.boot.model.process.spi +org.hibernate.boot.model.relational +org.hibernate.boot.model.relational.internal +org.hibernate.boot.model.source.internal +org.hibernate.boot.model.source.internal.annotations +org.hibernate.boot.model.source.internal.hbm +org.hibernate.boot.model.source.spi +org.hibernate.boot.query +org.hibernate.boot.registry +org.hibernate.boot.registry.classloading.internal +org.hibernate.boot.registry.classloading.spi +org.hibernate.boot.registry.internal +org.hibernate.boot.registry.selector +org.hibernate.boot.registry.selector.internal +org.hibernate.boot.registry.selector.spi +org.hibernate.boot.spi +org.hibernate.boot.xsd +org.hibernate.bytecode +org.hibernate.bytecode.enhance.internal.bytebuddy +org.hibernate.bytecode.enhance.internal.tracker +org.hibernate.bytecode.enhance.spi +org.hibernate.bytecode.enhance.spi.interceptor +org.hibernate.bytecode.internal +org.hibernate.bytecode.internal.bytebuddy +org.hibernate.bytecode.internal.none +org.hibernate.bytecode.spi +org.hibernate.c3p0.internal +org.hibernate.cache +org.hibernate.cache.cfg.internal +org.hibernate.cache.cfg.spi +org.hibernate.cache.internal +org.hibernate.cache.jcache +org.hibernate.cache.jcache.internal +org.hibernate.cache.spi +org.hibernate.cache.spi.access +org.hibernate.cache.spi.entry +org.hibernate.cache.spi.support +org.hibernate.cfg +org.hibernate.cfg.annotations +org.hibernate.cfg.annotations.reflection +org.hibernate.cfg.annotations.reflection.internal +org.hibernate.cfg.beanvalidation +org.hibernate.cfg.internal +org.hibernate.classic +org.hibernate.collection.internal +org.hibernate.collection.spi +org.hibernate.context +org.hibernate.context.internal +org.hibernate.context.spi +org.hibernate.dialect +org.hibernate.dialect.function +org.hibernate.dialect.hint +org.hibernate.dialect.identity +org.hibernate.dialect.lock +org.hibernate.dialect.pagination +org.hibernate.dialect.sequence +org.hibernate.dialect.temptable +org.hibernate.dialect.unique +org.hibernate.engine +org.hibernate.engine.config.internal +org.hibernate.engine.config.spi +org.hibernate.engine.internal +org.hibernate.engine.jdbc +org.hibernate.engine.jdbc.batch.internal +org.hibernate.engine.jdbc.batch.spi +org.hibernate.engine.jdbc.connections.internal +org.hibernate.engine.jdbc.connections.spi +org.hibernate.engine.jdbc.cursor.internal +org.hibernate.engine.jdbc.cursor.spi +org.hibernate.engine.jdbc.dialect.internal +org.hibernate.engine.jdbc.dialect.spi +org.hibernate.engine.jdbc.env.internal +org.hibernate.engine.jdbc.env.spi +org.hibernate.engine.jdbc.internal +org.hibernate.engine.jdbc.spi +org.hibernate.engine.jndi +org.hibernate.engine.jndi.internal +org.hibernate.engine.jndi.spi +org.hibernate.engine.profile +org.hibernate.engine.query +org.hibernate.engine.query.internal +org.hibernate.engine.query.spi +org.hibernate.engine.spi +org.hibernate.engine.transaction.internal +org.hibernate.engine.transaction.internal.jta +org.hibernate.engine.transaction.jta.platform.internal +org.hibernate.engine.transaction.jta.platform.spi +org.hibernate.engine.transaction.spi +org.hibernate.envers +org.hibernate.envers.boot +org.hibernate.envers.boot.internal +org.hibernate.envers.boot.model +org.hibernate.envers.boot.registry.classloading +org.hibernate.envers.boot.spi +org.hibernate.envers.configuration +org.hibernate.envers.configuration.internal +org.hibernate.envers.configuration.internal.metadata +org.hibernate.envers.configuration.internal.metadata.reader +org.hibernate.envers.enhanced +org.hibernate.envers.event.spi +org.hibernate.envers.exception +org.hibernate.envers.function +org.hibernate.envers.internal +org.hibernate.envers.internal.entities +org.hibernate.envers.internal.entities.mapper +org.hibernate.envers.internal.entities.mapper.id +org.hibernate.envers.internal.entities.mapper.relation +org.hibernate.envers.internal.entities.mapper.relation.component +org.hibernate.envers.internal.entities.mapper.relation.lazy +org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor +org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy +org.hibernate.envers.internal.entities.mapper.relation.query +org.hibernate.envers.internal.reader +org.hibernate.envers.internal.revisioninfo +org.hibernate.envers.internal.synchronization +org.hibernate.envers.internal.synchronization.work +org.hibernate.envers.internal.tools +org.hibernate.envers.internal.tools.graph +org.hibernate.envers.internal.tools.query +org.hibernate.envers.query +org.hibernate.envers.query.criteria +org.hibernate.envers.query.criteria.internal +org.hibernate.envers.query.internal.impl +org.hibernate.envers.query.internal.property +org.hibernate.envers.query.order +org.hibernate.envers.query.order.internal +org.hibernate.envers.query.projection +org.hibernate.envers.query.projection.internal +org.hibernate.envers.strategy +org.hibernate.envers.strategy.internal +org.hibernate.envers.strategy.spi +org.hibernate.envers.tools +org.hibernate.event.internal +org.hibernate.event.service.internal +org.hibernate.event.service.spi +org.hibernate.event.spi +org.hibernate.exception +org.hibernate.exception.internal +org.hibernate.exception.spi +org.hibernate.grammars.graph +org.hibernate.grammars.hql +org.hibernate.grammars.importsql +org.hibernate.grammars.ordering +org.hibernate.graph +org.hibernate.graph.internal +org.hibernate.graph.internal.parse +org.hibernate.graph.spi +org.hibernate.hikaricp.internal +org.hibernate.id +org.hibernate.id.enhanced +org.hibernate.id.factory +org.hibernate.id.factory.internal +org.hibernate.id.factory.spi +org.hibernate.id.insert +org.hibernate.id.uuid +org.hibernate.integrator.internal +org.hibernate.integrator.spi +org.hibernate.internal +org.hibernate.internal.build +org.hibernate.internal.log +org.hibernate.internal.util +org.hibernate.internal.util.beans +org.hibernate.internal.util.collections +org.hibernate.internal.util.compare +org.hibernate.internal.util.config +org.hibernate.internal.util.io +org.hibernate.internal.util.securitymanager +org.hibernate.internal.util.type +org.hibernate.internal.util.xml +org.hibernate.jdbc +org.hibernate.jpa +org.hibernate.jpa.boot.internal +org.hibernate.jpa.boot.spi +org.hibernate.jpa.event.internal +org.hibernate.jpa.event.spi +org.hibernate.jpa.internal +org.hibernate.jpa.internal.enhance +org.hibernate.jpa.internal.util +org.hibernate.jpa.spi +org.hibernate.jpamodelgen +org.hibernate.jpamodelgen.annotation +org.hibernate.jpamodelgen.model +org.hibernate.jpamodelgen.util +org.hibernate.jpamodelgen.util.xml +org.hibernate.jpamodelgen.xml +org.hibernate.jpamodelgen.xml.jaxb +org.hibernate.loader +org.hibernate.loader.access +org.hibernate.loader.ast.internal +org.hibernate.loader.ast.spi +org.hibernate.loader.entity +org.hibernate.loader.internal +org.hibernate.mapping +org.hibernate.metadata +org.hibernate.metamodel +org.hibernate.metamodel.internal +org.hibernate.metamodel.mapping +org.hibernate.metamodel.mapping.internal +org.hibernate.metamodel.mapping.ordering +org.hibernate.metamodel.mapping.ordering.ast +org.hibernate.metamodel.model.convert.internal +org.hibernate.metamodel.model.convert.spi +org.hibernate.metamodel.model.domain +org.hibernate.metamodel.model.domain.internal +org.hibernate.metamodel.model.domain.spi +org.hibernate.metamodel.relational +org.hibernate.metamodel.spi +org.hibernate.persister.collection +org.hibernate.persister.entity +org.hibernate.persister.internal +org.hibernate.persister.spi +org.hibernate.persister.walking.spi +org.hibernate.pretty +org.hibernate.procedure +org.hibernate.procedure.internal +org.hibernate.procedure.spi +org.hibernate.property.access.internal +org.hibernate.property.access.spi +org.hibernate.proxool.internal +org.hibernate.proxy +org.hibernate.proxy.map +org.hibernate.proxy.pojo +org.hibernate.proxy.pojo.bytebuddy +org.hibernate.query +org.hibernate.query.criteria +org.hibernate.query.criteria.internal +org.hibernate.query.derived +org.hibernate.query.hql +org.hibernate.query.hql.internal +org.hibernate.query.hql.spi +org.hibernate.query.internal +org.hibernate.query.named +org.hibernate.query.procedure +org.hibernate.query.results +org.hibernate.query.results.complete +org.hibernate.query.results.dynamic +org.hibernate.query.results.implicit +org.hibernate.query.spi +org.hibernate.query.sql +org.hibernate.query.sql.internal +org.hibernate.query.sql.spi +org.hibernate.query.sqm +org.hibernate.query.sqm.function +org.hibernate.query.sqm.internal +org.hibernate.query.sqm.mutation.internal +org.hibernate.query.sqm.mutation.internal.cte +org.hibernate.query.sqm.mutation.internal.inline +org.hibernate.query.sqm.mutation.internal.temptable +org.hibernate.query.sqm.mutation.spi +org.hibernate.query.sqm.produce.function +org.hibernate.query.sqm.produce.function.internal +org.hibernate.query.sqm.spi +org.hibernate.query.sqm.sql +org.hibernate.query.sqm.sql.internal +org.hibernate.query.sqm.tree +org.hibernate.query.sqm.tree.cte +org.hibernate.query.sqm.tree.delete +org.hibernate.query.sqm.tree.domain +org.hibernate.query.sqm.tree.expression +org.hibernate.query.sqm.tree.from +org.hibernate.query.sqm.tree.insert +org.hibernate.query.sqm.tree.jpa +org.hibernate.query.sqm.tree.predicate +org.hibernate.query.sqm.tree.select +org.hibernate.query.sqm.tree.update +org.hibernate.resource.beans.container.internal +org.hibernate.resource.beans.container.spi +org.hibernate.resource.beans.internal +org.hibernate.resource.beans.spi +org.hibernate.resource.jdbc +org.hibernate.resource.jdbc.internal +org.hibernate.resource.jdbc.spi +org.hibernate.resource.transaction +org.hibernate.resource.transaction.backend.jdbc.internal +org.hibernate.resource.transaction.backend.jdbc.spi +org.hibernate.resource.transaction.backend.jta.internal +org.hibernate.resource.transaction.backend.jta.internal.synchronization +org.hibernate.resource.transaction.internal +org.hibernate.resource.transaction.spi +org.hibernate.result +org.hibernate.result.internal +org.hibernate.result.spi +org.hibernate.service +org.hibernate.service.internal +org.hibernate.service.spi +org.hibernate.spatial +org.hibernate.spatial.contributor +org.hibernate.spatial.dialect.cockroachdb +org.hibernate.spatial.dialect.db2 +org.hibernate.spatial.dialect.h2gis +org.hibernate.spatial.dialect.hana +org.hibernate.spatial.dialect.mariadb +org.hibernate.spatial.dialect.mysql +org.hibernate.spatial.dialect.oracle +org.hibernate.spatial.dialect.postgis +org.hibernate.spatial.dialect.sqlserver +org.hibernate.spatial.integration +org.hibernate.spatial.jts +org.hibernate.spatial.predicate +org.hibernate.spi +org.hibernate.sql +org.hibernate.sql.ast +org.hibernate.sql.ast.spi +org.hibernate.sql.ast.tree +org.hibernate.sql.ast.tree.cte +org.hibernate.sql.ast.tree.delete +org.hibernate.sql.ast.tree.expression +org.hibernate.sql.ast.tree.from +org.hibernate.sql.ast.tree.insert +org.hibernate.sql.ast.tree.predicate +org.hibernate.sql.ast.tree.select +org.hibernate.sql.ast.tree.update +org.hibernate.sql.exec +org.hibernate.sql.exec.internal +org.hibernate.sql.exec.spi +org.hibernate.sql.results +org.hibernate.sql.results.caching +org.hibernate.sql.results.caching.internal +org.hibernate.sql.results.graph +org.hibernate.sql.results.graph.basic +org.hibernate.sql.results.graph.collection +org.hibernate.sql.results.graph.collection.internal +org.hibernate.sql.results.graph.embeddable +org.hibernate.sql.results.graph.embeddable.internal +org.hibernate.sql.results.graph.entity +org.hibernate.sql.results.graph.entity.internal +org.hibernate.sql.results.graph.instantiation +org.hibernate.sql.results.graph.instantiation.internal +org.hibernate.sql.results.graph.tuple +org.hibernate.sql.results.internal +org.hibernate.sql.results.internal.domain +org.hibernate.sql.results.jdbc.internal +org.hibernate.sql.results.jdbc.spi +org.hibernate.sql.results.spi +org.hibernate.stat +org.hibernate.stat.internal +org.hibernate.stat.spi +org.hibernate.testing +org.hibernate.testing.async +org.hibernate.testing.boot +org.hibernate.testing.bytecode.enhancement +org.hibernate.testing.byteman +org.hibernate.testing.cache +org.hibernate.testing.cleaner +org.hibernate.testing.common.connections +org.hibernate.testing.env +org.hibernate.testing.hamcrest +org.hibernate.testing.jdbc +org.hibernate.testing.jdbc.leak +org.hibernate.testing.jta +org.hibernate.testing.junit4 +org.hibernate.testing.logger +org.hibernate.testing.orm +org.hibernate.testing.orm.assertj +org.hibernate.testing.orm.domain +org.hibernate.testing.orm.domain.animal +org.hibernate.testing.orm.domain.contacts +org.hibernate.testing.orm.domain.gambit +org.hibernate.testing.orm.domain.helpdesk +org.hibernate.testing.orm.domain.retail +org.hibernate.testing.orm.jdbc +org.hibernate.testing.orm.jpa +org.hibernate.testing.orm.junit +org.hibernate.testing.orm.logger +org.hibernate.testing.orm.transaction +org.hibernate.testing.schema +org.hibernate.testing.transaction +org.hibernate.testing.util +org.hibernate.testing.util.jpa +org.hibernate.tool.schema +org.hibernate.tool.schema.extract.internal +org.hibernate.tool.schema.extract.spi +org.hibernate.tool.schema.internal +org.hibernate.tool.schema.internal.exec +org.hibernate.tool.schema.internal.script +org.hibernate.tool.schema.spi +org.hibernate.transform +org.hibernate.tuple +org.hibernate.tuple.component +org.hibernate.tuple.entity +org.hibernate.type +org.hibernate.type.descriptor +org.hibernate.type.descriptor.converter +org.hibernate.type.descriptor.java +org.hibernate.type.descriptor.java.spi +org.hibernate.type.descriptor.jdbc +org.hibernate.type.descriptor.jdbc.internal +org.hibernate.type.descriptor.jdbc.spi +org.hibernate.type.descriptor.sql +org.hibernate.type.descriptor.sql.internal +org.hibernate.type.descriptor.sql.spi +org.hibernate.type.internal +org.hibernate.type.jackson +org.hibernate.type.jakartajson +org.hibernate.type.jaxb +org.hibernate.type.spi +org.hibernate.usertype +org.hibernate.usertype.internal +org.hibernate.vibur.internal diff --git a/integrations/cdi/hibernate-cdi/etc/spotbugs/exclude.xml b/integrations/cdi/hibernate-cdi/etc/spotbugs/exclude.xml new file mode 100644 index 00000000000..93a8fe1988f --- /dev/null +++ b/integrations/cdi/hibernate-cdi/etc/spotbugs/exclude.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + diff --git a/integrations/cdi/hibernate-cdi/pom.xml b/integrations/cdi/hibernate-cdi/pom.xml index be3ed41e32f..27b1ee5945c 100644 --- a/integrations/cdi/hibernate-cdi/pom.xml +++ b/integrations/cdi/hibernate-cdi/pom.xml @@ -29,6 +29,10 @@ helidon-integrations-cdi-hibernate Helidon CDI Integrations Hibernate + + etc/spotbugs/exclude.xml + + @@ -36,6 +40,11 @@ junit-jupiter-api test + + com.h2database + h2 + test + org.hamcrest hamcrest-all diff --git a/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/CDISEJtaPlatformProvider.java b/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/CDISEJtaPlatformProvider.java index 18d209c65ba..3e84250cd80 100644 --- a/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/CDISEJtaPlatformProvider.java +++ b/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/CDISEJtaPlatformProvider.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,38 +15,84 @@ */ package io.helidon.integrations.cdi.hibernate; +import java.lang.System.Logger; + import jakarta.enterprise.inject.spi.CDI; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformProvider; +import static java.lang.System.Logger.Level.WARNING; + /** - * A {@link JtaPlatformProvider} that uses a {@link CDI} instance to - * {@linkplain CDI#select(Class, java.lang.annotation.Annotation...) provide} a {@link - * JtaPlatform}. + * A {@link JtaPlatformProvider} that uses a {@link CDI} instance to {@linkplain CDI#select(Class, + * java.lang.annotation.Annotation...) provide} a {@link JtaPlatform}. * - *

Normally this class is instantiated by the {@linkplain - * java.util.ServiceLoader Java service provider infrastructure}.

+ *

Normally this class is instantiated by the {@linkplain java.util.ServiceLoader Java service provider + * infrastructure}.

* * @see JtaPlatform * * @see CDISEJtaPlatform */ public final class CDISEJtaPlatformProvider implements JtaPlatformProvider { - /** - * Creates a new {@link CDISEJtaPlatformProvider}. - */ - public CDISEJtaPlatformProvider() { - super(); - } - - /** - * Returns a non-{@code null} {@link JtaPlatform}. - * - * @return a non-{@code null} {@link JtaPlatform} - */ - @Override - public JtaPlatform getProvidedJtaPlatform() { - return CDI.current().select(JtaPlatform.class).get(); - } + + + /* + * Static fields. + */ + + + /** + * A {@link Logger} for instances of this class. + */ + private static final Logger LOGGER = System.getLogger(CDISEJtaPlatformProvider.class.getName()); + + + /* + * Constructors. + */ + + + /** + * Creates a new {@link CDISEJtaPlatformProvider}. + * + * @deprecated For Hibernate use only. + */ + @Deprecated + public CDISEJtaPlatformProvider() { + super(); + } + + + /* + * Instance methods. + */ + + + /** + * Returns a {@link JtaPlatform}. + * + *

If CDI is not available, this method returns {@code null} as + * permitted by Hibernate in violation of its own contract documentation.

+ * + * @return a {@link JtaPlatform}, or {@code null} + * + * @deprecated For Hibernate use only. + */ + @Deprecated + @Override + public JtaPlatform getProvidedJtaPlatform() { + CDI cdi; + try { + cdi = CDI.current(); + } catch (IllegalStateException e) { + if (LOGGER.isLoggable(WARNING)) { + LOGGER.log(WARNING, "CDI is not available.", e); + } + return null; + } + return cdi.select(JtaPlatform.class).get(); + } } diff --git a/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/DataSourceBackedDialectFactory.java b/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/DataSourceBackedDialectFactory.java new file mode 100644 index 00000000000..bf649800c8b --- /dev/null +++ b/integrations/cdi/hibernate-cdi/src/main/java/io/helidon/integrations/cdi/hibernate/DataSourceBackedDialectFactory.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.integrations.cdi.hibernate; + +import java.lang.System.Logger; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.util.Map; + +import javax.sql.DataSource; + +import org.hibernate.boot.registry.StandardServiceInitiator; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl; +import org.hibernate.engine.jdbc.dialect.spi.BasicSQLExceptionConverter; +import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter; +import org.hibernate.engine.jdbc.dialect.spi.DialectFactory; +import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; +import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfoSource; +import org.hibernate.service.spi.ServiceContributor; +import org.hibernate.service.spi.ServiceRegistryImplementor; + +import static java.lang.System.Logger.Level.WARNING; + +/** + * A {@link DialectFactory} implementation (and a {@link ServiceContributor}, and a {@link StandardServiceInitiator + * StandardServiceInitiator<DialectFactory>}) that introspects {@link DatabaseMetaData} from a configured {@link + * DataSource}. + * + *

Hibernate is guaranteed to perform each of the following invocations, once, ever, in order:

+ * + *
    + * + *
  1. (The {@linkplain #DataSourceBackedDialectFactory() zero-argument constructor})
  2. + * + *
  3. The {@link #contribute(StandardServiceRegistryBuilder)} method
  4. + * + *
  5. The {@link #initiateService(Map, ServiceRegistryImplementor)} method (if applicable)
  6. + * + *
+ * + *

Then, at application runtime, after the sole instance of this class has been installed following the protocol + * above, Hibernate will call the {@link #buildDialect(Map, DialectResolutionInfoSource)} method as appropriate.

+ * + * @see #contribute(StandardServiceRegistryBuilder) + * + * @see #initiateService(Map, ServiceRegistryImplementor) + * + * @see #buildDialect(Map, DialectResolutionInfoSource) + * + * @see Custom {@code Service} Implementations (overriding) in the Hibernate Integration Guide + */ +public final class DataSourceBackedDialectFactory + implements DialectFactory, ServiceContributor, StandardServiceInitiator { + + + /* + * Static fields. + */ + + + /** + * A {@link Logger} for instances of this class. + * + * @see Logger + */ + private static final Logger LOGGER = System.getLogger(DataSourceBackedDialectFactory.class.getName()); + + + /** + * A version identifier for {@linkplain java.io.Serializable serialization} purposes. + */ + private static final long serialVersionUID = 1L; + + + /* + * Instance fields. + */ + + + /** + * An instance of Hibernate's standard {@link DialectFactory} implementation ({@link DialectFactoryImpl}) to which + * all "real work" is delegated. + * + *

This field is set once, ever, to a non-{@code null} value, by the {@link #initiateService(Map, + * ServiceRegistryImplementor)} method, which Hibernate calls as part of its bootstrap protocol.

+ * + * @see #initiateService(Map, ServiceRegistryImplementor) + * + * @see StandardServiceInitiator#initiateService(Map, ServiceRegistryImplementor) + * + * @see DialectFactoryImpl#buildDialect(Map, DialectResolutionInfoSource) + */ + private DialectFactoryImpl dfi; + + + /* + * Constructors. + */ + + + /** + * Creates a new {@link DataSourceBackedDialectFactory}. + * + * @deprecated For use by {@link java.util.ServiceLoader} instances only. + */ + @Deprecated + public DataSourceBackedDialectFactory() { + super(); + } + + + /* + * Instance methods. + */ + + + /** + * Retrieves the {@link DataSource} stored in the supplied {@link Map} under the {@link + * AvailableSettings#JAKARTA_JTA_DATASOURCE} key, and uses it to ultimately acquire a {@link DatabaseMetaData} instance + * to adapt into a {@link DialectResolutionInfo} instance, such that a {@link DialectResolutionInfoSource} can be + * constructed, in the case where the supplied {@code dialectResolutionInfoSource} is {@code null}, and passes the + * resulting {@link DialectResolutionInfoSource} to the {@linkplain DialectFactoryImpl#buildDialect(Map, + * DialectResolutionInfoSource) standard DialectFactory that Hibernate uses by default}, such that + * Hibernate can determine what {@link Dialect} to use when database connectivity is established via a {@code + * META-INF/persistence.xml}'s {@code jta-data-source} element. + * + * @param settings a {@link Map} containing the settings returned by an invocation of the {@link + * StandardServiceRegistryBuilder#getSettings()} method; must not be {@code null} + * + * @param dialectResolutionInfoSource a {@link DialectResolutionInfoSource} supplied by Hibernate; may be, and often + * is, {@code null} + * + * @return a {@link Dialect}; never {@code null} + * + * @exception NullPointerException if {@code settings} is {@code null} + * + * @exception org.hibernate.HibernateException if a {@link Dialect} could not be constructed + * + * @see DialectFactoryImpl#buildDialect(Map, DialectResolutionInfoSource) + * + * @see AvailableSettings#JAKARTA_JTA_DATASOURCE + * + * @see DatabaseMetaDataDialectResolutionInfoAdapter + * + * @deprecated For Hibernate use only. + */ + @Deprecated + @Override // DialectFactory + public Dialect buildDialect(Map settings, DialectResolutionInfoSource dialectResolutionInfoSource) { + if (dialectResolutionInfoSource == null) { + DataSource ds = getDataSource(settings); + if (ds != null) { + DatabaseMetaData dmd; + try (Connection c = ds.getConnection()) { + dmd = c.getMetaData(); + } catch (SQLException e) { + throw BasicSQLExceptionConverter.INSTANCE.convert(e); + } + DialectResolutionInfo dri = new DatabaseMetaDataDialectResolutionInfoAdapter(dmd); + dialectResolutionInfoSource = () -> dri; + } + } + // No null check needed for this.dfi because it is guaranteed to have been set by the initiateService(Map, + // ServiceRegistryImplementor) method (q.v.). + return this.dfi.buildDialect(settings, dialectResolutionInfoSource); + } + + /** + * {@linkplain StandardServiceRegistryBuilder#addInitiator(StandardServiceInitiator) Contributes} this {@link + * DataSourceBackedDialectFactory} as a {@link StandardServiceInitiator + * StandardServiceInitiator<DialectFactory>} if and only if certain requirements are met. + * + *

This method will call {@link StandardServiceRegistryBuilder#addInitiator(StandardServiceInitiator) + * standardServiceRegistryBuilder.addInitiator(this)} if and only if all of the following preconditions hold:

+ * + *
    + * + *
  • {@code settings.get(}{@link AvailableSettings#DIALECT DIALECT}{@code )} returns an object that is either {@code + * null} or a {@linkplain String#isBlank() blank} {@link String}
  • + * + *
  • {@code settings.get(}{@link AvailableSettings#JAKARTA_JTA_DATASOURCE JAKARTA_JTA_DATASOURCE}{@code )} returns a + * non-{@code null} {@link DataSource}
  • + * + *
+ * + *

If any other state of affairs holds, this method takes no action.

+ * + * @param standardServiceRegistryBuilder a {@link StandardServiceRegistryBuilder} whose {@link + * StandardServiceRegistryBuilder#addInitiator(StandardServiceInitiator)} may be called with {@code this} as its + * sole argument; must not be {@code null} + * + * @deprecated For Hibernate use only. + */ + @Deprecated + @Override // ServiceContributor + public void contribute(StandardServiceRegistryBuilder standardServiceRegistryBuilder) { + Map settings = standardServiceRegistryBuilder.getSettings(); + Object dialect = settings.get(AvailableSettings.DIALECT); + if ((dialect == null || dialect instanceof String dialectString && dialectString.isBlank()) + && getDataSource(settings) != null) { + standardServiceRegistryBuilder.addInitiator(this); + } + } + + /** + * Returns {@link Class Class<DialectFactory>} when invoked, thus describing the type of service the {@link + * #initiateService(Map, ServiceRegistryImplementor)} will initiate. + * + * @return {@link Class Class<DialectFactory>} when invoked + * + * @see StandardServiceInitiator#getServiceInitiated() + * + * @deprecated For Hibernate use only. + */ + @Deprecated + @Override // StandardServiceInitiator + public Class getServiceInitiated() { + return DialectFactory.class; + } + + /** + * Returns {@code this} when invoked. + * + * @param settings ignored + * + * @param serviceRegistry a {@link ServiceRegistryImplementor} supplied by Hibernate + * + * @return {@code this} when invoked + * + * @deprecated For Hibernate use only. + */ + @Deprecated + @Override // StandardServiceInitiator + public DataSourceBackedDialectFactory initiateService(Map settings, + ServiceRegistryImplementor serviceRegistry) { + // This method is kind of like a @PostConstruct method. The initiateService(Map, ServiceRegistryImplementor) + // method is called only once, ever, by Hibernate, in a guaranteed bootstrap protocol. Consequently this is the + // only place where the dfi instance field will ever be set. No null check for this.dfi is therefore needed in + // the buildDialect(Map, DialectResolutionInfoSource) method. + // + // Additionally, ServiceInitiators are not required to be thread-safe, so the dfi instance variable is not, and + // need not be, volatile. + this.dfi = new DialectFactoryImpl(); + this.dfi.injectServices(serviceRegistry); + return this; + } + + + /* + * Static methods. + */ + + + /** + * Retrieves the value indexed under the {@link AvailableSettings#JAKARTA_JTA_DATASOURCE} key, and, if and only if it is + * a {@link DataSource}, returns it. + * + * @param settings a {@link Map} containing the settings returned by an invocation of the {@link + * StandardServiceRegistryBuilder#getSettings()} method; must not be {@code null} + * + * @return a {@link DataSource}, or {@code null} + * + * @exception NullPointerException if {@code settings} is {@code null} + */ + private static DataSource getDataSource(Map settings) { + Object ds = settings.get(AvailableSettings.JAKARTA_JTA_DATASOURCE); + if (!(ds instanceof DataSource)) { + if (LOGGER.isLoggable(WARNING)) { + LOGGER.log(WARNING, "No DataSource found under key " + AvailableSettings.JAKARTA_JTA_DATASOURCE); + } + return null; + } + return (DataSource) ds; + } + +} 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 d0b0ac43d11..bcb12537478 100644 --- a/integrations/cdi/hibernate-cdi/src/main/java/module-info.java +++ b/integrations/cdi/hibernate-cdi/src/main/java/module-info.java @@ -26,6 +26,7 @@ @SuppressWarnings({"requires-automatic", "requires-transitive-automatic"}) module io.helidon.integrations.cdi.hibernate { + requires static java.naming; // or tests (representing usage) cannot run requires transitive jakarta.cdi; requires transitive jakarta.inject; requires jakarta.persistence; @@ -34,6 +35,9 @@ exports io.helidon.integrations.cdi.hibernate; + provides org.hibernate.service.spi.ServiceContributor + with io.helidon.integrations.cdi.hibernate.DataSourceBackedDialectFactory; + provides org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformProvider with io.helidon.integrations.cdi.hibernate.CDISEJtaPlatformProvider; } diff --git a/integrations/cdi/hibernate-cdi/src/test/java/io/helidon/integrations/cdi/hibernate/TestDialectDetection.java b/integrations/cdi/hibernate-cdi/src/test/java/io/helidon/integrations/cdi/hibernate/TestDialectDetection.java new file mode 100644 index 00000000000..84fc7dda5a4 --- /dev/null +++ b/integrations/cdi/hibernate-cdi/src/test/java/io/helidon/integrations/cdi/hibernate/TestDialectDetection.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.integrations.cdi.hibernate; + +import java.net.URL; +import java.util.List; +import java.util.Properties; + +import javax.sql.DataSource; + +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.SharedCacheMode; +import jakarta.persistence.ValidationMode; +import jakarta.persistence.spi.ClassTransformer; +import jakarta.persistence.spi.PersistenceProvider; +import jakarta.persistence.spi.PersistenceProviderResolverHolder; +import jakarta.persistence.spi.PersistenceUnitInfo; +import jakarta.persistence.spi.PersistenceUnitTransactionType; + +import org.h2.jdbcx.JdbcDataSource; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.engine.jdbc.dialect.spi.DialectFactory; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.junit.jupiter.api.Test; + +import static jakarta.persistence.spi.PersistenceProviderResolverHolder.getPersistenceProviderResolver; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; + +final class TestDialectDetection { + + TestDialectDetection() { + super(); + } + + @Test + void testDialectDetection() { + PersistenceProvider pp = getPersistenceProviderResolver().getPersistenceProviders().get(0); + RuntimeException re = null; + EntityManagerFactory emf = pp.createContainerEntityManagerFactory(new PUI(), null); + try { + SessionFactoryImplementor sfi = emf.unwrap(SessionFactoryImplementor.class); + assertThat(sfi.getServiceRegistry().getService(DialectFactory.class), instanceOf(DataSourceBackedDialectFactory.class)); + assertThat(sfi.getJdbcServices().getDialect(), instanceOf(H2Dialect.class)); + } catch (RuntimeException e) { + re = e; + } finally { + try { + emf.close(); + } catch (IllegalStateException e) { + if (re == null) { + re = e; + } else { + re.addSuppressed(e); + } + } + } + if (re != null) { + throw re; + } + } + + private static class PUI implements PersistenceUnitInfo { + + private final Properties properties; + + private final JdbcDataSource dataSource; + + private PUI() { + super(); + this.properties = new Properties(); + this.dataSource = new JdbcDataSource(); + this.dataSource.setURL("jdbc:h2:mem:" + this.getClass().getName()); + this.dataSource.setUser("sa"); + this.dataSource.setPassword("sa"); + } + + @Override + public void addTransformer(ClassTransformer ignored) { + + } + + @Override + public boolean excludeUnlistedClasses() { + return true; + } + + @Override + public ClassLoader getClassLoader() { + return Thread.currentThread().getContextClassLoader(); + } + + @Override + public List getJarFileUrls() { + return List.of(); + } + + @Override + public DataSource getJtaDataSource() { + return this.dataSource; + } + + @Override + public List getManagedClassNames() { + return List.of(); + } + + @Override + public List getMappingFileNames() { + return List.of(); + } + + @Override + public ClassLoader getNewTempClassLoader() { + return this.getClassLoader(); + } + + @Override + public DataSource getNonJtaDataSource() { + return this.dataSource; + } + + @Override + public String getPersistenceProviderClassName() { + return null; + } + + @Override + public String getPersistenceUnitName() { + return "TestDialectDetection"; + } + + @Override + public URL getPersistenceUnitRootUrl() { + return null; + } + + @Override + public String getPersistenceXMLSchemaVersion() { + return "3.1"; + } + + @Override + public Properties getProperties() { + return this.properties; + } + + @Override + public SharedCacheMode getSharedCacheMode() { + return SharedCacheMode.UNSPECIFIED; + } + + @Override + public PersistenceUnitTransactionType getTransactionType() { + return PersistenceUnitTransactionType.RESOURCE_LOCAL; + } + + @Override + public ValidationMode getValidationMode() { + return ValidationMode.NONE; + } + + } + +} diff --git a/pom.xml b/pom.xml index 03488811909..33c4ef20d84 100644 --- a/pom.xml +++ b/pom.xml @@ -156,6 +156,7 @@ https://docs.jboss.org/weld/javadoc/3.0/weld-spi/ http://narayana.io/docs/api/ https://www.eclipse.org/eclipselink/api/3.0/ + https://docs.jboss.org/hibernate/orm/${version.lib.hibernate.family}/javadocs/ 2.12 https://fasterxml.github.io/jackson-annotations/javadoc/${javadoc.jackson.version}/ @@ -386,6 +387,10 @@ ${javadoc.link.eclipselink} ${javadoc.packagelist.dir}/eclipselink + + ${javadoc.link.hibernate} + ${javadoc.packagelist.dir}/hibernate + -J-Dhttp.agent=maven-javadoc-plugin