Given this class:
data class CSVRecord(private val columns: SortedSet<CSVColumn>) : Iterable<String> {
override fun iterator(): Iterator<String> {
return columns.map { it.value }.iterator()
}
}
spotbugs raises an error:
[ERROR] Questionable cast from Collection to abstract class java.util.List in com.example.CSVRecord.iterator() [com.example.CSVRecord] At CSVRecord.kt:[line 15] BC_BAD_CAST_TO_ABSTRACT_COLLECTION
Is this just because spotbugs doesn't support Kotlin, or is my implementation potentially invalid?
FindBugs processes bytecode and then reverse-looks-up the file and line info. It appears likely that the Kotlin compiler emitted a CHECKCAST
instruction where, from Kotlin's point of view, it is clear that the cast will pass, but the return type declaration of the Java method, or the declared local variable/parameter type, is broader.
This is what I got from IDEA as the decompiled Kotlin bytecode for your function:
@NotNull
public Iterator iterator() {
Iterable $receiver$iv = (Iterable)this.columns;
Collection destination$iv$iv = (Collection)
(new ArrayList(collectionSizeOrDefault($receiver$iv, 10)));
Iterator var4 = $receiver$iv.iterator();
while(var4.hasNext()) {
Object item$iv$iv = var4.next();
CSVColumn it = (CSVColumn)item$iv$iv;
String var11 = it.getValue();
destination$iv$iv.add(var11);
}
return ((List)destination$iv$iv).iterator();
}
You can see what the declaration inline fun map
means on this level: its entire code became a part of your method implementation. The emitted bytecode happens to use a Collection
-typed variable destination$iv$iv
to hold a reference to an ArrayList
. The return
statement casts it to List
, which it's perfectly allowed to, and which is obviously safe.