As a Salesforce developer, I am frequently working with Maps and am looking to abstract the process of generating maps from SObject lists.
I've created the following helper class:
private class MapBySharedKeyExtractor {
SObjectField keyField;
XAP_PRED_SObjectPredicateIntf predicate;
MapBySharedKeyExtractor(SObjectField keyField, XAP_PRED_SObjectPredicateIntf predicate) {
this.keyField = keyField;
this.predicate = predicate;
}
public Map<Object, List<SObject>> extractFrom(List<SObject> homogeneousSObjectList) {
if (homogeneousSObjectList == null || homogeneousSObjectList.isEmpty()) {
return null;
}
Map<Object, List<SObject>> sObjectListByKeyMap = new Map<Object, List<SObject>>();
for (SObject sObj : homogeneousSObjectList) {
if (this.predicate.isTrueFor(sObj)) {
Object key = sObj.get(this.keyField);
if (!sObjectListByKeyMap.containsKey(key)) {
sObjectListByKeyMap.put(key, new List<SObject>());
}
sObjectListByKeyMap.get(key).add(sObj);
}
}
return sObjectListByKeyMap;
}
}
This is the prediate interface:
public interface XAP_PRED_SObjectPredicateIntf {
Boolean isTrueFor(SObject sObj);
}
However, as the final step of this journey, I would like to be able to change the generated Map into concrete types, so I would like (for example) to have a helper method:
public static Map<Id, List<SObject>> mapBySpecifiedIdField(List<SObject> homogeneousSObjectList, SObjectField idField) {
Map<Object, List<SObject>> sObjectListBySpecifiedObjectMap
= new MapBySharedKeyExtractor(idField, new XAP_PRED_SObjectFieldHasNonNullValue(idField))
.extractFrom(homogeneousSObjectList);
String mapType = 'Map<Id, List<' + homogeneousSObjectList[0].getSObjectType() + '>>';
Map<Id, List<SObject>> concreteSObjectListByIdMap = (Map<Id, List<SObject>>) Type.forName(mapType).newInstance();
concreteSObjectListByIdMap.putAll(sObjectListBySpecifiedObjectMap);
return concreteSObjectListByIdMap;
}
However this fails because this is invalid:
concreteSObjectListByIdMap.putAll(sObjectListBySpecifiedObjectMap);
Is there any way I can make this work without iterating through sObjectListBySpecifiedObjectMap and casting each key individually?
Best Answer
No. You can't convert key types without a loop. The
Map
structure is not flexible in this way. TheList
type is a bit more flexible, however, and so you can make this minor simplification, as concretely typing theList<SObject>
offers few tangible benefits unless you plan toupsert
it.No need for dynamic
Type.forName
instantiation.