Liquibase databasechangelog table stores relative path if run spring boot and let liquibase do the migration automatically - spring-boot

I know that liquibase will create a databasechangelog to check if one change set has been applied. But if i let the app to run it automatically, the FILENAME column will store the relative path of the changelog file. But if I run mvn liquibase:status, it said my change set had not been applied, the cause is that in liquibase.properties file I defined the path of the changelog as absolute path (i.e changeLogFile=src/main/resources/db/changelog/db-changeLog-master.xml) while for spring boot app automatic migration the path was defined as relative path (spring.liquibase.change-log=classpath:db/changelog/db-changeLog-master.xml) in application.properties file and "db/changelog/db-changeLog-master.xml" was stored in the database. If you do it manually (by running mvn liquibase:update), "src/main/resources/db/changelog/db-changeLog-master.xml" would be stored instead.
How could I solve this problem? Since I wanna have control over the migration (i.e. do the migration manually) or check the status of migration in development environment.

after I changed the property: changeLogFile=/db/changelog/db-changeLog-master.xml, in liquibase.properties, mvn command works as expected: now liquibase consider the path of my changelog to be "db/changelog/db-changeLog-master.xml"

Related

Specifying files by absolute path was removed in Liquibase 4.0

I am getting the following liquibase error when I run my Spring Boot application:
Specifying files by absolute path was removed in Liquibase 4.0. Please use a relative path or add '/' to the classpath parameter.
Here is the class path in application.yaml:
liquibase:
change-log: classpath:db/changelog/db-changelog-master.xml
I also tried:
liquibase:
change-log: classpath:/db/changelog/db-changelog-master.xml
Here is folder structure:
Changlog master:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="db-changelog-1.0.xml"/>
</databaseChangeLog>
I got this issue when putting the changelog files outside the resources folder, but if I include them under resources/db/changelog, then it would work fine with setting the bellow config.
spring.liquibase.change-log=classpath:/db/changelog/changelog-master.xml
Tested under 4.6.2
This is still an open issue unfortunately. See 2281.
Looks like this was fixed in v4.4.3
As explained here
How the Liquibase classpath worked before version 4.0
Before version 4.0, one of the default locations Liquibase added to
the classpath was the root directory in your filesystem (/). The
change caused issues because of a machine-dependent changelog path,
such as /home/my-user/projects/liquibase/changelog.xml, found under
the / directory. This way, Liquibase uses the given path as part of
the changeset identifier stored in the DATABASECHANGELOG table, and
when you run Liquibase from
/home/other-user/projects/liquibase/changelog.xml, Liquibase sees it
as a different changelog and tries to rerun all the previously run
changesets.
To prevent identification issues from happening, a / was removed as a
default part of the classpath. How the Liquibase classpath works in
4.0 and later versions
Starting with Liquibase 4.0, the root directory (/) is no longer a
default part of the classpath because of the issue mentioned in the
previous section.
...
The message "Please use a relative path or add '/' to the classpath parameter." refers to the root directory '/', and does not mean to add a slash to the start of your classpath path. Afaik, classpath:x and classpath:/x are the same.
Also, the message appears when the master changelog is not found, for whatever reason, so also a typo can cause this message. It's only a hint telling you that it might not be found because the file is not on the classpath, because they removed the root directory from the classpath, but it could also not be found because you specified the wrong path (I just did that).
To configure it correctly, the master changelog must be on the Liquibase classpath. In Spring Boot, the Liquibase classpath is set to the application's classpath, i.e. you can use src/main/resources.
Tl;dr: When your file is src/main/resources/db/changelog/db.changelog-master.xml use
spring.liquibase.change-log=classpath:/db/changelog/db.changelog-master.xml
I don't know, whether there was or is a bug in regards to that with certain Liquibase versions, but that's how it's supposed to work, anyway.
Just try to remove "classpath:" from "change-log:" parameter.
Also try to check your pom.xml ("changeLogFile" tag in configuration):
there should not be a "${basedir}" before change log file path.
<changeLogFile>
/src/main/resources/liquibase/changelog.xml
</changeLogFile>

Spring boot external properties not working

