1

I'm working on after update trigger. And it's throwing an exception after I'm checking null values too. i don't have any idea why it's

public void AfterUpdate(Map<Id, SObject> newItems, Map<Id, SObject> oldItems) 
    {
        /** 
         * This method is to calclate average of all ARPU amounts with case have customer order recordtype
         * as well as case details with either ADD-On (OR) New Subscription and update in related account
         * field called ARPU. 
         * This method will fire only when any case with record type called customer order is created as well updated. 
    */
        Id recordTypeId = [Select Id From RecordType Where DeveloperName = 'Customer_Order' Limit 1].Id;
        Id recordTypeId1 = [Select Id From RecordType Where DeveloperName = 'UBI_Fulfillment' Limit 1].Id;
        Id TrainingrecordTypeId = [Select Id from RecordType Where DeveloperName = 'Customer_Training' LIMIT 1].Id;
        List<Account> Accountstoupdate =new List<Account>();
        Map<Id, AggregateResult> results =new Map<Id, AggregateResult>();
        Map<Id,Account> accWithCaseSalesDiv = new Map<Id,Account>();
        set<Id> CaseAccountIds = new set<Id>();
        Set<Id> CaseAccountIdsELD = new set<Id>();
        List<Case> Onboarding= new List<Case>();
        List<Case> CaseIDs = new List<Case>();
        List<Case> TrainingCases = new List<Case>();
        System.debug('Details in olditems keys'+oldItems.keyset());
        System.debug('Details in olditems values'+oldItems.values());
        System.debug('Details in full valuess'+oldItems);
        Map<Id, Case> OldRecords = new Map<Id, Case>();
        Map<Id,Id> AccountDetails = new Map<Id,Id>();
        Map<Id,Account> FullAccountDetails = new Map<Id,Account>();
        for(Id key : oldItems.keySet())
        {
            OldRecords.put(key, (Case)oldItems.get(key));
        }
        for(case css:OldRecords.values())
        {
            if(css.Case_Details__c == 'New Subscription' && css.Ship_Date__c == null )
            {
                AccountDetails.put(css.accountid,css.id);   
            }
        }
        If(AccountDetails <> null && !AccountDetails.isEmpty())
        {
            for(account a:[SELECT Id,Name,OwnerId,Team__c,Account_Status__c,Type FROM Account where id IN:AccountDetails.keyset()])
            {
                accWithCaseSalesDiv.put(AccountDetails.get(a.id),a);
                FullAccountDetails.put(a.id,a);
            }
        }
        System.debug('Accounts Data values'+accWithCaseSalesDiv);
        for(Case i:(List<case>)newItems.values())
        {   
            if(i.ARPU__c != OldRecords.get(i.id).ARPU__c && RecordTypeId == recordTypeId || i.RecordTypeId == recordTypeId1 && (i.Case_Details__c =='New Subscription' || i.Case_Details__c =='Add On') )
            {
        //Loop through and add caseId's to the list.
                CaseIDs.add(i);
                CaseAccountIds.add(i.accountId);
            }
            if(((i.P_SM_T377AZKAATT__c != OldRecords.get(i.id).P_SM_T377AZKAATT__c) || (i.P_GPS_TABE_8_KIT_P__c != OldRecords.get(i.id).P_GPS_TABE_8_KIT_P__c)) && i.RecordTypeId == recordTypeId && i.Status =='Shipped' && i.Total_ELD_Shipped__c > 0)
            {
                CaseAccountIdsELD.add(i.AccountId);
            }
            if(accWithCaseSalesDiv != null && !accWithCaseSalesDiv.isEmpty())
            {
                System.debug('Details ifor account'+accWithCaseSalesDiv);
                System.debug('Current account id'+i.AccountId);
                System.debug('RecordTypeID:'+i.RecordTypeId);
                //System.debug('accWithCaseSalesDiv Details'+accWithCaseSalesDiv.get(i.Id).id);
                //System.debug('accWithCaseSalesDiv details Account Status'+accWithCaseSalesDiv.get(i.Id).Account_Status__c);
                //System.debug('accWithCaseSalesDiv Type'+accWithCaseSalesDiv.get(i.Id).Type);
                System.debug('Case Details'+i.Case_Details__c);
                System.debug('Account Details directly team'+i.account.team__c);
                System.debug('old ship date'+OldRecords.get(i.id).Ship_Date__c);
                System.debug('current ship details'+i.Ship_Date__c);
                If(accWithCaseSalesDiv.get(i.Id).id != null && accWithCaseSalesDiv.get(i.Id).Account_Status__c != null && accWithCaseSalesDiv.get(i.Id).Type != null)
                {
                    if(i.RecordTypeId == recordTypeId && i.AccountId == accWithCaseSalesDiv.get(i.Id).id && accWithCaseSalesDiv.get(i.id).team__c != '' && accWithCaseSalesDiv.get(i.id).team__c == 'Bangalore Team' && accWithCaseSalesDiv.get(i.id).Account_Status__c != '' && accWithCaseSalesDiv.get(i.Id).Account_Status__c == 'Active / Green' && 
                       accWithCaseSalesDiv.get(i.Id).Type != '' && (accWithCaseSalesDiv.get(i.Id).Type == 'Revenue' || accWithCaseSalesDiv.get(i.Id).Type == 'Transient') && i.Case_Details__c == 'New Subscription'  && OldRecords.get(i.id).Ship_Date__c == null && i.Ship_Date__c != null)
                {
                    OnBoarding.add(i);
                }
                }
            }
        }
        }

