liquibase / liquibase-hibernate

Liquibase Hibernate Integration
Apache License 2.0
271 stars 157 forks source link

Unable to resolve persistence unit root URL #170

Closed tomaszc closed 2 years ago

tomaszc commented 6 years ago

Hello,

I' struggling with liquibase diff generation on a very simple project which uses newest Spring Boot 1.5.8.RELEASE. I have empty, running database (MariaDB 10.3.2) and a simple domain object. I wan't to generate initial changelog based on this domain

build.gradle:

    ext {
        springBootVersion = '1.5.8.RELEASE'
            lombokVersion = '1.16.18'
            mariadbJdbcVersion = '2.1.2'
    }
    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"

        //GRADLE LIQUIBASE PLUGIN DEPENDENCIES
        classpath "org.springframework:spring-beans:4.3.12.RELEASE"
        classpath "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
            classpath "org.mariadb.jdbc:mariadb-java-client:$mariadbJdbcVersion"
        classpath "org.hibernate:hibernate-core:5.0.12.Final"
        classpath "gradle.plugin.org.liquibase:liquibase-gradle-plugin:1.2.4"
            classpath "org.liquibase:liquibase-core:3.5.3"
        classpath "org.liquibase.ext:liquibase-hibernate5:3.6
    }
}

apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'groovy'
apply plugin: 'org.liquibase.gradle'

jar.baseName = 'myApplication'
group = 'my.group.id'
version = '1.0-SNAPSHOT'
sourceCompatibility = 1.8

dependencies {
    compile "org.springframework.boot:spring-boot-starter:$springBootVersion"
    compile "org.springframework.boot:spring-boot-starter-data-jpa"
    compile "org.projectlombok:lombok:$lombokVersion"

    compile "org.mariadb.jdbc:mariadb-java-client:$mariadbJdbcVersion"
    compile "org.liquibase:liquibase-core:3.5.3"
}

liquibase {
    activities {
        main {
            driver 'org.mariadb.jdbc.Driver'
            url 'jdbc:mariadb://localhost:3306/greeterDB'
            username 'root'
            password 'mariadb_pass'

            changeLogFile 'src/main/resources/db/changelog/changelog-master.xml'

            referenceUrl 'hibernate:spring:my.group.id.persistence.domain?dialect=org.hibernate.dialect.MySQLDialect'
        }
    }
}

Domain object (only one in this package):

package my.group.id.persistence.domain;

import lombok.*;
import javax.persistence.*;

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
@ToString
public class Greeting {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String message;
    private String type;
}

Error during liquibase diff execution:

10:53:20: Executing external task 'diff'...
:diff
liquibase-plugin: Running the 'main' activity...
INFO 11/6/17 10:53 AM: liquibase-hibernate: Reading hibernate configuration hibernate:spring:my.group.id.persistence.domain?dialect=org.hibernate.dialect.MySQLDialect
INFO 11/6/17 10:53 AM: liquibase-hibernate: Found package my.group.id.persistence.domain
Unexpected error running Liquibase: Unable to resolve persistence unit root URL

SEVERE 11/6/17 10:53 AM: 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:127)
    at liquibase.integration.commandline.Main.createReferenceDatabaseFromCommandParams(Main.java:1283)
    at liquibase.integration.commandline.Main.doMigration(Main.java:993)
    at liquibase.integration.commandline.Main.run(Main.java:188)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.invoke(StaticMetaMethodSite.java:46)
    at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.call(StaticMetaMethodSite.java:91)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.liquibase.gradle.LiquibaseTask.runLiquibase(LiquibaseTask.groovy:113)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:384)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:154)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:166)
    at org.liquibase.gradle.LiquibaseTask$_liquibaseAction_closure2.doCall(LiquibaseTask.groovy:56)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
    at groovy.lang.Closure.call(Closure.java:414)
    at groovy.lang.Closure.call(Closure.java:430)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2040)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2025)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2078)
    at org.codehaus.groovy.runtime.dgm$165.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoMetaMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:251)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:71)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.liquibase.gradle.LiquibaseTask.liquibaseAction(LiquibaseTask.groovy:55)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.doExecute(DefaultTaskClassInfoStore.java:142)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:135)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:122)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:762)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:729)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:121)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:110)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
    at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:97)
    at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:87)
    at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:79)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:104)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:98)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:625)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:580)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    at java.lang.Thread.run(Thread.java:748)
