Search code examples
kotlinspotbugs

Kotlin iterable


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?


Solution

  • 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.