liquibase.change.Change implementations are the objects created from database change log files. Each Change generates a series of SqlStatements from a set of inputs. Create new Change implementations when you want to create a new high-level database change you want to make available to end users.
- You want to simulate identity fields in Oracle, so you create a Change to create a sequence and set an insert trigger using a single tag in your changelog.
How to Create
To create a new Change class, implement the liquibase.change.Change interface directly, or extend the liquibase.change.AbstractChange_ class.
When extending AbstractChange, the only methods you need to implement are:
public SqlStatement generateStatements(Database database)
in which you return an array of SqlStatements that should be executed, and
public String getConfirmationMessage()
which returns a message to output when the change executes successfully.
If your Change implementation requires custom properties to be set (tableName, etc.), simply add them as private variables. The change log parser(s) will use reflection to set them, so get/set methods are not required. If you wish to control the serialization/deserialization process, you can annotate your propeties with the liquibase.change.ChangeProperty annotation. By default, any property found is serialized and deserialized according to the property's name.
Additional methods available for override on liquibase.change.Change
The following methods are optional if extending AbstractChange, but depending on what you are implementing you may wish to override them. If you are implementing liquibase.change.Change directly, they must be implemented.
public ChangeMetaData getChangeMetaData();
Returns a ChangeMetaData object describing the command name (used by change log parsers), description, and priority of this Change implementation. AbstractChange returns values passed into its constructor.
public void init() throws SetupException
Called by Liquibase after all properties are set. AbstractChange implements this as a no-op.
boolean supports(Database database);
Does the Change support the passed database? AbstractChange checks the supports method on all the SqlStatements returned by generateStatements().
public ValidationErrors validate(Database database);
Are the properties set on the Change valid? AbstractChange checks the validate method on all the SqlStatements returned by generateStatements().
public Set<DatabaseObject> getAffectedDatabaseObjects(Database database);
What database objects are affected by this change. Used for dbdoc command. AbstractChange checks the validate method on all the SqlStatements returned by generateStatements().
public CheckSum generateCheckSum();
Generates a checksum for the change. AbstractChange uses liquibase.parser.string.StringChangeLogSerializer to generate a standarized representation of the change, and creates an MD5Sum hash.
public boolean supportsRollback(Database database);
Does the Change support rollback? AbstractChange returns true if the AbstractChange-specific createInverses() method returns a non-null value.
public SqlStatement generateRollbackStatements(Database database) throws UnsupportedChangeException, RollbackImpossibleException;
Generates statement to execute if a rollback is requested. AbstractChange calls the AbstractChange-specific generateRollbackStatementsFromInverse method.
AbstractChange convenience methods to override
protected Change createInverses()
Generates Change objects that are the opposite of the given Change. Used by supportsRollback and generateRollbackStatements. AbstractChange returns null.
Registering Custom Change implementations
There are two ways to register a custom Change:
- Create the class in the package "liquibase.change.ext". Liquibase automatically registers Change implementations it finds in that package
- Call liquibase.change.ChangeFactory.getInstance().register(YourChange.class)
Threading/Singleton and Implementation notes
Change implementations do not need to be thread safe. ChangeFactory will generate a new instance of them each time they are used. Since new instances are created on each use, there must be a no-arg constructor that will be called.