Comparing Object Types in Apex

At some stage, every developer will require verifying whether a generic SObject corresponds to a specific concrete SObject type.

This scenario commonly arises when inspecting the owner of a custom object or the who.id and what.id of objects containing polymorphic keys like Task. Developers might consider using the Apex instanceof keyword for this verification. However, a challenge emerges: instanceof only performs comparisons between a concrete object and a class, rendering it ineffective when comparing a generic SObject to another entity.

Let’s explore an example using a custom object named Project that I’ve created:

Project__c = [SELECT id, ownerId FROM Project__c][0];

Before proceeding with additional operations on the Project’s owner, we aim to verify whether it belongs to a User or Group. Here’s one approach to achieve this:

SObject comp;
try{
    comp = (Group)Group.SObjectType.newSObject(project.ownerId);
}catch(System.SObjectException e){
    //we don't have a group we have a user
    comp = (User)User.SObjectType.newSObject(project.ownerId);
}
// do something with comp

At line three, we try to instantiate a new Group object using the ownerId. Should the ownerId be an invalid group ID, it triggers an exception, which we handle within the catch block. As the only plausible alternative is that ownerId represents a valid user ID, we manage this exception by creating a new User object in line six.

This process can be confirmed effortlessly using:

System.debug(comp.getSObjectType());

While effective in binary scenarios like the one illustrated, this method lacks optimization and reusability. Consider the scenario where we aim to check the whoId of related tasks for our project—our code could become convoluted quickly. Additionally, consider the potential outcome if an exception is thrown at line six.

Attempting to use instanceof in this context would result in an error citing incompatible types, leading to undesirable consequences.

To enhance this approach, we can strive for greater reusability and generality in our comparisons. One way to achieve this improvement is by developing a new class dedicated to managing these comparisons for us.

public class ObjectHelper{
	public static boolean compare(SObject compare, String checkType){
		try{
Schema.SObjectType targetType = Schema.getGlobalDescribe().get(checkType);
			if(targetType == null){
				return false;
			}else if( compare.getSObjectType() == targetType){
				return true;
			}else{
				return false;
			}
		}catch(Exception e){
			//handle exception
		             return false;
		}
		return false;
	}
}

In this setup, we provide inputs for the SObject we wish to assess and the intended comparison type. At line four, we retrieve the SObjectType details for the designated comparison object. Line five’s function is rather straightforward. By line seven, we conduct a comparison between the SObject type and the designated comparison type, returning true if they match. Conversely, we return false if no exceptions arise, yet the types differ. With this new class in place, we can address similar issues more efficiently.

Project__c project = [select id, ownerId from project__c][0];
Schema.SObjectType oType = project.ownerId.getSObjectType();
SObject myObj = oType.newSObject(project.ownerId);
If( ObjectHelper.compare(myObj, 'User')){
	//do something with the User
} else {
	//do something with Group
}

In this discussion, I concentrated on a specific custom object, yet the same methodology can be applied whenever there’s a need to compare a generic SObject to another type. I’ve suggested one approach for this purpose. Do you happen to have a more effective alternative in mind? Feel free to share your thoughts.