Calling java from liquibase

The requirement is to call a java program from liquibase and pass the value obtained from java to placeholders present in liquibase sql scripts.

I’m using liquibase-core 4.28.0 and liquibase-maven-plugin 4.28.0

Here’s the sample project structure and changes which i have tried after researching.
Liquibase
│ liquibase.properties
│ pom.xml
├───src
├───main
├───java
│ └───com
│ └───example
│ LiquibaseCustomTask.java
│ RandomStringGenerator.java

└───resources
└───db
changelog.yml
insert_data.sql

In changelog.yml I’m using

    - customChange:
        class: com.example.LiquibaseCustomTask

Using cmd mvn liquibase:update

This calls my java file succesfully.

LiquibaseCustomTask.java this class implements CustomTaskChange provided by the liquibase.

public class LiquibaseCustomTask1 extends AbstractChange implements CustomTaskChange {

public void execute(Database database) throws CustomChangeException {

RandomStringGenerator gen = new RandomStringGenerator();
String randomString = gen.generate(20);
Liquibase liquibase = new Liquibase(“db/changelog/changelog.yml”,new ClassLoaderResourceAccessor(getClass().getClassLoader()), database);
liquibase.setChangeLogParameter(“randomString”, randomString);
liquibase.update();
}

This approach didn’t works as this liquibase.update tries to run the liquibase again and goes into stack overflow.
I’ve also tried with CommandScope approach but still the output is same.

Can someone explain me how to achieve this requirement?

Yes, this code will cause an infinite recursion, as it will just keep running liquibase update.

To make sure, you are wanting to shell out to execute a Java program to get your property values?

@wwillard Yes, I want to execute a java program that generates some value and pass it back to liquibase. I’m able to call the java program using customChange tag from liquibase but the generated value from java I’m unable to pass it back to liquibase as a property, so that this value can be passed to the placeholders in liquibase sql scripts.

You need to pull the call to liquibase.update out of the custom task execute method. That call should be made from a higher level , such as your main program, or somewhere like that. All you need to have in your execute method is your call to execute the Java program.

As for returning values, one strategy would be to write your replacement properties to STDOUT, and then capture that output when you invoke the Java program. You can then put those properties in the ChangeLogParameters object that is associated with your DatabaseChangeLog object. You can then access them back in your calling logic.