Declaration site variance and Java interop


#1

I’m having an interesting issue with Kotlin declaration-site variance.

Let’s say I have some interface with type parameter Foo with method that takes generic param T as argument and return it, so T should be invariant.
Also, there is abstract class A that implements Foo<List<String>>, but doesn’t implement foo directly, but have a different method with a similar signature.

interface Foo<T> {
    fun foo(t: T): T
}

abstract class A : Foo<List<String>> {
    //method foo is abstract
    
    protected fun bar(list: List<String>): List<String> {
        return listOf("a", "b")
    }
}

The idea is that concrete child of A will implement foo(List) but use bar method of A to get the value.

Then the interesting part: I can easily implement such class with Kotlin:

class B : A() {
    override fun foo(strings: List<String>): List<String> {
        return bar(strings)
    }
}

This works fine, and code compiles.

But if I want to implement the same in Java,

public class C extends A {
    @Override
    public List<? extends String> foo(List<? extends String> strings) {
        return bar(strings); // <- error here
    }
}

there are two issues:

  • List<String> becomes List<? extends String> in argument and return types
  • implementation cannot call bar(strings) because it canot cast List<? extends String> to List<String>.

As I understand that happens because List is defined as List<out T> in Kotlin, but becomes just java.util.List<T> in java class.

How can this problem be (type-)safely resolved?
P.S. Java needs to be used because B class is intended to be generated by annotation processor, so I can’t just convert it to kotlin.


#2

See http://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#variant-generics


#3

Thank you! Worked for me