When I check debug logs it's showing error on these lines:

If(accWithCaseSalesDiv.get(i.Id).id != null && 
 accWithCaseSalesDiv.get(i.Id).Account_Status__c != null 
 &&accWithCaseSalesDiv.get(i.Id).Type != null)
                {
                }

Debug Logs:

11:22:27.50 (1837155126)|EXCEPTION_THROWN|[28]|System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, ForARPU: execution of AfterUpdate

caused by: System.NullPointerException: Attempt to de-reference a null object

Class.CaseTriggerHandler.AfterUpdate: line 720, column 1 Class.TriggerDispatcher.Run: line 36, column 1 Trigger.ForARPU: line 4, column 1: [] 11:22:27.50 (1837827557)|HEAP_ALLOCATE|[28]|Bytes:351 11:22:27.50 (1848750570)|FATAL_ERROR|System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, ForARPU: execution of AfterUpdate

caused by: System.NullPointerException: Attempt to de-reference a null object

Class.CaseTriggerHandler.AfterUpdate: line 720, column 1 Class.TriggerDispatcher.Run: line 36, column 1 Trigger.ForARPU: line 4, column 1: []

3

You're error is because accWithCaseSalesDiv.get(i.Id) returns null and you are attempting to dereference it .Id

The . is the dereference operator. Attempt to dereference a null object happens when the object to the left hand side of the dereference operator is null.

Instead of:

If(
    accWithCaseSalesDiv.get(i.Id).id != null && 
    accWithCaseSalesDiv.get(i.Id).Account_Status__c != null && 
    accWithCaseSalesDiv.get(i.Id).Type != null
)
{...}

Try:

If(
    accWithCaseSalesDiv.get(i.Id) != null &&
    accWithCaseSalesDiv.get(i.Id).id != null && 
    accWithCaseSalesDiv.get(i.Id).Account_Status__c != null && 
    accWithCaseSalesDiv.get(i.Id).Type != null
)
{...}

The comment on your post is sort of correct. If you use map.containsKey() you will definitely solve at least 1 problem in that if the map does not contain the key, your error will be suppressed; however, If the map contains the key but it references a null value, you will still get your error. accWithCaseSalesDiv.get(i.Id) != null will solve both problems as if the key does not exist, you will get a null value and if the key does exist but it references a null object, you will still get a null value.

This works because the code will stop evaluating the condition once the condition is false and cannot be evaluated to true. In this case, since all of the conditions are in a single group using &&, as soon as 1 of the conditions is false, they are all false. So if the first one fails, the rest are not evaluated and your null error will never happen.

| improve this answer | |
  • You saved my day and thanks for sharing the knowledge much appreciated. – Pavan tej Sep 17 '19 at 10:04
0

