Listeners
Listeners and operations¶
Start with the operation-specific annotations. They remain fully supported in 0.1.8 and now also accept custom filters. The generic listener is explained afterward as an optional alternative.
UponInserting¶
@UponInserting runs a method when an INSERT occurs on the entity table.
@UponInserting(entity = Person.class)
public void onPersonInserted(Person person) {
System.out.println("Inserted: " + person.getEmail());
}
Use cases: run logic after a record is created, send a notification, start a workflow or create an audit record.
Insert with explicit logical name¶
@UponInserting(entity = Person.class, entityName = "Person")
public void onPersonInserted(Person person) {
}
Insert with STRING filter¶
@UponInserting(
entity = Person.class,
field = "email",
valueType = ValueType.STRING,
value = "admin@example.com"
)
public void onAdminInserted(Person person) {
}
Insert with BOOLEAN filter¶
@UponInserting(
entity = User.class,
field = "active",
valueType = ValueType.BOOLEAN,
value = "true"
)
public void onActiveUserInserted(User user) {
}
Insert with numeric filter¶
@UponInserting(
entity = User.class,
field = "level",
valueType = ValueType.LONG,
value = "1"
)
public void onLevelOneUserInserted(User user) {
}
Insert with date filter¶
@UponInserting(
entity = Payment.class,
field = "paymentDate",
valueType = ValueType.DATE,
value = "2026-07-07"
)
public void onPaymentDate(Payment payment) {
}
Insert with excluded columns¶
@UponInserting(
entity = User.class,
exclude = {"password", "token"}
)
public void onUserInserted(User user) {
}
UponUpdating¶
@UponUpdating runs a method when an UPDATE occurs on the entity table.
@UponUpdating(entity = Person.class)
public void onPersonUpdated(Person person) {
System.out.println("Updated: " + person.getEmail());
}
You can also receive the previous record values by adding a second parameter of the same entity type.
@UponUpdating(entity = Person.class)
public void onPersonUpdated(Person newPerson, Person oldPerson) {
}
If you add a third parameter, Tentacolous provides the previous snapshots for that same record, ordered from oldest to newest.
@UponUpdating(entity = Person.class)
public void onPersonUpdated(Person newPerson, Person oldPerson, List<Person> history) {
}
The history parameter can be a List<Person> or Person[]. Tentacolous matches the record by its @Id column when available, otherwise by id.
Use cases: recalculate derived data, invalidate cache, notify other systems or synchronize with an external service.
Update with STRING filter¶
@UponUpdating(
entity = Payment.class,
field = "status",
valueType = ValueType.STRING,
value = "APPROVED"
)
public void onPaymentApproved(Payment payment) {
}
Update with BOOLEAN filter¶
@UponUpdating(
entity = User.class,
field = "enabled",
valueType = ValueType.BOOLEAN,
value = "false"
)
public void onUserDisabled(User user) {
}
Update with DATETIME filter¶
@UponUpdating(
entity = Invoice.class,
field = "paidAt",
valueType = ValueType.DATETIME,
value = "2026-07-07T13:45:00Z"
)
public void onInvoicePaidAt(Invoice invoice) {
}
Update with excluded columns¶
@UponUpdating(
entity = User.class,
exclude = {"password", "refresh_token"}
)
public void onUserUpdated(User user) {
}
Excluded columns are removed from both the new and previous payloads.
UponDeleting¶
@UponDeleting runs a method when a DELETE occurs on the entity table. For a delete, the payload contains the previous values of the record because the row no longer exists after deletion.
@UponDeleting(entity = Person.class)
public void onPersonDeleted(Person person) {
System.out.println("Deleted: " + person.getEmail());
}
You can also receive the previous snapshots for that same record by adding a second parameter.
@UponDeleting(entity = Person.class)
public void onPersonDeleted(Person person, List<Person> history) {
}
The history parameter can be a List<Person> or Person[].
Use cases: clean up external resources, delete related data in another database, notify about deletions or register deletion audit data.
Delete with STRING filter¶
@UponDeleting(
entity = Person.class,
field = "email",
valueType = ValueType.STRING,
value = "admin@example.com"
)
public void onAdminDeleted(Person person) {
}
Delete with UUID filter¶
@UponDeleting(
entity = Session.class,
field = "externalId",
valueType = ValueType.UUID,
value = "550e8400-e29b-41d4-a716-446655440000"
)
public void onSessionDeleted(Session session) {
}
Delete with excluded columns¶
@UponDeleting(
entity = User.class,
exclude = {"password", "token"}
)
public void onUserDeleted(User user) {
}
Generic alternative: TentacolousListener¶
@TentacolousListener is the generic alternative. Its action determines the operation and valid method signature.
@TentacolousListener(entity = Person.class, action = ActionListener.INSERT)
public void onPersonInserted(Person person) {
}
@TentacolousListener(entity = Person.class, action = ActionListener.UPDATE)
public void onPersonUpdated(Person newPerson, Person oldPerson, List<Person> history) {
}
@TentacolousListener(entity = Person.class, action = ActionListener.DELETE)
public void onPersonDeleted(Person person, List<Person> history) {
}
The parameter rules are identical to the corresponding operation-specific annotations.