In the code below, the type parameter D
can be either a List<Byte>
or a List<List<Byte>>
(it is the third generic parameter in the Fields<?, ?, D>
interface but still I might omit it there - but it is present also in the return type of the method). Can't seem to find a way to tell the compiler this - get Unchecked cast
warnings in the lines marked //*
:
public static <D, K, T extends Enum<T> & Fields<?, ?, D>> List<EnumMap<T, D>>
getEntries(InputStream is, Class<T> fields) throws IOException {
final List<List<Byte>> entries = new ArrayList<List<Byte>>();
// populate "entries"
final boolean hasLists = hasLists(fields);
List<K> daBytes;
if (hasLists) {
daBytes = (List<K>) new ArrayList<EnumMap<T, List<List<Byte>>>>(); //*
} else {
daBytes = (List<K>) new ArrayList<EnumMap<T, List<Byte>>>(); //*
}
final int numOfEntries = entries.size();
for (int currentEntry = 0; currentEntry < numOfEntries; ++currentEntry) {
// add an element in daBytes for this currentEntry
if (hasLists) {
daBytes.add((K) new EnumMap<T, List<List<Byte>>>(fields)); //*
} else {
daBytes.add((K) new EnumMap<T, List<Byte>>(fields)); //*
}
for (T daField : fields.getEnumConstants()) {
List<Byte> field = new ArrayList<Byte>();
// populate "field"
D map = (D) daBytes.get(currentEntry);
if (hasLists) {
List<List<Byte>> fieldEntries = new ArrayList<List<Byte>>();
// populate "fieldEntries"
((EnumMap<T, List<List<Byte>>>) map).put(daField,
fieldEntries); //*
} else {
((EnumMap<T, List<Byte>>) map).put(daField, field); //*
}
}
}
return (List<EnumMap<T, D>>) daBytes; //*
}
If hasLists
is false then I need D to be a List<Byte>
else a List<List<Byte>>
. The daList
variable is a List<EnumMap<T, D>>
. Now it would seem natural (to me) to define :
List<EnumMap<T, D>> daBytes;
But as soon as I do this and change :
if (hasLists) {
daBytes = (List<EnumMap<T, D>>) new ArrayList<EnumMap<T, List<List<Byte>>>>();
}
I get an error :
Cannot cast from
ArrayList<EnumMap<T,List<List<Byte>>>>
toList<EnumMap<T,D>>
Been going round in circles making daBytes an Object, a List<?>
etc but always getting to use either outright casts or generic casts that lead to warnings. There must a way to have this compile cleanly with no casts
I did a bit of refactoring, extracting a "method object" as suggested by other posters. This is an instance of the so called "strategy class" design pattern.
Wherever you have a check on
hasLists
I introduced an abstract method. It turns out that you do not need theK
type parameter anymore.The code produces one unchecked warning at the top, where I have put a check on
hasLists
to choose an implementation of the abstract class.You probably can remove the sole remaining unchecked warning by moving
hasLists()
logic and the switch to choose which strategy class to use to theFields
interface and implementing it in theenum
classes.UPDATE: here is the updated definition of
selectStrategy
andFields
which does not raise any warnings:You need to implement
selectStrategy()
in yourenum
types and return either an appropriateGetByteEntries
orGetByteListEntries
.You can remove
hasLists()
now.