I recently tripped across the need to take a list of objects (instances of a class–not sobjects) and split them into smaller lists of 200 members each.
The unit test below shows the code inside a unit test. It passes, but it's not really what I want.
I would like the signature for the method to be:
list<list<object>> listSplit(list<object> aList, integer size)
but the problem with that is a runtime conversion error:
System.TypeException: Invalid conversion from runtime type
List<List<ANY>>
toList<List<String>>
@isTest
public class TomTest
{
// this unit test creates a list of 26 members
// then calls listSplit to create chunks of
// 7 members each, except for the last which
// has the left-overs.
static testMethod void splitTest() {
list<string> alphabet = new list<string> {
'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z'
};
list<list<string>> octaves = listSplit(alphabet, 7);
// I should have my list of lists and the
// first three should have 7 letters each,
// and the last one only 5.
system.assertEquals(4, octaves.size());
system.assertEquals(7, octaves[0].size());
system.assertEquals(7, octaves[1].size());
system.assertEquals(7, octaves[2].size());
system.assertEquals(5, octaves[3].size());
}
// here's the utility for splitting a list into
// smaller parts, but rather than hard-coding the list type,
// I would prefer something generic like list<list<object>>,
// and though the method works fine that way, I can't
// cast the result back to list<list<string>> without throwing
// a runtime conversion exception.
static list<list<string>> listSplit(list<string> aList, integer size)
{
list<list<string>> collector = new list<list<string>>();
integer i = 1;
list<string> petiteList = new list<string>();
for (string each : aList) {
petiteList.add(each);
if (Math.Mod(i, size) == 0) {
collector.add(petiteList);
petiteList = new list<string>();
}
i++;
}
if (petiteList.isEmpty() == false)
collector.add(petiteList);
return collector;
}
}
Best Answer
You can't cast
ANY
to a more specific type, so you have to actually obtain the type that you want to return. Without proper reflection, you have to tell the function what type you'd like to return. There's several ways you can do that, but here's one way:You use the code like this:
It's a little messy, as you have to give it a primitive data type and then cast it back, but it works.
As an alternative, you might try the "out-param" approach:
This one can't incur the run-time exception if destType isn't compatible with
List<List<Object>>
and saves you a bit of casting. You can use it like this:The callee now becomes responsible for initializing the correct object type, but avoids the extra casting.