diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index 46d06f132d..cff9ecdec7 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -87,43 +87,43 @@ jar { attributes( 'Main-Class': 'org.hibernate.Version', - // BND Plugin instructions (for OSGi): - 'Import-Package': [ - 'javax.security.auth;resolution:=optional', - // Make javax.security.jacc optional and do not reference a version range (because that's what we used to do) - 'javax.security.jacc;resolution:=optional;version=!', - // Make javax.validation optional and do not reference a version range (because that's what we used to do) - 'javax.validation;resolution:=optional;version=!', - 'javax.validation.constraints;resolution:=optional;version=!', - 'javax.validation.groups;resolution:=optional;version=!', - 'javax.validation.metadata;resolution:=optional;version=!', - // Make javax.enterprise optional and do not reference a version range (because that's what we used to do) - '!javax.enterprise*', - 'javax.enterprise.context.spi;resolution:=optional;version=!', - 'javax.enterprise.inject.spi;resolution:=optional;version=!', - // For JPA, we don't want to target the automatically generated range, but a specific version - "javax.persistence;version=\"${project.jpaVersion.osgiName}\"", - // optionals - 'jakarta.persistence.spi;resolution:=optional', - 'javax.management;resolution:=optional', - 'javax.naming.event;resolution:=optional', - 'javax.naming.spi;resolution:=optional', - 'org.apache.tools.ant;resolution:=optional', - 'org.apache.tools.ant.taskdefs;resolution:=optional', - 'org.apache.tools.ant.types;resolution:=optional', - 'javax.inject;resolution:=optional', - 'net.bytebuddy.*;resolution:=optional', - 'org.objectweb.jonas_tm;resolution:=optional', - 'com.ibm.websphere.jtaextensions;resolution:=optional', - // We must specify the version explicitly to allow Karaf - // to use an older version of JAXB (the only one we can use in Karaf) - "javax.xml.bind.*;version=\"${project.jaxbApiVersionOsgiRange}\"", - // Temporarily support JTA 1.1 -- Karaf and other frameworks still - // use it. Without this, the plugin generates [1.2,2). - 'javax.transaction;version="[1.1,2)"', - // Also import every package referenced in the code - '*' - ].join( ',' ), +// // BND Plugin instructions (for OSGi): +// 'Import-Package': [ +// 'javax.security.auth;resolution:=optional', +// // Make javax.security.jacc optional and do not reference a version range (because that's what we used to do) +// 'javax.security.jacc;resolution:=optional;version=!', +// // Make javax.validation optional and do not reference a version range (because that's what we used to do) +// 'javax.validation;resolution:=optional;version=!', +// 'javax.validation.constraints;resolution:=optional;version=!', +// 'javax.validation.groups;resolution:=optional;version=!', +// 'javax.validation.metadata;resolution:=optional;version=!', +// // Make javax.enterprise optional and do not reference a version range (because that's what we used to do) +// '!javax.enterprise*', +// 'javax.enterprise.context.spi;resolution:=optional;version=!', +// 'javax.enterprise.inject.spi;resolution:=optional;version=!', +// // For JPA, we don't want to target the automatically generated range, but a specific version +// "javax.persistence;version=\"${project.jpaVersion.osgiName}\"", +// // optionals +// 'jakarta.persistence.spi;resolution:=optional', +// 'javax.management;resolution:=optional', +// 'javax.naming.event;resolution:=optional', +// 'javax.naming.spi;resolution:=optional', +// 'org.apache.tools.ant;resolution:=optional', +// 'org.apache.tools.ant.taskdefs;resolution:=optional', +// 'org.apache.tools.ant.types;resolution:=optional', +// 'javax.inject;resolution:=optional', +// 'net.bytebuddy.*;resolution:=optional', +// 'org.objectweb.jonas_tm;resolution:=optional', +// 'com.ibm.websphere.jtaextensions;resolution:=optional', +// // We must specify the version explicitly to allow Karaf +// // to use an older version of JAXB (the only one we can use in Karaf) +// "javax.xml.bind.*;version=\"${project.jaxbApiVersionOsgiRange}\"", +// // Temporarily support JTA 1.1 -- Karaf and other frameworks still +// // use it. Without this, the plugin generates [1.2,2). +// 'javax.transaction;version="[1.1,2)"', +// // Also import every package referenced in the code +// '*' +// ].join( ',' ), '-exportcontents': [ // Legacy resource packages containing XSDs that were traditionally not exported "!org.hibernate.xsd.cfg", diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java index cb21431812..61b899ff5c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java @@ -377,7 +377,7 @@ public final class CollectionHelper { @SuppressWarnings( "unchecked" ) public static void collectMapEntries(BiConsumer mapEntryConsumer, Object[] mappings) { // even numbered - assert mappings.length %2 == 0; + assert mappings.length % 2 == 0; for ( int i = 0; i < mappings.length; i += 2 ) { mapEntryConsumer.accept( (K) mappings[i], (V) mappings[i+1] ); @@ -397,4 +397,59 @@ public final class CollectionHelper { return map; } + + public static Map toMap(String... pairs) { + assert pairs.length % 2 == 0; + if ( pairs.length == 2 ) { + return Collections.singletonMap( pairs[0], pairs[1] ); + } + + final Map result = new HashMap<>(); + applyToMap( result, pairs ); + return result; + } + + private static void applyToMap(Map map, String... pairs) { + assert pairs.length % 2 == 0; + for ( int i = 0; i < pairs.length; i+=2 ) { + map.put( pairs[i], pairs[i+1] ); + } + } + + public static Map toMap(Object... pairs) { + assert pairs.length % 2 == 0; + if ( pairs.length == 2 ) { + return Collections.singletonMap( (String) pairs[0], pairs[1] ); + } + + final Map result = new HashMap<>(); + applyToMap( result, pairs ); + return result; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static void applyToMap(Map map, Object... pairs) { + assert pairs.length % 2 == 0; + for ( int i = 0; i < pairs.length; i+=2 ) { + ( (Map) map ).put( pairs[i], pairs[i+1] ); + } + } + + public static Properties toProperties(Object... pairs) { + final Properties properties = new Properties(); + if ( pairs.length > 0 ) { + assert pairs.length % 2 == 0; + for ( int i = 0; i < pairs.length; i+=2 ) { + properties.put( pairs[i], pairs[i+1] ); + } + } + return properties; + } + + public static void applyToProperties(Properties properties, Object... pairs) { + assert pairs.length % 2 == 0; + for ( int i = 0; i < pairs.length; i+=2 ) { + properties.put( pairs[i], pairs[i+1] ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/Action.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/Action.java index 9591671894..37774266f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/Action.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/Action.java @@ -135,6 +135,13 @@ public enum Action { } } + // lastly, look at the enum name + for ( Action action : values() ) { + if ( action.name().equals( name ) ) { + return action; + } + } + throw new IllegalArgumentException( "Unrecognized JPA schema generation action value : " + value ); } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java index 98ef4b619e..d80591344b 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java @@ -47,6 +47,7 @@ import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DROP_SOURCE; import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_SCRIPTS_ACTION; import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_SCRIPTS_CREATE_TARGET; import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_SCRIPTS_DROP_TARGET; +import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; /** * Responsible for coordinating SchemaManagementTool execution(s) for auto-tooling whether @@ -630,71 +631,142 @@ public class SchemaManagementToolCoordinator { } /** - * For test use + * For test use. See {@link #interpret(Metadata, Map)} for the "real" impl */ @Internal - public static ActionGrouping interpret(Map configurationValues) { - Object databaseActionSetting = configurationValues.get( HBM2DDL_DATABASE_ACTION ); - Object scriptsActionSetting = configurationValues.get( HBM2DDL_SCRIPTS_ACTION ); - if ( databaseActionSetting == null ) { - databaseActionSetting = configurationValues.get( JAKARTA_HBM2DDL_DATABASE_ACTION ); - } - if ( scriptsActionSetting == null ) { - scriptsActionSetting = configurationValues.get( JAKARTA_HBM2DDL_SCRIPTS_ACTION ); - } - // interpret the JPA settings first - Action databaseAction = Action.interpretJpaSetting( databaseActionSetting ); - Action scriptAction = Action.interpretJpaSetting( scriptsActionSetting ); + public static ActionGrouping interpret(Map configurationValues) { + // default to the JPA settings + Action databaseAction = determineJpaDbActionSetting( configurationValues ); + Action scriptAction = determineJpaScriptActionSetting( configurationValues ); // if no JPA settings were specified, look at the legacy HBM2DDL_AUTO setting... - if ( databaseAction == Action.NONE && scriptAction == Action.NONE ) { - final Action hbm2ddlAutoAction = Action.interpretHbm2ddlSetting( configurationValues.get( HBM2DDL_AUTO ) ); - if ( hbm2ddlAutoAction != Action.NONE ) { - databaseAction = hbm2ddlAutoAction; + if ( databaseAction == null && scriptAction == null ) { + final Action autoAction = determineAutoSettingImpliedAction( configurationValues, null, null ); + if ( autoAction != null ) { + databaseAction = autoAction; } } + if ( databaseAction == null ) { + databaseAction = Action.NONE; + } + if ( scriptAction == null ) { + scriptAction = Action.NONE; + } + return new ActionGrouping( "orm", databaseAction, scriptAction ); } + private static Action determineJpaDbActionSetting(Map configurationValues) { + return determineJpaDbActionSetting( configurationValues, null, null ); + } + + /** + * Exposed for tests + */ + @Internal + public static Action determineJpaDbActionSetting( + Map configurationValues, + String contributor, + Action defaultValue) { + final String jakartaSettingName = contributor == null + ? JAKARTA_HBM2DDL_DATABASE_ACTION + : JAKARTA_HBM2DDL_DATABASE_ACTION + "." + contributor; + final String javaxSettingName = contributor == null + ? HBM2DDL_DATABASE_ACTION + : HBM2DDL_DATABASE_ACTION + "." + contributor; + + Object databaseActionSetting = configurationValues.get( jakartaSettingName ); + if ( databaseActionSetting == null ) { + databaseActionSetting = configurationValues.get( javaxSettingName ); + if ( databaseActionSetting != null ) { + DEPRECATION_LOGGER.deprecatedSetting( HBM2DDL_DATABASE_ACTION, JAKARTA_HBM2DDL_DATABASE_ACTION ); + } + } + + return databaseActionSetting == null ? defaultValue : Action.interpretJpaSetting( databaseActionSetting ); + } + + private static Action determineJpaScriptActionSetting(Map configurationValues) { + return determineJpaScriptActionSetting( configurationValues, null, null ); + } + + /** + * Exposed for tests + */ + @Internal + public static Action determineJpaScriptActionSetting( + Map configurationValues, + String contributor, + Action defaultValue) { + final String jakartaSettingName = contributor == null + ? JAKARTA_HBM2DDL_SCRIPTS_ACTION + : JAKARTA_HBM2DDL_SCRIPTS_ACTION + "." + contributor; + final String javaxSettingName = contributor == null + ? HBM2DDL_SCRIPTS_ACTION + : HBM2DDL_SCRIPTS_ACTION + "." + contributor; + + Object scriptsActionSetting = configurationValues.get( jakartaSettingName ); + if ( scriptsActionSetting == null ) { + scriptsActionSetting = configurationValues.get( javaxSettingName ); + if ( scriptsActionSetting != null ) { + DEPRECATION_LOGGER.deprecatedSetting( HBM2DDL_SCRIPTS_ACTION, JAKARTA_HBM2DDL_SCRIPTS_ACTION ); + } + } + + return scriptsActionSetting == null ? defaultValue : Action.interpretJpaSetting( scriptsActionSetting ); + } + + public static Action determineAutoSettingImpliedAction(Map settings, String contributor, Action defaultValue) { + final String settingName = contributor == null + ? HBM2DDL_AUTO + : HBM2DDL_AUTO + "." + contributor; + + final Object scriptsActionSetting = settings.get( settingName ); + if ( scriptsActionSetting == null ) { + return defaultValue; + } + + return Action.interpretHbm2ddlSetting( scriptsActionSetting ); + } + public static Set interpret(Metadata metadata, Map configurationValues) { // these represent the base (non-contributor-specific) values - final Action rootDatabaseAction = Action.interpretJpaSetting( configurationValues.get( HBM2DDL_DATABASE_ACTION ) ); - final Action rootScriptAction = Action.interpretJpaSetting( configurationValues.get( HBM2DDL_SCRIPTS_ACTION ) ); - final Action rootExportAction = Action.interpretHbm2ddlSetting( configurationValues.get( HBM2DDL_AUTO ) ); + final Action rootDatabaseAction = determineJpaDbActionSetting( configurationValues, null, null ); + final Action rootScriptAction = determineJpaScriptActionSetting( configurationValues, null, null ); + + final Action rootAutoAction = determineAutoSettingImpliedAction( configurationValues, null, null ); final Set contributors = metadata.getContributors(); final Set groupings = new HashSet<>( contributors.size() ); // for each contributor, look for specific tooling config values for ( String contributor : contributors ) { - final Object contributorDatabaseActionSetting = configurationValues.get( HBM2DDL_DATABASE_ACTION + "." + contributor ); - final Object contributorScriptActionSetting = configurationValues.get( HBM2DDL_SCRIPTS_ACTION + "." + contributor ); - final Object contributorExportActionSetting = configurationValues.get( HBM2DDL_AUTO + "." + contributor ); + Action databaseActionToUse = determineJpaDbActionSetting( configurationValues, contributor, rootDatabaseAction );; + Action scriptActionToUse = determineJpaScriptActionSetting( configurationValues, contributor, rootScriptAction ); - final Action contributorDatabaseAction = contributorDatabaseActionSetting == null - ? rootDatabaseAction - : Action.interpretJpaSetting( contributorDatabaseActionSetting ); - final Action contributorScriptAction = contributorScriptActionSetting == null - ? rootScriptAction - : Action.interpretJpaSetting( contributorScriptActionSetting ); - final Action contributorExportAction = contributorExportActionSetting == null - ? rootExportAction - : Action.interpretJpaSetting( contributorExportActionSetting ); - - Action databaseAction = contributorDatabaseAction; - if ( databaseAction == Action.NONE && contributorScriptAction == Action.NONE ) { - if ( contributorExportAction != Action.NONE ) { - databaseAction = contributorExportAction; - } - - if ( databaseAction == Action.NONE ) { - log.debugf( "No schema actions specified for contributor `%s`; doing nothing", contributor ); - continue; + if ( databaseActionToUse == null && scriptActionToUse == null ) { + // no JPA (jakarta nor javax) settings were specified, use the legacy Hibernate + // `hbm2ddl.auto` setting to possibly set the database-action + final Action contributorAutoSetting = determineAutoSettingImpliedAction( configurationValues, contributor, rootAutoAction ); + if ( contributorAutoSetting != null ) { + databaseActionToUse = contributorAutoSetting; } } - groupings.add( new ActionGrouping( contributor, databaseAction, contributorScriptAction ) ); + if ( databaseActionToUse == null ) { + databaseActionToUse = Action.NONE; + } + if ( scriptActionToUse == null ) { + scriptActionToUse = Action.NONE; + } + + if ( databaseActionToUse == Action.NONE && scriptActionToUse == Action.NONE ) { + log.debugf( "No schema actions specified for contributor `%s`; doing nothing", contributor ); + continue; + } + + groupings.add( new ActionGrouping( contributor, databaseActionToUse, scriptActionToUse ) ); } return groupings; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ejb3configuration/ConfigurationObjectSettingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ejb3configuration/ConfigurationObjectSettingTest.java index b62200f476..e5b7cea4ce 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ejb3configuration/ConfigurationObjectSettingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/ejb3configuration/ConfigurationObjectSettingTest.java @@ -7,14 +7,25 @@ package org.hibernate.orm.test.jpa.ejb3configuration; import java.util.Collections; -import java.util.HashMap; import java.util.Map; -import java.util.Properties; +import java.util.Set; import org.hibernate.HibernateException; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.engine.jdbc.dialect.internal.DialectResolverInitiator; +import org.hibernate.engine.jdbc.dialect.spi.DialectResolver; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; import org.hibernate.jpa.boot.spi.Bootstrap; +import org.hibernate.orm.test.dialect.resolver.TestingDialectResolutionInfo; +import org.hibernate.service.spi.ServiceRegistryImplementor; +import org.hibernate.tool.schema.Action; +import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.ActionGrouping; import org.hibernate.testing.orm.jpa.PersistenceUnitInfoAdapter; import org.hibernate.testing.orm.junit.BaseUnitTest; @@ -203,7 +214,7 @@ public class ConfigurationObjectSettingTest { { builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( empty, - toMap( + CollectionHelper.toMap( jdbcUrl, urlValue, jdbcDriver, driverValue, jdbcUser, userValue, @@ -221,7 +232,7 @@ public class ConfigurationObjectSettingTest { } PersistenceUnitInfoAdapter pui = new PersistenceUnitInfoAdapter(); - applyToMap( + CollectionHelper.applyToProperties( pui.getProperties(), jdbcUrl, urlValue, jdbcDriver, driverValue, @@ -242,34 +253,67 @@ public class ConfigurationObjectSettingTest { builder.cancel(); } - - } - private static Map toMap(String... pairs) { - assert pairs.length %2 == 0; - if ( pairs.length == 2 ) { - return Collections.singletonMap( pairs[0], pairs[1] ); - } - - final Map result = new HashMap<>(); - for ( int i = 0; i < pairs.length; i+=2 ) { - result.put( pairs[i], pairs[i+1] ); - } - return result; + @Test + public void testSchemaGenSettings() { + verifySchemaGenSettings( + AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, + AvailableSettings.JAKARTA_HBM2DDL_SCRIPTS_ACTION, + AvailableSettings.JAKARTA_HBM2DDL_CREATE_SCHEMAS, + AvailableSettings.JAKARTA_HBM2DDL_DB_NAME + ); + verifySchemaGenSettings( + AvailableSettings.HBM2DDL_DATABASE_ACTION, + AvailableSettings.HBM2DDL_SCRIPTS_ACTION, + AvailableSettings.HBM2DDL_CREATE_SCHEMAS, + AvailableSettings.DIALECT_DB_NAME + ); +// verifySchemaGenSettingsPrecedence(); } - private static void applyToMap(Map map, String... pairs) { - assert pairs.length %2 == 0; - for ( int i = 0; i < pairs.length; i+=2 ) { - map.put( pairs[i], pairs[i+1] ); - } + private void verifySchemaGenSettings( + String dbActionSettingName, + String scriptActionSettingName, + String createSchemasSettingName, + String dbNameSettingName) { + final Action dbAction = Action.CREATE_ONLY; + final Action scriptAction = Action.CREATE_ONLY; + final boolean createSchemas = true; + final String dbName = "H2"; + + final Map settings = CollectionHelper.toMap( + dbActionSettingName, dbAction.getExternalJpaName(), + scriptActionSettingName, scriptAction.getExternalJpaName(), + createSchemasSettingName, Boolean.toString( createSchemas ), + dbNameSettingName, dbName + ); + + // first verify the individual interpretations + final Action interpretedDbAction = ActionGrouping.determineJpaDbActionSetting( settings, null, null ); + assertThat( interpretedDbAction ).isEqualTo( dbAction ); + final Action interpretedScriptAction = ActionGrouping.determineJpaScriptActionSetting( settings, null, null ); + assertThat( interpretedScriptAction ).isEqualTo( scriptAction ); + + // next verify the action-group determination + final ActionGrouping actionGrouping = ActionGrouping.interpret( settings ); + assertThat( actionGrouping.getDatabaseAction() ).isEqualTo( dbAction ); + assertThat( actionGrouping.getScriptAction() ).isEqualTo( scriptAction ); + + // the check above uses a "for testing only" form of what happens for "real". + // verify the "real" path as well + final Metadata metadata = new MetadataSources().addAnnotatedClass( Bell.class ).buildMetadata(); + final Set actionGroupings = ActionGrouping.interpret( metadata, settings ); + assertThat( actionGroupings ).hasSize( 1 ); + final ActionGrouping grouping = actionGroupings.iterator().next(); + assertThat( grouping.getContributor() ).isEqualTo( "orm" ); + assertThat( grouping.getDatabaseAction() ).isEqualTo( dbAction ); + assertThat( grouping.getScriptAction() ).isEqualTo( scriptAction ); + + // verify also interpreting the db-name, etc... they are used by SF/EMF to resolve Dialect + final DialectResolver dialectResolver = new DialectResolverInitiator().initiateService( settings, (ServiceRegistryImplementor) new StandardServiceRegistryBuilder().build() ); + final Dialect dialect = dialectResolver.resolveDialect( TestingDialectResolutionInfo.forDatabaseInfo( dbName ) ); + assertThat( dialect ).isInstanceOf( H2Dialect.class ); } - private static void applyToMap(Properties map, String... pairs) { - assert pairs.length %2 == 0; - for ( int i = 0; i < pairs.length; i+=2 ) { - map.put( pairs[i], pairs[i+1] ); - } - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaSchemaToolingSettingPrecedenceTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaSchemaToolingSettingPrecedenceTests.java new file mode 100644 index 0000000000..f654fe3627 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaSchemaToolingSettingPrecedenceTests.java @@ -0,0 +1,38 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.jpa.jakarta; + +import org.hibernate.cfg.AvailableSettings; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; + +/** + * Make sure {@code `jakarta.persistence.*`} settings have function precedence over + * the legacy {@link `javax.persistence.*`} counterparts + * + * @author Steve Ebersole + */ +@ServiceRegistry( + settings = { + @Setting( name = AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, value = "create-drop" ), + @Setting( name = AvailableSettings.HBM2DDL_DATABASE_ACTION, value = "none" ) + } +) +@DomainModel( annotatedClasses = SimpleEntity.class ) +@SessionFactory +public class JakartaSchemaToolingSettingPrecedenceTests { + @Test + public void verifySchemaCreated(SessionFactoryScope scope) { + // the query would fail if the schema were not exported - just a smoke test + scope.inTransaction( (s) -> s.createQuery( "from SimpleEntity" ).list() ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaSchemaToolingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaSchemaToolingTests.java new file mode 100644 index 0000000000..49b5d82397 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaSchemaToolingTests.java @@ -0,0 +1,125 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.jpa.jakarta; + +import java.util.Collections; +import java.util.List; +import java.util.Properties; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.jpa.boot.spi.Bootstrap; +import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; +import org.hibernate.tool.schema.Action; + +import org.hibernate.testing.orm.jpa.PersistenceUnitDescriptorAdapter; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.Setting; +import org.hibernate.testing.transaction.TransactionUtil2; +import org.junit.jupiter.api.Test; + +import static org.hibernate.cfg.AvailableSettings.HBM2DDL_DATABASE_ACTION; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_JDBC_DRIVER; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_JDBC_PASSWORD; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_JDBC_URL; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_JDBC_USER; +import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_DRIVER; +import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_PASSWORD; +import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_URL; +import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_USER; + +/** + * @author Steve Ebersole + */ +@ServiceRegistry( + settings = { + @Setting( name = JAKARTA_HBM2DDL_DATABASE_ACTION, value = "create-drop" ) + } +) +@DomainModel( annotatedClasses = SimpleEntity.class ) +@SessionFactory +public class JakartaSchemaToolingTests { + @Test + public void testSchemaCreation() { + verifySchemaCreation( JAKARTA_HBM2DDL_DATABASE_ACTION, JAKARTA_JPA_JDBC_DRIVER, JAKARTA_JPA_JDBC_URL, JAKARTA_JPA_JDBC_USER, JAKARTA_JPA_JDBC_PASSWORD ); + verifySchemaCreation( HBM2DDL_DATABASE_ACTION, JPA_JDBC_DRIVER, JPA_JDBC_URL, JPA_JDBC_USER, JPA_JDBC_PASSWORD ); + } + + private void verifySchemaCreation( + String actionSettingName, + String driverSettingName, + String urlSettingName, + String userSettingName, + String passwordSettingName) { + final SessionFactoryImplementor sessionFactory = buildSessionFactory( + actionSettingName, Action.CREATE_DROP, + driverSettingName, Environment.getProperties().get( AvailableSettings.DRIVER ), + urlSettingName, Environment.getProperties().get( AvailableSettings.URL ), + userSettingName, Environment.getProperties().get( AvailableSettings.USER ), + passwordSettingName, Environment.getProperties().get( AvailableSettings.PASS ) + ); + try { + tryQuery( sessionFactory ); + } + finally { + sessionFactory.close(); + } + + } + + private void tryQuery(SessionFactoryImplementor sessionFactory) { + TransactionUtil2.inTransaction( sessionFactory, (session) -> { + // the query would fail if the schema were not exported - just a smoke test + session.createQuery( "from SimpleEntity" ).list(); + }); + } + + @Test + public void testPrecedence() { + // make sure JAKARTA_HBM2DDL_DATABASE_ACTION (`jakarta...`) takes precedence over HBM2DDL_DATABASE_ACTION (`javax...`) + try ( SessionFactoryImplementor sessionFactory = buildSessionFactory( + JAKARTA_HBM2DDL_DATABASE_ACTION, Action.CREATE_DROP, + HBM2DDL_DATABASE_ACTION, Action.NONE, + JAKARTA_JPA_JDBC_DRIVER, Environment.getProperties().get( AvailableSettings.DRIVER ), + JAKARTA_JPA_JDBC_URL, Environment.getProperties().get( AvailableSettings.URL ), + JAKARTA_JPA_JDBC_USER, Environment.getProperties().get( AvailableSettings.USER ), + JAKARTA_JPA_JDBC_PASSWORD, Environment.getProperties().get( AvailableSettings.PASS ) + ) ) { + tryQuery( sessionFactory ); + } + } + + private SessionFactoryImplementor buildSessionFactory(Object... settingPairs) { + final Properties settings = CollectionHelper.toProperties( settingPairs ); + + final PersistenceUnitDescriptorAdapter puDescriptor = new PersistenceUnitDescriptorAdapter() { + @Override + public Properties getProperties() { + return settings; + } + + @Override + public List getManagedClassNames() { + return Collections.singletonList( SimpleEntity.class.getName() ); + } + }; + + + final EntityManagerFactoryBuilder emfBuilder = Bootstrap.getEntityManagerFactoryBuilder( + puDescriptor, + settings, + (mergedSettings) -> mergedSettings.getConfigurationValues().clear() + ); + + return emfBuilder.build().unwrap( SessionFactoryImplementor.class ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/xml/JakartaXmlSmokeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/orm/test/jpa/xml/JakartaXmlSmokeTests.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java index 2d996897ce..d88329e2c1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/xml/JakartaXmlSmokeTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.jpa.xml; +package org.hibernate.orm.test.jpa.jakarta; import java.io.IOException; import java.io.InputStream; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/SimpleEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/SimpleEntity.java new file mode 100644 index 0000000000..127e56fef1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/SimpleEntity.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.jpa.jakarta; + +import jakarta.persistence.Basic; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +/** + * @author Steve Ebersole + */ +@Entity(name = "SimpleEntity") +@Table(name = "SimpleEntity") +public class SimpleEntity { + @Id + public Integer id; + @Basic + public String name; +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/package-info.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/package-info.java new file mode 100644 index 0000000000..091a322cf6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/package-info.java @@ -0,0 +1,13 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ + +/** + * Initial tests for functional Jakarta Persistence support; + * + * @author Steve Ebersole + */ +package org.hibernate.orm.test.jpa.jakarta; \ No newline at end of file