AfterInsert.Bypassable
Skips a Writer or Dispatcher for the whole chunk when a condition holds, such as a static flag or a custom permission. The handler's other contexts are not affected.
Interface
apex
public class AfterInsert {
public interface Bypassable {
Boolean bypassOnAfterInsertWhen();
}
}bypassOnAfterInsertWhen(): called once per chunk, before parents load; not called when metadata orTriggerOrchestrator.bypass()already skips the handler. Returnstrueto skip this handler for this chunk.
Example
apex
public with sharing class ContactWriter implements AfterInsert.Writer, AfterInsert.Bypassable {
public static Boolean isDisabled = false;
public Boolean bypassOnAfterInsertWhen() {
return ContactWriter.isDisabled;
}
public Boolean writeOnAfterInsertWhen(TriggerHandler.InsertRecord record) {
return record.isNotNull(Contact.AccountId);
}
public void writeOnAfterInsert(TriggerHandler.InsertRecord record, TriggerHandler.UnitOfWork unitOfWork) {
unitOfWork.toInsert(new Task(WhatId = ((Contact) record.getNewSObject()).AccountId, Subject = 'Review contact'));
}
}cls
public with sharing class ContactOwnerAlignmentWriter implements AfterInsert.Writer, AfterInsert.ParentQuery, AfterInsert.Bypassable {
public static Boolean isDisabled = false;
public Map<SObjectField, TriggerHandler.ParentFields> queryParentsOnAfterInsert() {
return new Map<SObjectField, TriggerHandler.ParentFields>{ Contact.AccountId => TriggerHandler.ParentFields.with(Account.OwnerId).with('Owner', User.IsActive) };
}
public Boolean bypassOnAfterInsertWhen() {
return ContactOwnerAlignmentWriter.isDisabled;
}
public Boolean writeOnAfterInsertWhen(TriggerHandler.InsertRecord record) {
Contact contactRecord = (Contact) record.getNewSObject();
Account accountRecord = (Account) record.getNewParent('Account');
return accountRecord?.Owner?.IsActive == true && accountRecord.OwnerId != contactRecord.OwnerId;
}
public void writeOnAfterInsert(TriggerHandler.InsertRecord record, TriggerHandler.UnitOfWork unitOfWork) {
Account accountRecord = (Account) record.getNewParent('Account');
unitOfWork.toUpdate(new Contact(Id = record.getId(), OwnerId = accountRecord.OwnerId));
}
}Good to Know
- Skip single records in the predicate. Bypassable switches off the whole handler.
- Checked before the first handler runs. A flag that an earlier handler sets takes effect from the next chunk.
- Outside the error handling. An exception from
bypassOnAfterInsertWhen()is not logged, ContinueOnError does not apply, and the insert fails. - Static flags last the transaction.
ContactOwnerAlignmentWriter.isDisabled = truestays set for every later chunk and nested save until you reset it. - Class switches miss inner classes.
TriggerOrchestrator.bypass().handler(X.class)and.orchestrator(X.class)do not match an inner class. Use aTriggerHandler__mdtrecord or this interface. See Bypassing.