Caused by: javax.persistence.PersistenceException: Unable to resolve persistence unit root URL
    at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl(DefaultPersistenceUnitManager.java:605)
    at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.preparePersistenceUnitInfos(DefaultPersistenceUnitManager.java:445)
    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:131)
    at liquibase.database.DatabaseFactory.openDatabase(DatabaseFactory.java:151)
    at liquibase.integration.commandline.CommandLineUtils.createDatabaseObject(CommandLineUtils.java:85)
    ... 96 more
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:187)
    at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl(DefaultPersistenceUnitManager.java:601)
    ... 104 more

For more information, use the --logLevel flag
:diff FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':diff'.
> liquibase.exception.LiquibaseException: Unexpected error running Liquibase: Unable to resolve persistence unit root URL

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

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

BUILD FAILED in 0s
1 actionable task: 1 executed
class path resource [] cannot be resolved to URL because it does not exist
10:53:20: External task execution finished 'diff'.

I know that this issue was mentioned under ticket 68. But I wasn't able to resolve it be altering different hibernate/liquibase/liquibase-ext dependency versions.

┆Issue is synchronized with this Jira Bug by Unito

angrybobcat commented 6 years ago

I am currently running into the exact same issue - did you make any progress in solving it?

tomaszc commented 6 years ago

My solution was to create custom liquibase task. I'll try to provide you with the most important parts of the code, based on this post. Thanks to it I was able to create changelog (by gradle task diffFixedDBvsEntities) from differences between my current database schema and java-domain-entities from 'my.package.with.domain.entities' package:

  1. build.gradle:
buildscript {
    ext {
        springBootVersion = '1.5.8.RELEASE'
            mariadbJdbcVersion = '2.1.2'
                liquibaseVersion = '3.5.3'
    }
    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"

        ...

        //GRADLE LIQUIBASE PLUGIN DEPENDENCIES
            classpath "org.mariadb.jdbc:mariadb-java-client:$mariadbJdbcVersion"
                classpath 'gradle.plugin.org.liquibase:liquibase-gradle-plugin:1.2.4'
                classpath 'org.hibernate:hibernate-core:5.0.12.Final'
                classpath 'org.yaml:snakeyaml:1.17'
    }
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'
...
apply from: 'gradle/liquibase.gradle'

...

dependencies {
    compile "org.springframework.boot:spring-boot-starter"
    compile "org.springframework.boot:spring-boot-starter-data-jpa"
        ...
        compile "org.mariadb.jdbc:mariadb-java-client:$mariadbJdbcVersion"
        ...
        runtime "org.liquibase:liquibase-core:$liquibaseVersion"
}
  1. src/main/resources/application-dev.properties:
spring.datasource.url=jdbc:mariadb://127.0.0.1:3306/myDB
spring.datasource.username=MARIADB_USER
spring.datasource.password=MARIADB_PASS
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver

liquibaseDiff.referenceUrl=hibernate:spring:my.package.with.domain.entities?hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&dialect=org.hibernate.dialect.MySQL5Dialect
  1. gradle/liquibase.gradle:
    
    //retrieve spring datasource properties from application.properties
    def applicationProps = new Properties()
    applicationProps.load(new FileInputStream("src/main/resources/application-dev.properties"))

def dbUsername = applicationProps.getProperty('spring.datasource.username') def dbPassword = applicationProps.getProperty('spring.datasource.password') def dbUrl = applicationProps.getProperty('spring.datasource.url') def dbJdbcDriver = applicationProps.getProperty('spring.datasource.driver-class-name') def liquibaseReferenceURL = applicationProps.getProperty('liquibaseDiff.referenceUrl')

//output files def defaultChangeLogFile = "$projectDir/src/main/resources/db/changelog/db.changelog-master.yaml" def customDiffChangeLogFile = "$projectDir/src/main/resources/db/changelog/db.changeloginitial${new Date().format('yyyyMMdd_HHmmss')}.yaml"

