Configure resource providers
In May we received request from our friends at Quarkus asking that we allow users more control over how Flyway looks up resources. By resources, we mean things like migrations, callbacks, and so on. They were even kind enough to provide a Pull Request!
The Pull Request was merged, and the changes released in Flyway 6.5. In this blog I’ll explain a bit more about how this new feature works.
Injecting a ResourceProvider
By default, Flyway will use a process of recursive classpath scanning to find resources. Let’s look at a simple programmatic configuration of Flyway:
Flyway flyway = Flyway.configure()
.dataSource("jdbc:h2:mem:db", "sa", "password")
.locations("db/migration")
.load();
flyway.migrate();
locations
is set to a folder, db/migration
. Flyway will perform a recursive scan of this folder to search for the resources it needs to perform the migration.
We’ve now expanded Flyway’s API to allow you override this behavior with custom Java code. You can specify your own override of the ResourceProvider
abstract class, which defines a contract for a class that can supply resources to Flyway.
A simple implementation might look like this:
LoadableResource loadableResource = new LoadableResource() {
@Override
public Reader read() {
try {
return new FileReader("C:\\V1__migration.sql");
} catch (FileNotFoundException e) {
// No op
}
return null;
}
@Override
public String getAbsolutePath() {
return "C:\\V1__migration.sql";
}
@Override
public String getAbsolutePathOnDisk() {
return "C:\\V1__migration.sql";
}
@Override
public String getFilename() {
return "V1__migration.sql";
}
@Override
public String getRelativePath() {
return "V1__migration.sql";
}
};
Flyway flyway = Flyway.configure()
.dataSource("jdbc:h2:mem:db", "sa", "password")
.resourceProvider(new ResourceProvider() {
@Override
public LoadableResource getResource(String name) {
return loadableResource;
}
@Override
public Collection<LoadableResource> getResources(String prefix, String[] suffixes) {
ArrayList<LoadableResource> arr = new ArrayList<>();
arr.add(loadableResource);
return arr;
}
})
.load();
flyway.migrate();
We’ve defined a LoadableResource
object which points to a single migration V1__migration.sql
. We call .resourceProvider
when setting up the configuration to give Flyway a custom ResourceProvider
, which in turn provides a LoadableResource
.
This is a trivial example, but it demonstrates the principle. Given that we allow you to inject a plain Java object there are many possibilities. For instance, you could read resources from a cloud storage provider, parse a bespoke configuration file format, or perhaps even prompt for user input.
Summary
That’s a brief overview of how the new API methods work. This is a fairly advanced feature which is designed to make Flyway more flexible. You can also inject a Java migration resource provider too. You can read more about the API in the documentation.