liquibase / liquibase-gradle-plugin

A Gradle plugin for Liquibase
Other
197 stars 57 forks source link

Unable to perform diff with Spring Boot #44

Closed Kr0oked closed 5 years ago

Kr0oked commented 5 years ago

build.gradle:

id 'org.liquibase.gradle' version '2.0.0'
liquibaseRuntime('org.liquibase:liquibase-core:3.6.2')
liquibaseRuntime('org.liquibase.ext:liquibase-hibernate5:3.6')
liquibaseRuntime('mysql:mysql-connector-java:5.1.46')
liquibaseRuntime("org.springframework.boot:spring-boot:2.0.1.RELEASE")
liquibaseRuntime('org.springframework:spring-orm:5.0.5.RELEASE')
liquibaseRuntime('javax.validation:validation-api:2.0.1.Final')
liquibase {
    activities {
        main {
            driver 'com.mysql.jdbc.Driver'
            url 'jdbc:mysql://my.company:3306/my_database'
            username 'myUsername'
            password 'myPassword'
            changeLogFile 'src/main/resources/db/changelog/changelog-master.xml'
            referenceUrl 'hibernate:spring:my.company' +
                    '?dialect=org.hibernate.dialect.MySQL5Dialect' +
                    '&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy' +
                    '&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy'
        }
    }
}
18:08:12: Executing task 'diff'...

> Task :diff FAILED
liquibase-plugin: Running the 'main' activity...
Starte Liquibase am Mi, 18 Jul 2018 18:08:13 MESZ (Version 3.6.2, kompiliert am 2018-07-03 11:28:09)
Unerwarteter Fehler bei der Ausführung von Liquibase: Unable to resolve persistence unit root URL
liquibase.exception.DatabaseException: javax.persistence.PersistenceException: Unable to resolve persistence unit root URL
    at liquibase.integration.commandline.CommandLineUtils.createDatabaseObject(CommandLineUtils.java:132)
    at liquibase.integration.commandline.Main.createReferenceDatabaseFromCommandParams(Main.java:1408)
    at liquibase.integration.commandline.Main.doMigration(Main.java:1005)
    at liquibase.integration.commandline.Main.run(Main.java:191)
    at liquibase.integration.commandline.Main.main(Main.java:129)
Caused by: javax.persistence.PersistenceException: Unable to resolve persistence unit root URL
    at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl(DefaultPersistenceUnitManager.java:637)
    at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.preparePersistenceUnitInfos(DefaultPersistenceUnitManager.java:459)
    at liquibase.ext.hibernate.database.HibernateSpringPackageDatabase.createEntityManagerFactory(HibernateSpringPackageDatabase.java:79)
    at liquibase.ext.hibernate.database.HibernateEjb3Database.buildMetadataFromPath(HibernateEjb3Database.java:51)
    at liquibase.ext.hibernate.database.HibernateDatabase.buildMetadata(HibernateDatabase.java:136)
    at liquibase.ext.hibernate.database.HibernateDatabase.setConnection(HibernateDatabase.java:75)
    at liquibase.database.DatabaseFactory.findCorrectDatabaseImplementation(DatabaseFactory.java:129)
    at liquibase.database.DatabaseFactory.openDatabase(DatabaseFactory.java:149)
    at liquibase.integration.commandline.CommandLineUtils.createDatabaseObject(CommandLineUtils.java:97)
    ... 4 common frames omitted
Caused by: java.io.FileNotFoundException: class path resource [] cannot be resolved to URL because it does not exist
    at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:195)
    at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl(DefaultPersistenceUnitManager.java:633)
    ... 12 common frames omitted

Bitte verwenden Sie die '--logLevel'-Option, um mehr Informationen zu erhalten.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':diff'.
> Process 'command '/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.172-9.b11.fc28.x86_64/bin/java'' finished with non-zero exit value 255

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
1 actionable task: 1 executed
Process 'command '/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.172-9.b11.fc28.x86_64/bin/java'' finished with non-zero exit value 255
18:08:13: Task execution finished 'diff'.

This seems to be related to https://github.com/liquibase/liquibase-hibernate/issues/170

I cant find a solution for this problem. Does anybody have a working example with a Spring Boot application?

jebab commented 5 years ago

Hi, is there any news, i have the same issue,

atomfrede commented 5 years ago

You can try to add the compile classpath via liquibaseRuntime sourceSets.main.compileClasspath

Kr0oked commented 5 years ago

Unfortunately adding liquibaseRuntime sourceSets.main.compileClasspath did not resolve the problem. I created a demo project at https://github.com/Kr0oked/spring-liquibase. It contains a dockerfile for a MySQL database to perform the diff against, a Spring Boot application with one entity and a small description how to trigger the issue.

atomfrede commented 5 years ago

@Kr0oked will try to have a look. At least I've integrated the plugin into jhipster lately and it works (checked with postgres) https://github.com/jhipster/generator-jhipster/pull/8171

Ah okay I was thinking of diffChangelog not diff will try it later this day

Not sure, but can it have something to do with lombok maybe?

stevesaliman commented 5 years ago