My project structure looks like as attached file. Even though I have profile specific properties, I would like to run my app with external properties file i.e., outside of jar file.
I tried with following command:
java -jar test_service.jar --spring.config.location=file:///C:/external_props/test.properties
But its taking application-default.properties file.
from log file:
No active profile set, falling back to default profiles: default
Why it is not taking external properties file ?
When you pass --spring.config.location command line argument SpringBoot won't consider application-*.properties files in src/main/resources directory. The filename you mentioned for --spring.config.location is taken as base filename, in your case test. So, it will only load test.properties file from that path you provided as default profile.
If you want to enable certain profile, say prod, you need to create file C:/external_props/application-prod.properties and enable prod profile using --spring.profiles.active=prod.
Spring will automatically look for some property file in a specific location.
From where you execute the jar file, Spring will look in that directory for a property file called application.properties
An other way is to put a config directory in the directory you execute the jar from and put the application properties in there.
There is one more option and that is the -Dspring.profiles.active={profiles} parameter.
Spring will then look in the directory or config directory to application-{profile}.properties
Reference:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Also i think you use the
--spring.config.location=file:///C:/external_props/test.properties
is not used correctly for a windows based file path.
Windows uses the \ instead of the /.

Dynamically get JAR filename in DockerFile

I am new to Docker. I am using spring boot and when we build the project using maven, it will create jar file like app-.jar and then I am coping this jar file using ADD command in DockerFile. Now If I change the version number in pom.xml, then I need to manually update the JAR file name in DockerFile.
Is there anyway by which I can dynamically get the version number which is in the pom.xml and update the JAR file name automatically in the DockerFile?
Instead of copying the jar file inside the dockerfile, you can mount the folder in which jar is created. And you will not be needed to be worried with the filename.
What you want can be done using environment variables. You can create an --env-file and keep your version number there. And inside dockerfile, refer to value of variable declared in env file with {VERSIION}. By following this process, you may want to use this same version in your pom file. For that, take a look at this question.
The answer links environment variables by setting env.path and detailed guide is here.

Are spring-boot command line properties available when using spring-boot:run?

The short question:
How can you configure environment profiles, or even just an alternative configuration file name for
spring-boot:run?
The long version:
Yes, I read the doc. http://docs.spring.io/spring-boot/docs/current/reference/html/index.html
I have my application configuration settings in src/main/resources/application-mysql.properties:
# Specify the DBMS
spring.jpa.database = MYSQL
# Other Mysql config properties
spring.jpa.hibernate.ddl-auto=create
There is a corresponding application-hsql.properties, which contains the same set of configuration options for Hsql.
There is no application.poperties
There is a corresponding import.sql:
insert into users(name, email) values ('User One', 'one#email.com')
insert into users(name, email) values ('Two User', 'two#email.com')
The unit tests exist only to check for the presence of these users in the repo.
I believe it to be true that whenever the test is run using the MySql configuration, those rows are added to the users table. When the test is run with hsql, the mysql db should be unaffected.
I am manually dropping the users table between runs, because I want to manually see when it exists.
1) If I run mvn test, the tests use the configured db:
mvn -Dspring.profiles.active=mysql clean test
Produces mysql database rows and
mvn -Dspring.profiles.active=hsql clean test
Does not.
2) If I make a package, and then run the resulting jar file, I am able to specify a config file name:
java -jar -Dspring.profiles.active=mysql ./target/app.jar
3) If I run with spring-boot:run, only properties in application.properties (which doesn't exist in this test scenario) are discovered.
mvn -Dspring.profiles.active=mysql clean spring-boot:run
What does spring-boot:run do differently in launching than running unit tests and kicking off the jar? The db config is one example, but in theory I'd like to be able to specify a set of dev configs when the application is being run locally vs. a production configuration.
The Maven spring-boot plugin forks a new process so you'll need to send any extra parameters to it via jvmArguments, e.g.:
mvn spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=mysql"
The plugin allows you to specify the active profile(s) directly (perhaps it wasn't the case 3 year ago?) :
mvn spring-boot:run -Drun.profiles=mysql

How to configure relative datasource file for SQLite?

I'm trying to configure a SQLite database for an Spring Web App. The thing is that I'm not able to reach the database file that I've created in src/main/resources using a relative path.
I've tried several configurations for the jdbc url but none of them worked:
jdbc:sqlite:mydb.sqlite (here I changed the file location to the project root)
jdbc:sqlite:${jdbc.url} (here I passed the url as a parameter thru PropertyPlaceholderConfigurer)
jdbc:sqlite:src/main/resources/mydb.sqlite
A weird thing that I realized about is that the app is using Eclipse's directory as the directory to find the database file. I mean, when I put jdbc:sqlite:mydb.sqlite it creates an mydb.sqlite on Eclipse's directory not in project's root.
Check the JVM system property named "user.dir" and set the path relative to it. It is the "current dir" of your java app. It can be different if you run from eclipse or from cmd line or inside webserver(tomcat).
So, System.getPropery("user.dir") will tell you current dir of your running app. Set the path to db relative to that directory.
I would say eclipse does not run your app from the project dir, as it should by default. Check your "run" settings in the eclipse.

Resources