I suggest instead of debugging the code you rewrite it: not only do you need to get the code to work now, but others will have to maintain it in the future.

Something like the following would be clearer (but note that I may not have captured the details correctly). That uses these approaches:

  • Include the specific types in the method signature
  • Only declare variables when needed and close to where used
  • Don't repeat expressions that just make the code harder to read
  • Avoid really long lines that hide what is going on until you horizontal scroll
  • Break pieces out into separate methods
  • Only add null checks where really needed
  • Give variables helpful names

Code:

public void AfterUpdate(Map<Id, Case> newItems, Map<Id, Case> oldItems) {

    Map<Id, Id> caseToAccount = new Map<Id, Id>():
    for (Case c : oldItems.values()) {
        if (c.Case_Details__c == 'New Subscription' && c.Ship_Date__c == null) {
            caseToAccount.put(c.Id, c.AccountId);
        }
    }

    Case[] onboarding = new Case[] {};
    if (caseToAccount.size() > 0) {

        Map<Id, Account> accounts = new Map<Id, Account>([
            select Id, Name, OwnerId, Team__c, Account_Status__c, Type
            from Account
            where id in :caseToAccount.values()
        ]);

        for (Case c : newItems.values()) {
            Case old = oldItems.get(c.Id);
            if (c.ARPU__c != old.ARPU__c
                    && (c.RecordTypeId == coRtId || c.RecordTypeId == ufRtId)
                    && (c.Case_Details__c == 'New Subscription' || c.Case_Details__c == 'Add On')
                    ) {
                // Do something
            }
            if ((c.P_SM_T377AZKAATT__c != old.P_SM_T377AZKAATT__c || c.P_GPS_TABE_8_KIT_P__c != old.P_GPS_TABE_8_KIT_P__c)
                    && c.RecordTypeId == coRtId
                    && c.Status == 'Shipped'
                    && c.Total_ELD_Shipped__c > 0
                    ) {
                // Do something
            }
            Id accountId = caseToAccount.get(c.Id);
            if (accountId != null) {
                Account a = accounts.get(accountId);
                if (a != null) {
                    if (a.Team__c == 'Bangalore Team'
                            && a.Account_Status__c == 'Active / Green'
                            && (a.Type == 'Revenue' || a.Type == 'Transient')
                            && c.Case_Details__c == 'New Subscription'
                            && old.Ship_Date__c == null
                            && c.Ship_Date__c != null
                            ) {
                        onboarding.add(c);
                    }
                }
            }
        }
    }
    // Do something with onboarding
}

private Id coRtId {
    get {
        if (coRtId == null) initRtIds();
        return coRtId;
    }
    set;
}

private Id ufRtId {
    get {
        if (ufRtId == null) initRtIds();
        return ufRtId;
    }
    set;
}

private Id ctRtId {
    get {
        if (ctRtId == null) initRtIds();
        return ctRtId;
    }
    set;
}

private void initRtIds() {
    SObjectType t = Case.SObjectType;
    for (RecordTypeInfo info : t.getDescribe().getRecordTypeInfos()) {
        Id rtId = info.getRecordTypeId();
        switch on info.getDeveloperName() {
            when 'Customer_Order' { coRtId = rtId; }
            when 'UBI_Fulfillment' { ufRtId = rtId; }
            when 'Customer_Training' { ctRtId = rtId; }
        }
    }
}
| improve this answer | |
  • This answer seems very opinionated. Even if he followed all of the advice you gave him another dev can show up later and decide they hate the way the code looks and have trouble maintaining it. There is also no clear answer to the question, while the answer may exist in your code, it's not outlined well enough for OP (if OP was a strong dev they wouldn't be asking the question). – gNerb Sep 16 '19 at 22:16
  • Hi @gNerb, Fair point about "if OP was a strong dev they wouldn't be asking the question". IMHO it is useful for the community, in general, to consider that how something is coded has a big effect on bugs and their fixes. By the way, I upvoted your answer yesterday. – Keith C Sep 17 '19 at 6:57
  • I appreciate, the only reason I downvoted was because your answer doesn't explicitly address the question, I do agree with most of your style points. – gNerb Sep 17 '19 at 19:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.