[SalesForce] Custom exception thrown

I'm learning the APEX world (coming from the .NET world).

Defined a custom exception.

In a method (say A()) i'm using a try catch block in which, i 'm calling another method of another class (say Classname2.B() ).

In this Classname2.B() i 'm throwing the public defined Exception.

This does not get caught!!

If instead i throw the exception in the try catch block, then the exception gets caught! What do i miss? Shouldn't this work also in APEX (like in the .NET world)?

public class SomeClass {
    public void A() {
        try {
        //...
            Classname.B(); //<- doesn't work
            throw new CustomException();//<-works
        //...
        }
        catch(CustomException ex) {}
    }
}


public class Classname {
    //...
    void B() {
    //....
        throw new CustomException();
    //...
    }
}

EDIT: Here is the actual code (which is stripped down to only the relevant parts).

The trigger looks like this:

trigger Expenses on Expense__c (before insert, before update) {
    if(Trigger.isBefore && (Trigger.isUpdate  || Trigger.isInsert)) {
        Travel__c travel = getTravel(); 
        ExpensesTriggerHandler.onBeforeInsertOrUpdate(trigger.new, travel);
    }
}

The ExpensesTriggerHandler looks like this:

public with sharing class ExpensesTriggerHandler {

    public static void onBeforeInsertOrUpdate(List<Expense__c> newExpenses, Travel__c travel) {
        ExpenseValidator.validate(newExpenses, travel);
    }

}

The ExpenseValidator looks like this:

public with sharing class ExpenseValidator {

    private static List<ExpenseRule> rules;

    static {
        rules = new List<ExpenseRule>();

        for(ApexClass clazz : [SELECT NamespacePrefix, Name FROM ApexClass WHERE isValid = true]) {
            Type t = Type.forName(clazz.NamespacePrefix, clazz.Name);

            try {
                ExpenseRule rule = (ExpenseRule) t.newInstance();
                rules.add(rule);
            }
            catch(Exception ignored) {}
        }
    }


    public static void validate(List<Expense__c> expenses, Travel__c travel) {

        for(ExpenseRule rule : rules) {

            for(Expense__c expense : expenses) {
                rule.validate(expense);
            }
        }
    }

}

One of the classes implementing the ExpenseRule Interface is the following (from which the exception gets thrown):

public with sharing class ExpenseCannotEndBeforeStartRule implements ExpenseRule {

    private final static String ERROR_MESSAGE = 'Expense begins after end.';

    public void validate(Expense__c expense) {
        if (expense.dtm_DepartureTime__c > expense.dtm_ArrivalTime__c){
            throw new ExpenseValidationException(ERROR_MESSAGE);
        }
    }

}

Best Answer

It should work exactly as in .NET, you should be able to catch any exception besides limit and fatal exceptions. I tried to reproduce your scenario and it behaves as I'd expect.

public class Exceptions{
      public class TestException extends Exception{}
}

public class testRND{
     //your Classname.B method
     public static void throwException(){
          throw new Exceptions.TestException('test..');
     }
}

public class testRND_two{
      //your Someclass.A method
      public void replicateExceptionQ(){
            try{

                 //sc1:
                 system.debug('------------>SC1');
                 testRND.throwException();

                 /*
                 //sc2:
                 system.debug('------------>SC2');
                 throw new Exceptions.TestException('blablabla');
                 */
           }catch(Exceptions.TestException x){
                System.debug('----------------------->CAUGHT:' +x.getMessage());
           }
      }    
}

Executing this anonymously you'll see that it DOES get caught:

testRND_two test= new testRND_two();
test.replicateExceptionQ();

29.0 APEX_CODE,DEBUG
Execute Anonymous: testRND_two test= new testRND_two();
Execute Anonymous: 
Execute Anonymous: test.replicateExceptionQ();
08:58:00.092 (92865804)|EXECUTION_STARTED
08:58:00.092 (92872955)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex
08:58:00.096 (96210154)|METHOD_ENTRY|[1]|01pd0000002dWBM|testRND_two.testRND_two()
08:58:00.096 (96218290)|METHOD_EXIT|[1]|testRND_two
08:58:00.096 (96301071)|CONSTRUCTOR_ENTRY|[1]|01pd0000002dWBM|<init>()
08:58:00.096 (96342058)|CONSTRUCTOR_EXIT|[1]|01pd0000002dWBM|<init>()
08:58:00.096 (96391101)|METHOD_ENTRY|[3]|01pd0000002dWBM|sdry.testRND_two.replicateExceptionQ()
08:58:00.096 (96437928)|ENTERING_MANAGED_PKG|
08:58:00.096 (96460150)|USER_DEBUG|[8]|DEBUG|------------>SC1
08:58:00.097 (97902331)|METHOD_ENTRY|[1]|01pd0000002dWBH|testRND.testRND()
08:58:00.097 (97909789)|METHOD_EXIT|[1]|testRND
08:58:00.097 (97924747)|CONSTRUCTOR_ENTRY|[9]|01pd0000002dWBH|<init>()
08:58:00.097 (97942555)|CONSTRUCTOR_EXIT|[9]|01pd0000002dWBH|<init>()
08:58:00.097 (97961441)|METHOD_ENTRY|[10]|01pd0000002dWBH|sdry.testRND.throwException()
08:58:00.099 (99666391)|CONSTRUCTOR_ENTRY|[5]|01pd0000002dWBC|<init>(String)
08:58:00.100 (100284398)|CONSTRUCTOR_EXIT|[5]|01pd0000002dWBC|<init>(String)
08:58:00.100 (100324604)|EXCEPTION_THROWN|[5]|sdry.Exceptions.TestException: test..
08:58:00.100 (100332154)|METHOD_EXIT|[10]|01pd0000002dWBH|sdry.testRND.throwException()
08:58:00.100 (100377232)|ENTERING_MANAGED_PKG|
08:58:00.100 (100388207)|USER_DEBUG|[20]|DEBUG|----------------------->CAUGHT:test..
Related Topic