After upgrading to Spring Boot 2.2 I can no longer start my Liquibase application.
I am getting the following exception:
Caused by: java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlElement
at liquibase.pro.packaged.ki.<init>(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.ki.<init>(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.kj.setupModule(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.bW.registerModule(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.lQ.d_(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.ku.a(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.ku.a(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.kv.a(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.kv$a.a(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.kv$a$1.f(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.ks.a(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.kr.a(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.kp.a(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.pro.packaged.kp.<init>(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490) ~[na:na]
at java.base/java.lang.Class.newInstance(Class.java:584) ~[na:na]
at liquibase.license.LicenseServiceFactory.getLicenseService(LicenseServiceFactory.java:33) ~[liquibase-core-3.8.2.jar:na]
at liquibase.license.LicenseServiceUtils.checkForValidLicense(LicenseServiceUtils.java:46) ~[liquibase-core-3.8.2.jar:na]
at com.datical.liquibase.ext.appdba.synonym.SynonymSnapshotGenerator.getPriority(Unknown Source) ~[liquibase-core-3.8.2.jar:na]
at liquibase.snapshot.SnapshotGeneratorFactory.getGenerators(SnapshotGeneratorFactory.java:86) ~[liquibase-core-3.8.2.jar:na]
at liquibase.snapshot.SnapshotGeneratorFactory.getContainerTypes(SnapshotGeneratorFactory.java:308) ~[liquibase-core-3.8.2.jar:na]
at liquibase.snapshot.SnapshotGeneratorFactory.getContainerTypes(SnapshotGeneratorFactory.java:292) ~[liquibase-core-3.8.2.jar:na]
at liquibase.snapshot.SnapshotGeneratorFactory.has(SnapshotGeneratorFactory.java:103) ~[liquibase-core-3.8.2.jar:na]
at liquibase.snapshot.SnapshotGeneratorFactory.hasDatabaseChangeLogLockTable(SnapshotGeneratorFactory.java:281) ~[liquibase-core-3.8.2.jar:na]
at liquibase.lockservice.StandardLockService.hasDatabaseChangeLogLockTable(StandardLockService.java:198) ~[liquibase-core-3.8.2.jar:na]
at liquibase.lockservice.StandardLockService.init(StandardLockService.java:99) ~[liquibase-core-3.8.2.jar:na]
at liquibase.lockservice.StandardLockService.acquireLock(StandardLockService.java:252) ~[liquibase-core-3.8.2.jar:na]
at liquibase.lockservice.StandardLockService.waitForLock(StandardLockService.java:213) ~[liquibase-core-3.8.2.jar:na]
at liquibase.Liquibase.update(Liquibase.java:184) ~[liquibase-core-3.8.2.jar:na]
at liquibase.Liquibase.update(Liquibase.java:179) ~[liquibase-core-3.8.2.jar:na]
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:366) ~[liquibase-core-3.8.2.jar:na]
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:314) ~[liquibase-core-3.8.2.jar:na]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1855) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1792) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
... 17 common frames omitted
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlElement
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583) ~[na:na]
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) ~[na:na]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[na:na]
... 54 common frames omitted
Process finished with exit code 1
I have created an example reproducal repository here that demonstrates the problem. I created the project via start.spring.io and added a changelog.
The same problem is happening on Liquibase 3.8.1. The latest version where this is not the case is Liquibase 3.8.0.
It seems like since 3.8.1 the Liquibase Team changed the way the OSS liquibase-core.jar is packaged. Now this package includes new packages:
com.datical.liquibase.ext
was added in 3.8.1, containing subpackages like appdba, license and storedlogic.liquibase.integration.cdi
was added in 3.8.1, including the cdi META-INF: beans.xml and javax.enterprise.inject.spi.Extension service.liquibase.pro.packaged
was added in 3.8.1, containing what looks like obfuscated code.
This info is coming from the Liquibase CORE-3503.
Not sure what the stance of the Spring Boot team is about this, but I would advise in downgrading the Liquibase managed dependency to 3.8.0, until Liquibase team resolves this problem.
Comment From: wilkinsona
Thanks for the report and problem analysis.
It looks like there's something in Liquibase that is using JAX-B. It's not available by default in Java 9 and later. Please see the Spring Boot wiki for some more information. Adding a dependency on jakarta.xml.bind:jakarta.xml.bind-api
may be sufficient or you may need the full runtime as suggested in the wiki page.
Thanks for the suggestion, but we generally don't downgrade dependencies, particularly when there's a workaround or when the problem should only affect a subset of users. We'll upgrade to any new 3.8.x release of Liquibase in due course.
Comment From: filiphr
Thanks for responding @wilkinsona, but I disagree about the workaround.
Yes the workaround is adding jakarta.xml.bind:jakarta.xml.bind-api
. However, the problem is that it doesn't work out of the box when you add liquibase as a dependency, which is not a good experience for Spring Boot users that want to use Liquibase. My expectation is that if something is recommended (managed dependency by the Spring Boot team) that it would work when I try it out. It does not affect a subset of users, it affects all users that do not use Jakarta XML and use XML.
However, i accept and support the teams decision not to do a downgrade of a dependency.
Comment From: wilkinsona
It does not affect a subset of users, it affects all users that do not use Jakarta XML and use XML.
I don't believe that's true. We have smoke tests that use Liquibase that pass on Java 11. They don't add any extra JAX-B dependencies.
Comment From: filiphr
I don't believe that's true. We have smoke tests that use Liquibase that pass on Java 11. They don't add any extra JAX-B dependencies.
Not sure how your tests look like. I was also surprised. With an integration Junit test works, but running the application fails. Did you have a chance to look at the repository I created?
The test in the repository is green, but I now realized that spring-boot-starter-test
adds jakarta.xml.bind-api
as a dependency. So that's why it is working.
Comment From: MenschNestor
I know this is closed, but I'm pretty sure the issue is related to https://liquibase.jira.com/browse/CORE-3522. I believe Liquibase's packaging to be wrong.
Edit: This may be a different issue after all, but the Liquibase releases from 3.8.1 onwards definitely have packaging issues that have caused problems where none existed before.
Comment From: filiphr
I think you are right @MenschNestor the packaging of Liquibase 3.8.1+ seems to be wrong.
There is also https://liquibase.jira.com/projects/CORE/issues/CORE-3503 which talks about having some CDI classes in the packaging and I also created https://liquibase.jira.com/projects/CORE/issues/CORE-3537 for the Java 11 problems.
I hope that Liquibase would fix this soon. We are currently downgrading to 3.8.0 and we also added a FailureAnalyzer
for our project so that our users know that they would need to downgrade to 3.8.0 as well.
Comment From: alessiostalla
Perhaps JUnit is bringing in those XML dependencies itself. Anyway I think the "correct" dependency is javax.xml.bind:jaxb-api
Comment From: mpretzer
So, I just had some fun with this, too.
Upgraded my Spring Boot app to 2.2.4 and it wouldn't start anymore. Not even issuing the banner. I finally tracked this down to my logback configuration, which includes logstash-logback-encoder, which uses jackson, which fails miserably due to liquibase containing META-INF/services/ as described in the aforementioned liquibase issue, which is still not fixed.
So, please reconsider downgrading until the liquibase people get their s*** together.
Comment From: wilkinsona
Thanks for the suggestion, @mpretzer. Situations like this are never easy to deal with as it isn't possible to please everyone. On the one hand, we will have users who are relying upon a bug fix in the latest 3.8.x release of Liquibase and who are unaffected by the unwanted side-effects. On the other hand, we will have users like you who would prefer to stick with 3.8.0 for the time being. In the absence of a solution that will work for everyone, leaving things as they are feels like the least disruptive option.
For those trying to follow along, there are a few Liquibase issues mentioned above. The one that is tracking the META-INF/services/
problem is CORE-3522.
@SteveDonie please let us know if there's anything that the Spring Boot team can do to help with diagnosing CORE-3522 and how Spring Boot's users are affected.