/**

dependencies { liquibase "org.liquibase.ext:liquibase-hibernate5:3.6"

//TODO delete if checked that unused
//liquibase "org.springframework:spring-beans:4.3.12.RELEASE"
//liquibase "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"

}

/**

/**

liquibase { activities { main { driver dbJdbcDriver url dbUrl username dbUsername password dbPassword

        changeLogFile defaultChangeLogFile
    }
}

}

iBluemind commented 6 years ago

This is caused by liquibase-gradle-plugin, not liquibase-hibernate. liquibase-gradle-plugin has a problem related with classpath. https://github.com/liquibase/liquibase-gradle-plugin/issues/10

So for now, you can solve this problem by using classpath variable in activity closure for liquibase block of liquibase-gradle-plugin.

For example, you can modify your liquibase gradle block like below.

liquibase {
    activities {
        main {
            ...
            classpath 'src/main'
            ...
        }
    }
}
stevesaliman commented 6 years ago

Version 2.0 of the Liquibase Gradle plugin changed the way the classpath is set for Liquibase. You can now easily add any artifacts you need with liquibaseRuntime dependencies inside the normal dependencies block of the build.gradle file. That might help with this issue.

stevesaliman commented 6 years ago

It turns out the underlying issue is that the liquibase-gradle-plugin does not assume that you want or need your project's files in the classpath when Liquibase runs. And I'm not sure I want to always assume that for all builds by automatically including project files in the classpath of all Liquibase builds - it seems to only be an issue with Spring Boot projects.

There is a pretty simple workaround: Adding liquibaseRuntime files('src/main') or liquibaseRuntime sourceSets.main.output to your dependencies appears to solve this problem.

SulaymonHursanov commented 5 years ago

I also got this exception and it was solved by compiling project and after generating target folder i started command liquibase diff (i use maven) 1) mvn compile 2) mvn liquibase:diff

eXsio commented 5 years ago

I am also suffering from this issue. I am using maven plugin. Version 3.6 was working correctly (but it had other bugs like index regeneration during diffs). Bumping to 3.7 introduces this error. Can anyone take a look? This bug makes 3.7 pretty much unusable.

Neloop commented 5 years ago

We are facing the same issue on the new 3.7 version... Any idea how to solve this?

szczebel commented 5 years ago

Up. Same issue with 3.7

rfanjul commented 5 years ago

Hello I have the same error with maven, here the config I use

        <profile>
            <id>Liquibase DB Actions</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.liquibase</groupId>
                        <artifactId>liquibase-maven-plugin</artifactId>
                        <version>3.6.3</version>
                        <configuration>
                            <changeLogFile>
                                liquibase/master.xml
                            </changeLogFile>
                            <diffChangeLogFile>
                                src/main/resources/liquibase/changelog/${maven.build.timestamp}_changelog.xml
                            </diffChangeLogFile>
                            <url>jdbc:postgresql://${db.host}:5432/${db.name}</url>
                            <username>${db.username}</username>
                            <password>${db.password}</password>
                            <defaultSchemaName>public</defaultSchemaName>
                            <referenceUrl>
                                hibernate:spring:gara.model.db?hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect&amp;hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&amp;hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
                            </referenceUrl>
                            <verbose>true</verbose>
                            <logging>debug</logging>
                        </configuration>
                        <dependencies>
                            <dependency>
                                <groupId>org.liquibase.ext</groupId>
                                <artifactId>liquibase-hibernate5</artifactId>
                                <version>3.7</version>
                            </dependency>
                            <dependency>
                                <groupId>org.liquibase</groupId>
                                <artifactId>liquibase-core</artifactId>
                                <version>3.6.3</version>
                            </dependency>
                            <dependency>
                                <groupId>org.springframework</groupId>
                                <artifactId>spring-beans</artifactId>
                                <version>${spring.version}</version>
                            </dependency>
                            <dependency>
                                <groupId>org.springframework</groupId>
                                <artifactId>spring-core</artifactId>
                                <version>${spring.version}</version>
                            </dependency>
                            <dependency>
                                <groupId>org.springframework</groupId>
                                <artifactId>spring-orm</artifactId>
                                <version>${spring.version}</version>
                            </dependency>
                            <dependency>
                                <groupId>org.springframework</groupId>
                                <artifactId>spring-context</artifactId>
                                <version>${spring.version}</version>
                            </dependency>
                        </dependencies>
                    </plugin>
                </plugins>
            </build>
        </profile>

Error:

Error setting up or running Liquibase: javax.persistence.PersistenceException: Unable to resolve persistence unit root URL
mboullouz commented 5 years ago

@SulaymonHursanov your solution seems to work for me using maven. also I encountred this when a deleted changeLog file is referenced in the master.xml

Neloop commented 5 years ago

Still not working on version 3.8, mvn compile && mvn liquibase:diff makes no difference, we are still getting aforementioned error... So we have to remain on version 3.6 which works, but lacks some bugfixes which would be nice to have...

mselerin commented 5 years ago

My 2 cents here...

After a lot of debugging, I found that the bug comes from this method : HibernateSpringPackageDatabase.createEntityManagerFactoryBuilder() when initializing the DefaultPersistenceUnitManager.

Before version 3.6.0, no ResourceLoader was given to the DefaultPersistenceUnitManager.

After v3.6.0, with this commit, this line was added :

internalPersistenceUnitManager.setResourceLoader(new DefaultResourceLoader(getHibernateConnection().getResourceAccessor().toClassLoader()));

If I change this line with this, the plugin works again : internalPersistenceUnitManager.setResourceLoader(new DefaultResourceLoader());

Also, while debugging, I found that the ClassLoader given to the PersistenceUnitManager with v3.6+ was a CompositeClassLoader. Before (so, the default one), is a URLClassLoader.

mselerin commented 5 years ago

Some more digging...

The bug occurs inside the DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl() method.

The ResourceLoader tries to get the root URL from the ClassLoader. But, the new given ClassLoader is an instance of CompositeClassLoader which does not implement the getResource() and getResources() methods (they always return null / empty collection).

If I implement those, everything run fine 👌

private static class CompositeClassLoader extends ClassLoader {
    // ...

    @Override
    public URL getResource(String name) {
        for (ClassLoader cl : classLoaders) {
            URL url = cl.getResource(name);
            if (url != null)
                return url;
        }

        // Try with the context class loader associated with the current thread.
        return Thread.currentThread().getContextClassLoader().getResource(name);
    }

    @Override
    public Enumeration<URL> getResources(String name) throws IOException {
        List<URL> urls = new ArrayList<>();

        for (ClassLoader cl : classLoaders) {
            Enumeration<URL> resources = cl.getResources(name);
            while (resources.hasMoreElements()) {
                urls.add(resources.nextElement());
            }
        }

        if (!urls.isEmpty()) {
            return Collections.enumeration(urls);
        }

        // Try with the context class loader associated with the current thread.
        return Thread.currentThread().getContextClassLoader().getResources(name);
    }
}
mohamedzaki90 commented 4 years ago

It turns out the underlying issue is that the liquibase-gradle-plugin does not assume that you want or need your project's files in the classpath when Liquibase runs. And I'm not sure I want to always assume that for all builds by automatically including project files in the classpath of all Liquibase builds - it seems to only be an issue with Spring Boot projects.

There is a pretty simple workaround: Adding liquibaseRuntime files('src/main') or liquibaseRuntime sourceSets.main.output to your dependencies appears to solve this problem.

what is the equivalent fix for maven

sic2 commented 4 years ago

Three years and this is still not solved...how is this possible?

aljazerzen commented 4 years ago

@sic2 I am waiting for this too, but I understand that pace of development correlates with funding of the project.

stevesaliman commented 4 years ago

There is another workaround for Gradle users that may be simpler, depending on your use case. You could add liquibaseRuntime.extendsFrom runtime to your configurations block, or if you don't have a configurations block, add configurations.liquibaseRuntime.extendsFrom configurations.runtime elswwhere in your build.gradle file. This tells Gradle that the liquibaseRuntime configuration should inherit all dependencies from the runtime configuration. This would include all Spring and Hibernate dependencies, the database driver, and project files.

I'm not going to make this the default in the Gradle plugin because In most use cases, Liquibase only needs a database driver and parsing libraries, and I want to keep the classpath clean.

mselerin commented 4 years ago

@sic2 for Maven users, the problem should be fixed soon with this merged PR : https://github.com/liquibase/liquibase/pull/927

mselerin commented 4 years ago

Liquibase 3.8.7 is out. I have tested it in 2 of my projects and the problem seems fixed :-)

vschoener commented 4 years ago

Oh damn, I just merged my task with 3.6 :( I need to do another PR asap and rewrite documentation :P

Thank you !

timbru31 commented 4 years ago

With Liquibase 3.8.7 the issue is solved, too! 🎉

kataggart commented 2 years ago

I am going to close this one out as it appears to be resolved with newer versions of things... if this is not the case, please holler and we can reopen. Many thanks.