liquibase.snapshot.SnapshotGenerator
Overview
liquibase.snapshot.SnapshotGenerator
implementations define how to convert the "describe what you want to snapshot, not how to do it" requests
into the driver calls and queries your database understands.
Liquibase defines a database-independent metadata model in liquibase.snapshot.DatabaseSnapshot. That model contains standardized liquibase.structure.DatabaseObject objects such as liquibase.structure.core.Table.
The snapshot logic used in liquibase snapshot
, liquibase diff
, liquibase diff-changelog
, and any other "check the current database structure" operations rely on liquibase.snapshot.SnapshotGenerator
implementations to read the database's metadata and create the corresponding DatabaseObject
objects.
sequenceDiagram
participant DatabaseSnapshot
participant SnapshotFactory
participant SnapshotGenerator
participant Database
DatabaseSnapshot->>SnapshotFactory: Snapshot the DatabaseObjects
SnapshotFactory->>SnapshotGenerator: Snapshot a particular type
SnapshotGenerator->>Database: Executes Query
SnapshotGenerator-->>DatabaseSnapshot: Returns DatabaseObject
Tip
The default SnapshotGenerators for a given DatabaseObject are named by adding "SnapshotGenerator" to the DatabaseObject's class name. For example, Column -> ColumnSnapshotGenerator.
For SnapshotGenerators that handle specific environments, append a description of what makes it different to the end. For example, ColumnSnapshotGenerator -> ColumnSnapshotGeneratorOracle
SnapshotGenerator Selection
The getPriority
logic works a bit differently from other interfaces in that it's not used to choose the single "best" implementation to use, but rather to choose the order to run SnapshotGenerators.
Like other getPriority methods, if the implementation does not apply to the given type/database combination, it should return liquibase.snapshot.PRIORITY_NONE
.
However, Liquibase will use ALL instances that return a priority > 0 to snapshot an object.
Therefore, if an implementation is replacing a base SnapshotGenerator it must override the replaces()
function rather than returning a higher value from getPriority()
.
The replaces()
function lets it define "use this class in the snapshot logic instead of another one".
A good example implementation for a class that replaces the default ColumnSnapshotGenerator is
@Override
public int getPriority(Class<? extends DatabaseObject> objectType, Database database) {
if (database instanceof ExampleDatabase) {
return super.getPriority(objectType, database);
} else {
return PRIORITY_NONE;
}
}
@Override
public Class<? extends SnapshotGenerator>[] replaces() {
return new Class[] {
ColumnSnapshotGenerator.class
};
}
which relies on the superclass's "should I be part of the snapshot process for the given type" logic but only for ExampleDatabase while also taking the place of ColumnSnapshotGenerator when it's used.
API Highlights
Auto-Registration
SnapshotGenerators are dynamically discovered, so must have a no-arg constructor and be registered in the META-INF/services/liquibase.snapshot.SnapshotGenerator
file.
getPriority and replaces
Used in selecting the instance(s) to use
snapshot()
This is the method that is called by the snapshot system to either look up the information about the given example
object, OR add additional information to it.
Multiple SnapshotGenerator instances will work together to build up the final snapshot of the object.
The overall flow is:
1. The calling code defines the "example" object it wants.
Example
If they want to snapshot a Table with the name "address" they construct a liquibase.structure.core.Table
object and set the name to "address".
To look up the table in a different schema, they set the schema attribute on Table to the desired schema.
The "example" object will contain the fields set that should be used to identify the actual object to snapshot.
2. The snapshot system will collect all the SnapshotGenerators that say they should participate in the snapshot and call the snapshot
method in getPriority()
order.
Example
When snapshotting an example Table, the TableSnapshotGenerator.snapshot()
call will run first which captures the table name, schema, etc.
Then the ColumnSnapshotGenerator.snapshot() will run which snapshots all the columns associated with the table and adds those columns to the Table object.
3. After all the SnapshotGenerators have added their information to the Table object, it's returned to the calling code.
API Details
The complete javadocs for liquibase.snapshot.SnapshotGenerator
is available at https://javadocs.liquibase.com
Extension Guides
The following guides provide relevant examples: