function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Matthew GroesserMatthew Groesser 

System.nullPointerException on afterInsert

HI all, 

I have a simple brief to insert a contract on an account once the account has been created while using a factory trigger. I am getting a AccountTrigger: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object () error when trying to create an Account.

Here is my ITrigger interface:
public interface ITrigger {
	void bulkAfter();

	//For records inserted during a AFTER trigger
	void afterInsert(SObject so);
    
    void andFinally();
}
Account Handler:
public with sharing class AccountHandler
implements ITrigger
{
    private Set<Id> cont_inUseIds = new Set<Id>();
    
    private List<Contract> contr = new List<Contract>();


	public AccountHandler()
	{

	}

    
	public void bulkAfter()
	{
		if(Trigger.isInsert){
            cont_inUseIds = AccountGateway.findAccountIdsInUse(Trigger.oldMap.keySet());
        }
	}
    
    
    public void afterInsert(SObject so){
        Account myAccount = (Account)so;

        Contract contrTemp = new Contract();
        contrTemp.Name = myAccount.Name;
        contrTemp.id = myAccount.Id;
        
        
        contr.add(contrTemp);
        }
    
    
    public void andFinally(){
        if(!contr.isEmpty()){
            insert contr;
        }
    }
}
Trigger Factory:
public with sharing class TriggerFactory{
	public static void createHandler(Schema.sObjectType objType){
		ITrigger handler = getHandler(objType);

		if (handler == null){
			throw new TriggerException('no registered handler for object type '+ objType);
		}

		execute(handler);
	}

	private static void execute (ITrigger handler){       
		if(Trigger.isAfter){
			handler.bulkAfter();
            if(Trigger.isInsert){
                for(SObject so : Trigger.new){
                    handler.afterInsert(so);
                }
            }
			

			//Actions for after delete and update would go here
		}

		handler.andFinally();
	}


	public static ITrigger getHandler(Schema.sObjectType objType){
		if (objType == Account.sObjectType){
			return new AccountHandler();
		}
		return null;
	}
}
The trigger itself:
trigger AccountTrigger on Account ( after insert){
	TriggerFactory.createHandler(Account.sObjectType);
}
and the additional supporting classes:
public class TriggerException extends Exception {}

AccountGateway class:
public without sharing class AccountGateway
{
    public static Set<Id> findAccountIdsInUse(Set<Id> accIds)
    {
        Set<Id> inUseIds = new Set<Id>();

        for (Account[] accounts : [Select p.Id, (Select Id From Contracts Limit 1) From Account p where p.Id in : accIds])
        {  
            for (Account acc : accounts)
            {
                if (acc.Contracts.size() > 0)
                {
                    inUseIds.add(acc.id);
                }
            }
     	}
     	return inUseIds;
	}
}





 
Best Answer chosen by Matthew Groesser
Matthew GroesserMatthew Groesser
Hi all who come accross this question,

I found my issue, it was quite simple and the problem was the way in which I was trying to reference inside the accountHandler class as well as the use of the account gateway. The correct code can be seen below:
public interface ITrigger {

	//For records inserted during a AFTER trigger
	void afterInsert(SObject so);
    
    void andFinally();
}
 
public with sharing class AccountHandler
implements ITrigger
{
    private Set<Id> cont_inUseIds = new Set<Id>();
    
    List<Contract> contrList = new List<Contract>();


	public AccountHandler()
	{

	}    
    //Method which will create Contract after a account is created
    public void afterInsert(SObject so){

            Map<Id,Account> accWithContracts = new Map <Id, Account> ([Select Id, (Select Id FROM Contracts) 
                                                             FROM Account WHERE Id IN :Trigger.New]);

            for(Account a : [Select Id,Name FROM Account WHERE Id IN :Trigger.New 
                             AND Id NOT IN (Select AccountId FROM CONTRACT)]){
                	System.debug('accWithContracts.get(a.Id).Contracts.size()=' + accWithContracts.get(a.Id).Contracts.size());
                    contrList.add(new Contract(Name=a.Name + ' Contract', AccountId=a.Id));
                
            }

        }
    
    //Adding of all contracts in list to the DB
    public void andFinally(){
        if(!contrList.isEmpty()){
            insert contrList;
        }
    }
}
 
