Annotation Interface OnSchemaChange
The annotated method is given access to all of the previous object version's fields, including fields that have been deleted or whose types have changed in the new schema. This allows the object to perform any schema migration "fixups" that may be required before the old information is lost for good.
Simple changes that only modify a simple field's type can often be handled automatically; see
UpgradeConversionPolicy
, @PermazenField.upgradeConversion()
,
and Encoding.convert()
for details.
The annotated method must be an instance method (i.e., not static), return void, and take from one to three parameters.
The first parameter must have type Map<String, Object> oldValues
and will be an immutable map containing the values
of all the fields in the previous schema version of the object indexed by field name. The optional second and third
parameters have type SchemaId
and identify the old and new schemas (respectively).
In many cases, the simplest way to handle schema changes is to use the presence or absence of fields in oldValues
to determine what migration work needs to be done. For example:
@OnSchemaChange
private void applySchemaChanges(Map<String, Object> oldValues) {
// At some point we added a new field "balance"
if (!oldValues.containsKey("balance"))
this.setBalance(this.calculateBalanceForSchemaMigration());
// At some point we replaced "fullName" with "lastName" & "firstName"
if (oldValues.containsKey("fullName")) {
final String fullName = (String)oldValues.get("fullName");
if (fullName != null) {
final int comma = fullName.indexOf(',');
this.setLastName(comma == -1 ? null : fullName.substring(0, comma));
this.setFirstName(fullName.substring(comma + 1).trim());
}
}
// ...etc
}
Note: PermazenCounterField values are represented in oldValues
as Long
s.
A class may have multiple @OnSchemaChange
-annotated methods.
Incompatible Object Type Changes
Permazen supports arbitrary Java model schema changes across schemas, including adding and removing Java types. This creates a few caveats relating to schema migration.
First, if an object's type no longer exists in the new schema, migration is not possible, and any attempt to do so will
throw a TypeNotInSchemaException
. Such objects are still accessible however (see UntypedPermazenObject
).
Secondly, it's possible for an old field to have a value whose type simply doesn't exist in the new schema. When this happens,
it's not possible to provide the old value to an @OnSchemaChange
method in its original form.
This can happen in two ways:
- A reference field refers to an object whose type no longer exists in the new schema; or
- An
Enum
field refers to anEnum
type that no longer exists, or whose identifiers have changed (this is really just a special case of the previous scenario: when anEnum
type's constants change in any way, the newEnum
is treated as a completely new type).
Therefore, the following special rules apply to the oldValues
map:
- For a reference field whose type no longer exists, the referenced object will appear as an
UntypedPermazenObject
. - For
Enum
fields, old values are always represented asEnumValue
objects. For consistency's sake, this is true even if the associated field's type has not changed.
Meta-Annotations
This annotation may be configured indirectly as a Spring
meta-annotation
when spring-core
is on the classpath.