[SalesForce] Dynamically Cast Map To Specific SObject

We realized that often time in our code we're iterating through a list of SObjects and creating a map of String to SObject. To try and reduce how many times we're repeating this code, we were going to add it to a generic SObjectDomain that specific SObject domains extend.

Map<String, SObject> createStringFieldToSObjectsMap(String fieldName, List<SObject> sobjects){
    Map<String, SObject> sobjectMap = new Map<String, SObject>();
    for(SObject currentSObject : sobjects){
        sobjectMap.put(currentSObject.get(fieldName),currentSObject);
    }
    return sobjectMap;
}

The problem we're running into is that it's difficult to convert a generic SObject map into a specific SObject map. I tried just casting the generic map as the specific map, but ran into the following error:

Map<String, SObject> genericMap = new Map<String, SObject>();
Map<String, Account> accountMap = (Map<String, Account>) genericMap;

System.TypeException: Invalid conversion from runtime type Map&lt;String,SObject&gt; to Map&lt;String,Account&gt;

I also tried to declare the map with a dynamic SObject type in the following ways, but each time ran into an error saying that it was an invalid type.

Map<String, Account.SObjectType> accountMap = new Map<String, Account.SObjectType>();
Map<String, Account.SObjectType> accountMap = new Map<String, SObject>();
Map<String, Schema.SObjectType.Account> accountMap;

I also tried to use method like getSObjectType(), but I kept getting the following error:

Map<String, Account.getSObjectType()> accountMap = new Map<String, Account.getSObjectType()>();
Map<String, Account.getSObjectType()> accountMap = new Map<String, SObject>();
//Unexpected token '&lt;'.

I found a lot of posts stating that dynamically determining SObject type wasn't supported, but these posts were at least 4 years old and a lot has changed in that time. Does anyone know if what we're trying to do is possible?

Best Answer

I am not pretty sure why you wanna do it. You can dynamically instantiate Map using Type.newInstance(), Probably that's what you need?

 public static Map<String, SObject> createStringFieldToSObjectsMap(String fieldName, List<SObject> sobjects){
        String soBjectTypeString = String.valueOf(sobjects[0].getSObjectType());
        Type t= Type.forName('Map<String,'+soBjectTypeString+'>');  
        Map<String,Sobject> sobjectMap =(Map<String,Sobject>)t.newInstance();
        for(SObject currentSObject : sobjects){
            sobjectMap.put(String.valueOf(currentSObject.get(fieldName)),currentSObject);
        }
        return sobjectMap;   



}

Then to test

List<Sobject> sobjectList  =[Select Id from Account ];

System.debug(MyUtil.createStringFieldToSObjectsMap('Id',sobjectList) instanceof Map<String,Account>); //Returns true

Cast to AccountMap:

Map<String,Account> accMap =(Map<String,Account> ) MyUtil.createStringFieldToSObjectsMap('Id',sobjectList);

Src: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_type.htm

Related Topic