Skip to content

BeforeUpdate.Bypassable

Skips a Populator or Validator for the whole chunk when a condition holds, such as a static flag or a custom permission.

Interface

apex
public class BeforeUpdate {
    public interface Bypassable {
        Boolean bypassOnBeforeUpdateWhen();
    }
}
  • bypassOnBeforeUpdateWhen(): called once per chunk, before parents load; not called when metadata or TriggerOrchestrator.bypass() already skips the handler. Returns true to skip this handler for this chunk.

Example

apex
public with sharing class ContactPopulator implements BeforeUpdate.Populator, BeforeUpdate.Bypassable {
    public static Boolean isDisabled = false;

    public Boolean bypassOnBeforeUpdateWhen() {
        return ContactPopulator.isDisabled;
    }

    public Boolean populateOnBeforeUpdateWhen(TriggerHandler.UpdateRecord record) {
        return record.isChanged(Contact.Email);
    }

    public void populateOnBeforeUpdate(TriggerHandler.UpdateRecord record) {
        record.put(Contact.HasOptedOutOfEmail, false);
    }
}
cls
public with sharing class OpportunityReopenValidator implements BeforeUpdate.Validator, BeforeUpdate.Bypassable {
    public static Boolean isBypassed = false;

    public Boolean bypassOnBeforeUpdateWhen() {
        return isBypassed;
    }

    public Boolean errorShouldBeAttachedOnBeforeUpdateWhen(TriggerHandler.UpdateRecord record) {
        return record.isChangedFrom(Opportunity.StageName, 'Closed Won');
    }

    public void addErrorOnBeforeUpdate(TriggerHandler.RejectableUpdateRecord record) {
        Opportunity newOpportunity = (Opportunity) record.getNewSObject();

        record.addError(
            Opportunity.StageName,
            'A Closed Won Opportunity cannot be moved back to ' + newOpportunity.StageName + '. Raise a new Opportunity for the follow-up business.'
        );
    }
}

Good to Know

  • Not per record. To skip only some records, return false from the predicate.
  • Reset a static flag in finally. The flag stays set for every chunk and every nested update in the transaction.
  • Exceptions here are not logged. bypassOnBeforeUpdateWhen() runs outside the handler's error handling. ContinueOnError does not apply, and the update fails.
  • Only this context. A TriggerHandler__mdt row or TriggerOrchestrator.bypass().handler(X.class) switches the class off in every context. This add-on skips only before update.
  • Inner classes need this add-on. TriggerOrchestrator.bypass().handler(X.class) and .orchestrator(X.class) never match an inner class. Use a TriggerHandler__mdt row or this add-on.