4.21 seems to be out, but there are no release notes, yet. Could you please add them?
I am using liquibase embedded in a Kotlin application, as described in section " Embed Liquibase into your product" here: 3 Ways to Run Liquibase
My gradle update check task alerted me of the new version, and I tried to update because it warns that 4.20 has a security flaw in one the dependencies [CVE-2022-1471].
However, after the update my build fails with a deprecated warning at Liquibase.update().
At the update() method I use, there is just a @Deprecated annotation with no hint at all what to use instead.
When follow the trail in the liquibase sources to the overloaded method that all the update variants delegate to, I find @deprecated Use CommandStep
Not that helpful
Oh, I just noticed that there are new update() overloads which are not deprecated, all taking a Writer … and no such method has any JavaDoc
What is this Writer? Is it used for logging? If so, how would I get a Writer from log4j2 or slf4j?
Finally, could you please update the 3 Ways to Run Liquibase to use a non-deprecated update method?
Yeah, that javadoc could be improved. “Use CommandStep” is not really even the right answer for most people. Also the versions with Writer should either be deprecated now or will be soon. We aren’t planning to actually remove the methods for a while, but still good to shift to the newer APIs when you can
The replacement for the Liquibase class in general is the liquibase.command.CommandScope class. command.CommandScope - contribute.liquibase.com gives some more information on it. We are creating that class vs. the original Liquibase facade to be flexible enough to work with everything Liquibase can do now and is looking to do in the future. A static list of methods and arguments just wasn’t cutting it anymore.
Your new version of liquibase.update() will be more like:
where applyLiquibaseChangeList first creates a Liquibase object, with a JDBC connection and a resource accessor and the resource classpath to the changelog file embedded in the OSGi bundle (i.e. the jar file):
Ok, I’ve tried to translate this into Java code:
private void applyLiquibaseChangelist(Connection connection, String changelistClasspathResource) throws Exception {
var database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
Map<String, Object> scopeObjects = Map.of(
Scope.Attr.database.name(), database,
Scope.Attr.resourceAccessor.name(), new OSGiResourceAccessor(bundle));
Scope.child(scopeObjects, (ScopedRunner) () -> new CommandScope("update")
.addArgumentValue(DbUrlConnectionCommandStep.DATABASE_ARG, database)
.addArgumentValue(UpdateCommandStep.CHANGELOG_FILE_ARG, changelistClasspathResource)
.addArgumentValue(DatabaseChangelogCommandStep.CHANGELOG_PARAMETERS, new ChangeLogParameters(database))
.execute());
}
But it fails with the following error (fails in execute()):
liquibase.exception.CommandExecutionException: java.lang.RuntimeException: Cannot end scope xlveporhmt when currently at scope bsmuuxncug
at liquibase.command.CommandScope.execute(CommandScope.java:235) ~[?:?]
at no.priv.bang.karaf.sample.db.liquibase.test.SampleDbLiquibaseRunner.lambda$applyLiquibaseChangelist$1(SampleDbLiquibaseRunner.java:100) ~[?:?]
at liquibase.Scope.lambda$child$0(Scope.java:194) ~[?:?]
at liquibase.Scope.child(Scope.java:203) ~[?:?]
at liquibase.Scope.child(Scope.java:193) ~[?:?]
at liquibase.Scope.child(Scope.java:172) ~[?:?]
at no.priv.bang.karaf.sample.db.liquibase.test.SampleDbLiquibaseRunner.applyLiquibaseChangelist(SampleDbLiquibaseRunner.java:96) ~[?:?]
at no.priv.bang.karaf.sample.db.liquibase.test.SampleDbLiquibaseRunner.prepare(SampleDbLiquibaseRunner.java:65) ~[?:?]
at org.ops4j.pax.jdbc.config.impl.DataSourceRegistration.<init>(DataSourceRegistration.java:88) ~[?:?]
at org.ops4j.pax.jdbc.config.impl.DataSourceConfigManager.lambda$null$4(DataSourceConfigManager.java:95) ~[?:?]
at org.ops4j.pax.jdbc.config.impl.ServiceTrackerHelper$1.addingService(ServiceTrackerHelper.java:132) ~[?:?]
at org.osgi.util.tracker.ServiceTracker$Tracked.customizerAdding(ServiceTracker.java:943) ~[osgi.core-8.0.0.jar:?]
at org.osgi.util.tracker.ServiceTracker$Tracked.customizerAdding(ServiceTracker.java:871) ~[osgi.core-8.0.0.jar:?]
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:256) ~[osgi.core-8.0.0.jar:?]
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:229) ~[osgi.core-8.0.0.jar:?]
at org.osgi.util.tracker.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:903) ~[osgi.core-8.0.0.jar:?]
at org.apache.felix.framework.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:990) ~[?:?]
at org.apache.felix.framework.EventDispatcher.fireEventImmediately(EventDispatcher.java:838) ~[?:?]
at org.apache.felix.framework.EventDispatcher.fireServiceEvent(EventDispatcher.java:545) ~[?:?]
at org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4863) ~[?:?]
at org.apache.felix.framework.Felix.registerService(Felix.java:3834) ~[?:?]
at org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:328) ~[?:?]
at org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:302) ~[?:?]
at org.ops4j.pax.jdbc.derby.impl.Activator.start(Activator.java:34) ~[?:?]
at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:849) ~[?:?]
at org.apache.felix.framework.Felix.activateBundle(Felix.java:2429) ~[?:?]
at org.apache.felix.framework.Felix.startBundle(Felix.java:2335) ~[?:?]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:1006) ~[?:?]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:992) ~[?:?]
at org.apache.karaf.features.internal.service.BundleInstallSupportImpl.startBundle(BundleInstallSupportImpl.java:165) ~[?:?]
at org.apache.karaf.features.internal.service.FeaturesServiceImpl.startBundle(FeaturesServiceImpl.java:1160) ~[?:?]
at org.apache.karaf.features.internal.service.Deployer.deploy(Deployer.java:1041) ~[?:?]
at org.apache.karaf.features.internal.service.FeaturesServiceImpl.doProvision(FeaturesServiceImpl.java:1069) ~[?:?]
at org.apache.karaf.features.internal.service.FeaturesServiceImpl.lambda$doProvisionInThread$13(FeaturesServiceImpl.java:1004) ~[?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:829) ~[?:?]
Suppressed: java.sql.SQLException: Cannot close a connection while a transaction is still active.
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source) ~[?:?]
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source) ~[?:?]
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source) ~[?:?]
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source) ~[?:?]
at org.apache.derby.impl.jdbc.EmbedConnection.newSQLException(Unknown Source) ~[?:?]
at org.apache.derby.impl.jdbc.EmbedConnection.checkForTransactionInProgress(Unknown Source) ~[?:?]
at org.apache.derby.impl.jdbc.EmbedConnection.close(Unknown Source) ~[?:?]
at no.priv.bang.karaf.sample.db.liquibase.test.SampleDbLiquibaseRunner.prepare(SampleDbLiquibaseRunner.java:64) ~[?:?]
at org.ops4j.pax.jdbc.config.impl.DataSourceRegistration.<init>(DataSourceRegistration.java:88) ~[?:?]
at org.ops4j.pax.jdbc.config.impl.DataSourceConfigManager.lambda$null$4(DataSourceConfigManager.java:95) ~[?:?]
at org.ops4j.pax.jdbc.config.impl.ServiceTrackerHelper$1.addingService(ServiceTrackerHelper.java:132) ~[?:?]
at org.osgi.util.tracker.ServiceTracker$Tracked.customizerAdding(ServiceTracker.java:943) ~[osgi.core-8.0.0.jar:?]
at org.osgi.util.tracker.ServiceTracker$Tracked.customizerAdding(ServiceTracker.java:871) ~[osgi.core-8.0.0.jar:?]
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:256) ~[osgi.core-8.0.0.jar:?]
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:229) ~[osgi.core-8.0.0.jar:?]
at org.osgi.util.tracker.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:903) ~[osgi.core-8.0.0.jar:?]
at org.apache.felix.framework.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:990) ~[?:?]
at org.apache.felix.framework.EventDispatcher.fireEventImmediately(EventDispatcher.java:838) ~[?:?]
at org.apache.felix.framework.EventDispatcher.fireServiceEvent(EventDispatcher.java:545) ~[?:?]
at org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4863) ~[?:?]
at org.apache.felix.framework.Felix.registerService(Felix.java:3834) ~[?:?]
at org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:328) ~[?:?]
at org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:302) ~[?:?]
at org.ops4j.pax.jdbc.derby.impl.Activator.start(Activator.java:34) ~[?:?]
at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:849) ~[?:?]
at org.apache.felix.framework.Felix.activateBundle(Felix.java:2429) ~[?:?]
at org.apache.felix.framework.Felix.startBundle(Felix.java:2335) ~[?:?]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:1006) ~[?:?]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:992) ~[?:?]
at org.apache.karaf.features.internal.service.BundleInstallSupportImpl.startBundle(BundleInstallSupportImpl.java:165) ~[?:?]
at org.apache.karaf.features.internal.service.FeaturesServiceImpl.startBundle(FeaturesServiceImpl.java:1160) ~[?:?]
at org.apache.karaf.features.internal.service.Deployer.deploy(Deployer.java:1041) ~[?:?]
at org.apache.karaf.features.internal.service.FeaturesServiceImpl.doProvision(FeaturesServiceImpl.java:1069) ~[?:?]
at org.apache.karaf.features.internal.service.FeaturesServiceImpl.lambda$doProvisionInThread$13(FeaturesServiceImpl.java:1004) ~[?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:829) ~[?:?]
Caused by: org.apache.derby.iapi.error.StandardException: Cannot close a connection while a transaction is still active.
at org.apache.derby.iapi.error.StandardException.newException(Unknown Source) ~[?:?]
at org.apache.derby.impl.jdbc.SQLExceptionFactory.wrapArgsForTransportAcrossDRDA(Unknown Source) ~[?:?]
... 38 more
Caused by: java.lang.RuntimeException: Cannot end scope xlveporhmt when currently at scope bsmuuxncug
at liquibase.Scope.exit(Scope.java:241) ~[?:?]
at liquibase.Scope.child(Scope.java:205) ~[?:?]
at liquibase.Scope.child(Scope.java:193) ~[?:?]
at liquibase.Scope.child(Scope.java:189) ~[?:?]
at liquibase.command.CommandScope.addOutputFileToMdc(CommandScope.java:254) ~[?:?]
at liquibase.command.CommandScope.execute(CommandScope.java:207) ~[?:?]
... 37 more
Is it just me or is the CommandScope interface very confusing. How do I pass the connection it should use? I see it can be done by setting key values, but why is this so complicated? Not really self documenting…