It looks like the underlying problem is that the project's own files are not part of the classpath when Liquibase itself runs. Adding liquibaseRuntime files('src/main') to your dependencies appears to work around the problem.

The outstanding question for the plugin itself is whether or not I should always include the project's files in the classpath, or if there should be some sort of configuration option to include it. Until then, the workaround is not too bad. I do like the fact that it makes it clear that for your build, you need the project's own files in the classpath when running Liquibase.

Kr0oked commented 5 years ago

Adding liquibaseRuntime files('src/main') did not resolve the problem. But I added liquibaseRuntime sourceSets.main.output which indeed solved the problem! So the following build.gradle works for me:

---

dependencies {

    ---

    liquibaseRuntime 'org.liquibase:liquibase-core:3.6.2'
    liquibaseRuntime 'org.liquibase.ext:liquibase-hibernate5:3.6'
    liquibaseRuntime 'mysql:mysql-connector-java:5.1.46'
    liquibaseRuntime 'org.springframework.boot:spring-boot:2.0.1.RELEASE'
    liquibaseRuntime 'org.springframework:spring-orm:5.0.5.RELEASE'
    liquibaseRuntime sourceSets.main.output
}

diff.dependsOn compileJava
diffChangeLog.dependsOn compileJava

liquibase {
    activities {
        main {
            driver 'com.mysql.jdbc.Driver'
            url 'jdbc:mysql://127.0.0.1:3306/my_database'
            username 'myUsername'
            password 'myPassword'
            changeLogFile 'src/main/resources/db/changelog/changelog-master.xml'
            referenceUrl 'hibernate:spring:de.bobek' +
                    '?dialect=org.hibernate.dialect.MySQL5Dialect' +
                    '&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy' +
                    '&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy'
        }
    }
}

There is a full working example at https://github.com/Kr0oked/spring-liquibase

Maybe this could be a configuration option but as you mentioned it makes clear what is happening in the build.

stevesaliman commented 5 years ago

That's interesting that it didn't work in your situation - I tried it on your spring-liquibase repo, and it appeared to work for me. What platform are you on?

I got the idea for src/main from https://github.com/liquibase/liquibase-hibernate/issues/170 where it was mentioned, but I actually like sourceSets.main.output better, especially if lombok is in the mix. Even better still - if it works - might be sourceSets.main.resources, since I suspect that all you really need are the property files with the database connection information.

Kr0oked commented 5 years ago

I first supspected that I have to use sourceSets.main.output because I make use of Lombok to generate Getters and Setter in the Entities. But I completly removed Lombok and still have to use sourceSets.main.output. I am really confused why files('src/main) is working for you and not for me.

My Platform: OS: Fedora 28 Java: openjdk 1.8.0_181 Gradle Wrapper: 4.8

And sourceSets.main.resouces did not work. I have the "Unable to resolve persistence unit root URL" problem again then. That is because the property files should have nothing to do with this issue. From my understanding liquibase needs two databases for the diff. One database in this case is the MySQL databse from 'jdbc:mysql://127.0.0.1:3306/my_database'. The other database gets provided from Liquibase Hibernate which analyses the javax.persistence annotated classes. The database connection information from the property file should not be involved in this process.

snebjorn commented 5 years ago

I have the same problem-ish.

Adding the line diff.dependsOn compileJava and sourceSets.main.output seems very important.

Thanks @stevesaliman for your gradle file https://github.com/Kr0oked/spring-liquibase/blob/master/build.gradle

However I don't understand the need to have duplicate dependencies, like so

diff.dependsOn compileJava // WTF
dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-data-rest')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('com.oracle.jdbc:ojdbc8:12.2.0.1')

    liquibaseRuntime('org.liquibase:liquibase-core:3.6.2')
    liquibaseRuntime('org.liquibase:liquibase-groovy-dsl:2.0.1')
    liquibaseRuntime('org.liquibase.ext:liquibase-hibernate5:3.6')
    liquibaseRuntime('com.oracle.jdbc:ojdbc8:12.2.0.1') // duplicate
    liquibaseRuntime('org.springframework.boot:spring-boot-starter-data-jpa') // duplicate
    liquibaseRuntime sourceSets.main.output // WTF
}
stevesaliman commented 5 years ago

It's not a duplicate dependency.

the liquibaseRuntime classpath dependency tells the Liquibase plugin that the compile output directory needs to be on the classpath when Liquibase runs.

the diff.dependsOn compileJava task dependency makes sure there is actually something in the output directory by compiling the code before running Lliquibase.

stevesaliman commented 5 years ago

@snebjorn I just realized what you were asking in your last question. I was responding to the "WTF" comments.

The reason for the duplicate dependencies is that the liquibaseRuntime configuration doesn't inherit from the compile configuration.

It might be a good enhancement to change that, but I'd like to give it some thought. On the one hand, it would be nice to avoid the duplication and only add what the project itself didn't nave. On the other, Liquibase won't need most of the dependencies from the project, and why add additional complexity to the Liquibase runtime environment?

snebjorn commented 5 years ago

