Existing database types
Well, this might be the biggest advantage of using/hacking the open source projects. You have a chance to see how are things done. This is useful to find your inspiration, the places that require modifications and the hooks to existing system.Classes worth checking for our purposes are in the package:
liquibase.datatype.coreYou can browse them directly on github.
Sample custom BlobType implementation
Let's assume we're about to modify BlobType. Our implementation could look like this:package liquibase.datatype.core; import liquibase.database.Database; import liquibase.database.core.PostgresDatabase; import liquibase.datatype.DataTypeInfo; import liquibase.datatype.DatabaseDataType; import liquibase.datatype.LiquibaseDataType; @DataTypeInfo(name = "blob", aliases = { "longblob", "longvarbinary", "java.sql.Types.BLOB", "java.sql.Types.LONGBLOB", "java.sql.Types.LONGVARBINARY", "java.sql.Types.VARBINARY", "varbinary" }, minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DATABASE) public class BlobTypeTest extends BlobType { public DatabaseDataType toDatabaseDataType(Database database) { // handle the specifics here, you can go for the per DB specifics, let's assume Postgres if (database instanceof PostgresDatabase) { // your custom type here } // use defaults for all the others return super.toDatabaseDataType(database); } }
Specifics to keep in mind
There are some specifics that should be considered:- DataType priority is important
To make sure our type will be considered in favor to default implementation. We're going for:priority = LiquibaseDataType.PRIORITY_DATABASE
where the default one (in the supertype) is:priority = LiquibaseDataType.PRIORITY_DEFAULT
This just means that our implementation should be considered in favor to default one.
See method:liquibase.datatype.DataTypeFactory.register()
implementation for details. - DataType registration considers specific packages to be scanned only
We have more options here, but our stuff should go to any of these:- any of those listed in jar/MANIFEST.MF property:
Liquibase-Package
Where the default set in the liquibase-core-3.0.8.jar is:Liquibase-Package: liquibase.change,liquibase.database,liquibase.parse r,liquibase.precondition,liquibase.datatype,liquibase.serializer,liqu ibase.sqlgenerator,liquibase.executor,liquibase.snapshot,liquibase.lo gging,liquibase.diff,liquibase.structure,liquibase.structurecompare,l iquibase.lockservice,liquibase.ext
- comma separated custom package list provided via system property called:
liquibase.scan.packages
- if all of the above are empty, note the fallback package list is used. As implementation says:
if (packagesToScan.size() == 0) { addPackageToScan("liquibase.change"); addPackageToScan("liquibase.database"); addPackageToScan("liquibase.parser"); addPackageToScan("liquibase.precondition"); addPackageToScan("liquibase.datatype"); addPackageToScan("liquibase.serializer"); addPackageToScan("liquibase.sqlgenerator"); addPackageToScan("liquibase.executor"); addPackageToScan("liquibase.snapshot"); addPackageToScan("liquibase.logging"); addPackageToScan("liquibase.diff"); addPackageToScan("liquibase.structure"); addPackageToScan("liquibase.structurecompare"); addPackageToScan("liquibase.lockservice"); addPackageToScan("liquibase.ext"); }
ServiceLocator.setResourceAccessor()
implementation for details.
Well, as you might have noticed, I'm lazy enough as I went for the already registered package:liquibase.datatype.core
so it worked once my implementation is on the classpath. - any of those listed in jar/MANIFEST.MF property:
Debugging ant task
It's allways good idea to debug once playing around with the custom changes in the 3.rd party code.As I went for ant task, just addopted ANT_OPTS variable. In my case (as I'm on linux) following worked:
export ANT_OPTS="-Xdebug -agentlib:jdwp=transport=dt_socket,server=y,address=8000"remote debugging was possible afterwards.
To check if custom type is registered, check in the debug session the constructor:
DataTypeFactory.DataTypeFactory()local variable "classes" contents after line:
classes = ServiceLocator.getInstance().findClasses(LiquibaseDataType.class);to see all the types found.
That should provide you the basics on liquibase types hacking.