public with sharing class TriggerFactory{
	public static void createHandler(Schema.SObjectType objType){
		ITrigger handler = getHandler(objType);

		if (handler == null){
			throw new TriggerException('no registered handler for object type '+ objType);
		}

		execute(handler);
	}

	private static void execute (ITrigger handler){       
		if(Trigger.isAfter){
            if(Trigger.isInsert){
                for(SObject so : Trigger.new){
                    handler.afterInsert(so);
                }
            }
			

			//Actions for after delete and update would go here
		}

		handler.andFinally();
	}


	public static ITrigger getHandler(Schema.sObjectType objType){
		if (objType == Account.sObjectType){
			return new AccountHandler();
		}
		return null;
	}
}
 
trigger AccountTrigger on Account (after insert){
	TriggerFactory.createHandler(Account.sObjectType);
}
And of course the exception class:
public class TriggerException extends Exception {}


 

All Answers

Alain CabonAlain Cabon
Hi,

There is a typo or an error at least for :  contrTemp.id = myAccount.Id;
 
public void afterInsert(SObject so){
        Account myAccount = (Account)so;

        Contract contrTemp = new Contract();
        contrTemp.Name = myAccount.Name;

        contrTemp.AccountId = myAccount.Id;
                
        contr.add(contrTemp);
 }

 
Matthew GroesserMatthew Groesser
Hi,

I saw the error and changed it, still getting the same error unfortunately.
Matthew GroesserMatthew Groesser
Hi all who come accross this question,

I found my issue, it was quite simple and the problem was the way in which I was trying to reference inside the accountHandler class as well as the use of the account gateway. The correct code can be seen below:
public interface ITrigger {

	//For records inserted during a AFTER trigger
	void afterInsert(SObject so);
    
    void andFinally();
}
 
public with sharing class AccountHandler
implements ITrigger
{
    private Set<Id> cont_inUseIds = new Set<Id>();
    
    List<Contract> contrList = new List<Contract>();


	public AccountHandler()
	{

	}    
    //Method which will create Contract after a account is created
    public void afterInsert(SObject so){

            Map<Id,Account> accWithContracts = new Map <Id, Account> ([Select Id, (Select Id FROM Contracts) 
                                                             FROM Account WHERE Id IN :Trigger.New]);

            for(Account a : [Select Id,Name FROM Account WHERE Id IN :Trigger.New 
                             AND Id NOT IN (Select AccountId FROM CONTRACT)]){
                	System.debug('accWithContracts.get(a.Id).Contracts.size()=' + accWithContracts.get(a.Id).Contracts.size());
                    contrList.add(new Contract(Name=a.Name + ' Contract', AccountId=a.Id));
                
            }

        }
    
    //Adding of all contracts in list to the DB
    public void andFinally(){
        if(!contrList.isEmpty()){
            insert contrList;
        }
    }
}
 
public with sharing class TriggerFactory{
	public static void createHandler(Schema.SObjectType objType){
		ITrigger handler = getHandler(objType);

		if (handler == null){
			throw new TriggerException('no registered handler for object type '+ objType);
		}

		execute(handler);
	}

	private static void execute (ITrigger handler){       
		if(Trigger.isAfter){
            if(Trigger.isInsert){
                for(SObject so : Trigger.new){
                    handler.afterInsert(so);
                }
            }
			

			//Actions for after delete and update would go here
		}

		handler.andFinally();
	}


	public static ITrigger getHandler(Schema.sObjectType objType){
		if (objType == Account.sObjectType){
			return new AccountHandler();
		}
		return null;
	}
}
 
trigger AccountTrigger on Account (after insert){
	TriggerFactory.createHandler(Account.sObjectType);
}
And of course the exception class:
public class TriggerException extends Exception {}


 
This was selected as the best answer