I usually favor simple setup and simple usage, because well it's just easier :D

If it wasn't because Flyway is a paided solution I would have given up and tried that instead. So in theory it would attract more users to the product :)

jozefmorvay commented 5 years ago

@Kr0oked and @stevesaliman , which java do you use? On 11 when running liquibase diff gradle task, I'm getting:

Task :diff liquibase-plugin: Running the 'main' activity... Starting Liquibase at Tue, 27 Nov 2018 10:39:13 CET (version 3.6.2 built at 2018-07-03 11:28:09) Unexpected error running Liquibase: URI is not hierarchical java.lang.IllegalArgumentException: URI is not hierarchical at java.base/java.io.File.(File.java:418) at liquibase.resource.FileSystemResourceAccessor.addRootPath(FileSystemResourceAccessor.java:51) at liquibase.resource.AbstractResourceAccessor.init(AbstractResourceAccessor.java:39) at liquibase.resource.FileSystemResourceAccessor.init(FileSystemResourceAccessor.java:44) at liquibase.resource.FileSystemResourceAccessor.(FileSystemResourceAccessor.java:26) at liquibase.integration.commandline.Main.doMigration(Main.java:949) at liquibase.integration.commandline.Main.run(Main.java:191) at liquibase.integration.commandline.Main.main(Main.java:129)

Kr0oked commented 5 years ago

@jozefmorvay , I have the same issue when using Java 11. The uri which causes the exception is:jar:file:/home/pbobek/.gradle/caches/modules-2/files-2.1/javax.xml.bind/jaxb-api/2.3.1/8531ad5ac454cc2deb9d4d32c40c4d7451939b5d/jaxb-api-2.3.1.jar!/META-INF/versions/9/ I had to add javax.xml.bind:jaxb-api as liquibaseRuntime dependency to get to this point since the JAXB APIs got removed in Java 11.

I would suggest to open a new issue.

jozefmorvay commented 5 years ago

@Kr0oked I can open the new issue, but this project appears to be dead anyway. I do not have JAXB as liquibaseRuntime dependency, how come I reached the same error as you did?

Kr0oked commented 5 years ago

@jozefmorvay It seems only my project depends on the JAB API. Not sure which uri causes the issue in your project. I created a branch in my Demo project which describes how to reproduce the issue Spring Liquibase Demo. I would still recommend opening a new issue. The last release of this project was four days ago, so I don't think you can call it dead.

stevesaliman commented 5 years ago

The suggestion that this project is dead sure was a news to me :smiley:

I looked into it a little bit, and it definitely appears to be something with the JAXP dependency - maybe it is not ready for Java 11

It turns out there is already an issue (CORE-3262) logged against Liquiabse itself for this problem, so I doubt there is much I can do in the plugin to resolve it. Either Jaxb will fix the way it works, or Liquibase will change the way it tries to load dependencies.

Either way, I'd recommend moving it to a new issue, since this is not related to the original diff task problem,

jozefmorvay commented 5 years ago

@Kr0oked @stevesaliman The notion of this project being dead comes from some other thread, I just picked up on it. Glad to see it was not true :) so i read the liquibase issue, and the fix is now merged into master, but it is not in any hotfix release yet. Not sure if it makes sense for me to create a new issue when this is not a plugin problem.

jozefmorvay commented 5 years ago

@Kr0oked so you got it to actually work on JDK11 by including that dependency? Anyway, opened #54

Kr0oked commented 5 years ago

@jozefmorvay No, I had to add that dependency when upgrading to Java 11. Then I got the same error as you (URI is not hierarchical exception). And the URI that causes this exception is jar:file:/home/pbobek/.gradle/caches/modules-2/files-2.1/javax.xml.bind/jaxb-api/2.3.1/8531ad5ac454cc2deb9d4d32c40c4d7451939b5d/jaxb-api-2.3.1.jar!/META-INF/versions/9/. So it is kind of related to that dependency.

Kr0oked commented 5 years ago

@jozefmorvay For your information there is a Liquibase ticket regarding Java 11 compatibility: CORE-3362

kamenov commented 5 years ago

I know this issue is closed but I'm adding this comment to help others looking for a solution because in my case (Java 8, gradle 5.4.1 , spring boot 2.1.5, Hibernate5, liquibase-core 3.6.3, liquibase-hibernate 3.7) the suggested liquibaseRuntime sourceSets.main.output was causing my project classes to throw

liquibase.exception.DatabaseException: org.hibernate.boot.registry.classloading.spi.ClassLoadingException: Unable to load class [com...truncated...Role]
... stack frames removed ...
Caused by: java.lang.ClassNotFoundException: Could not load requested class

exception but adding liquibaseRuntime files('src/main/java') resolved the issue.

UPDATE: liquibaseRuntime files('src/main/java') doesn't help because the diff runs successfully but actually wants to drop all objects in the database because obviously doesn't find the project classes (the compiled ones in build/classes/java/main ).

UPDATE 2: tried all the suggestions here with changing liquibase and ext.hibernate versions up and down without success. @stevesaliman will open a new issue as I've been fighting this for 3 days already.