Hello, I have the following code to generate changelog programmatically:
Database db = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
String url = "hibernate:spring:cloud.service2,cloud.boot.starter.data"
+ "?dialect=org.hibernate.dialect.MySQL8Dialect"
+ "&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy"
+ "&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy";
HibernateConnection hibernateConnection = new HibernateConnection(url, null);
JdbcConnection jdbcConnection = new JdbcConnection(hibernateConnection);
Database hdb = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(jdbcConnection);
File changelog = new File(CHANGELOG_FOLDER + File.separator + changelogFileFileName);
changelog.delete();
CommandLineUtils.doDiffToChangeLog(changelog.getAbsolutePath(), hdb, db, new DiffOutputControl(false, false, false, null), null, null);
return Optional.of(changelog);
however, during the building of HibernateSpringPakcageDatabase (hdb in the code above) when the execution get to buildMetadataFromPath() of HibernateEjb3Database it throw an error at building the EntityManagerFactory:
2021-07-23 10:41:06.023 WARN 28764 [ main] o.h.e.j.e.i.JdbcEnvironmentInitiator * * * : HHH000342: Could not obtain connection to query metadata
java.lang.UnsupportedOperationException: The application must supply JDBC connections
at org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl.getConnection(UserSuppliedConnectionProviderImpl.java:44) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:68) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:176) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:127) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1224) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1255) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at liquibase.ext.hibernate.database.HibernateEjb3Database.buildMetadataFromPath(HibernateEjb3Database.java:59) ~[liquibase-hibernate5-4.3.5.jar:na]
at liquibase.ext.hibernate.database.HibernateDatabase.buildMetadata(HibernateDatabase.java:143) ~[liquibase-hibernate5-4.3.5.jar:na]
at liquibase.ext.hibernate.database.HibernateDatabase.setConnection(HibernateDatabase.java:83) ~[liquibase-hibernate5-4.3.5.jar:na]
at liquibase.database.DatabaseFactory.findCorrectDatabaseImplementation(DatabaseFactory.java:121) ~[liquibase-core-4.3.5.jar:na]
My understanding is that the HibernateSpringPackageDatabase is a meta database without real connection, however, at some point Hibernate is trying to get its connection. The root cause of this issue is that the buildMetadata() of HibernateDatabase class use the path from the url i specified to load the class but the path is the package, not a classname so it failed and thus fall back to loading metadata using connection.
My question has 2 parts:
1/My url match the template for HibernateSpringPackageDatabase which mean there are multiple Entity classes in the package, why the build metadata expects only 1 class? Am I wrong assuming that the changelog can be generated by diff 2 database with more than one entity/table?
2/Is there a documentation of how to use liquibase programmatically?