2

I have a trigger and an Account handler. I have an error on record insert. Trigger calls

Accounthandler.OnAfterInsert(Trigger.new, Trigger.newMap);

Here is a simplified version of the handler top method:

public void OnAfterInsert(Account[] newAccounts, Map<Id, Account> newAccountMap){
    if(!System.isFuture() && !System.isBatch()){
        myMethod(null, newAccounts, null, newAccountMap);
    }
}

Now the method itself:

private void identifyAndGeoCodeAccounts(Account[] oldAccounts, Account[] updatedAccounts, Map<ID, Account> oldAccountMap, Map<ID, Account> newAccountMap){
        Set<Id> ChangedAddressIDs = new Set<Id>();
        for(Account a : updatedAccounts){
            system.debug('evaluating account ' + a);
            if( 
                ( a.BillingCountry != null && oldAccounts == null )

                 // Error happens in line above, saying that a.BillingCountry is null object

                || 
                (
                    a.BillingStreet != oldAccountMap.get(a.id).BillingStreet ||
                    a.BillingCity != oldAccountMap.get(a.id).BillingCity ||
                    a.BillingState != oldAccountMap.get(a.id).BillingState ||
                    a.BillingPostalCode != oldAccountMap.get(a.id).BillingPostalCode ||
                    a.BillingCountry != oldAccountMap.get(a.id).BillingCountry
                )
                || 
                ( //otherstuff ) 
            ) {
                ChangedAddressIDs.add(a.id);
            }
        }
        if(ChangedAddressIDs.size() == 1){
            //dostuff
        } else if(ChangedAddressIDs.size() == 0){
            system.debug('ChangedAddressIDs.sizes = 0');
            return;
        } else {
            //system.debug('ChangedAddressIDs.size > 1');
            //do other stuff
        }
    }

And here is the test code:

    @isTest static void hasGeocode() {
            test.startTest();
            Account a = new Account(name='TestAccount');
            //a.BillingCountry = 'US';
            insert a;
            test.stopTest();
            //other stuff after asynch stuff happens
        }

Pretty straightforward. When I populate BillingCountry in the test, all is good. When I don't, all fails. I can debug the Account a and I have no problems. It even shows BillingCountry as null. Any ideas, StackExchangers?

The error is that I'm de-referencing a null object, and it refers specifically to the "a.BillingCountry != null" part. I've isolated it down to that. But a.BillingCountry is included when I debug the Account; even if it is null, my conditional should allow for it to be true, so the first part of the IF clause should be true on insert, so it should add the Id to the Set. But it has an error specifically with a.BillingCountry.

2 Answers 2

1

crop1645 is right in that the error is your second major OR grouping. If the first condition is not satisfied, only then will the second condition be evaluated, and you only want that to happen if there is an oldaccounts. You could do this through trigger awareness (which can make it a little harder to unit test), or you can just make sure you don't evaluate it if there are no oldaccounts:

||
(oldaccounts != null &&     
    (a.BillingStreet != oldAccountMap.get(a.id).BillingStreet ||
    a.BillingCity != oldAccountMap.get(a.id).BillingCity ||
    a.BillingState != oldAccountMap.get(a.id).BillingState ||
    a.BillingPostalCode != oldAccountMap.get(a.id).BillingPostalCode ||
    a.BillingCountry != oldAccountMap.get(a.id).BillingCountry))
||
1
  • Ah, now I understand. This is interesting. Yes, you are correct and my IF statement's second part was tripping me up. HOWEVER, the error message said the wrong line, so I hope that someone at salesforce.com sees this and can get the platform to say that the problem is in the second part of the IF and not the first part. Weird... Thanks for the sleuthing. Jul 31, 2013 at 1:02
2

I believe the error is in your 'or' condition. SFDC will report the if condition statement's first line and not pinpoint it down to the actual conditional expression (which is spread over multiple lines in your code)

When a.billingCountry is non null, the first condition is true and APEX won't bother to even evaluate the or condition(s). When it is null, then the or condition(s) get evaluated

As this is an insert operation, Trigger.oldMap won't be available - see APEX Doc http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_triggers_context_variables.htm?SearchType=Stem

You'll need to be isInsert vs isUpdateaware

3
  • I agree on all that. The code errors at the conditional and never exists the IF clause. I've narrowed it down to "a.BillingCountry != null" for the error. I know oldMap isn't available, and as you can see I've accounted for that. It doesn't error at "oldAccounts == null" so I have no problems there. The code can't be isInsert aware because I've pulled it from the trigger to a handler class, but it is effectively aware because I check if the old list is null. Jul 30, 2013 at 23:14
  • @David oldAccounts is not the same as oldAccountMap. If a.billingCountry is null, then the first if condition is false and APEX will immediately start evaluating the or condition(s).
    – cropredy
    Jul 30, 2013 at 23:25
  • 2
    @David - also, as an FYI - one can always do if (Trigger.isExecuting && Trigger.isInsert) within any class. Trigger context variables are not limited in use to just a .trigger file. That said, testing for null in the right places and right ways is clearer - especially as I can see you are using a pattern
    – cropredy
    Jul 30, 2013 at 23:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .