Reputation: 2600
I have method in Kotlin which returns an Rx Observable of a generic list:
public fun getObservable(): Observable<List<FooBar>> {
return Observable.just(theList)
}
Because the Kotlin list trait is defined as List<out T>
, Java will see the return type as Observable<List<? extends FooBar>>
.
Is there a way do tell the Kotlin compiler that Java should see this as Observable<List<FooBar>>
?
http://kotlinlang.org/docs/reference/generics.html
Updated to show problem correctly.
Upvotes: 6
Views: 1496
Reputation: 9584
Edit: This behaviour has changed in Kotlin Beta 4. See Jayson Minard's answer.
I can see two options:
The first is to return an Observable<MutableList<FooBar>>
. As a List
is immutable in kotlin, it is declared as List<out T>
since objects of type T can only be taken out of it.
MutableList
on the other hand is Java's true List
equivalent: since it is mutable it is declared as MutableList<T>
.
So your function would be:
public fun getObservable(): Observable<MutableList<FooBar>>
= Observable.just(theList)
The problem with this solution is that should you use it in kotlin, you grant "too much" access to your list if you only wanted to have an Observable of immutable list.
The second option is to write a "proxy" method in java that makes the cast once and for all:
@SuppressWarnings("unchecked")
public static Observable<List<String>> _getObservable() { return (Observable) TestPackage.getObservable(); }
This is ugly but it works, and it does not break kotlin
However, I assume you're using RxJava's Observable
, so why not use this opportunity to enforce kotlin's immutable list semantic in Java?
public static Observable<List<String>> _getObservable() {
return TestPackage.getObservable().map(new Func1<List<? extends String>, List<String>>() {
@Override
public List<String> call(List<? extends String> list) {
return Collections.unmodifiableList(list);
}
});
}
Upvotes: 3
Reputation: 85936
You can control how Java sees the Kotlin generics using the JvmWildcard
and JvmSuppressWildcards
annotation. It was added in Kotlin 1.0 Beta 4 (see announcement).
This change means that your code will already change to be ok, and no longer generate the wildcard. Because the new default is to not use them in many cases, and you can bring them back using the annotations or suppress them when not desired.
The announcement of this change states:
Java Wildcards
There were issues with how Kotlin translated variant types, e.g. whether a List should be List in Java or simply List. Subtleties details aside, we did the following:
- By default, we do not generate wildcards in return types and where they make no sense
- When a wildcard is needed, one can enforce its presence with a type annotation: List<@JvmWildcard String> is always List in Java
- When we need to get rid of a wildcards, we can use @JvmSuppressWildcards (this can be used on a type or any declaration that contains it)
Examples:
fun foo(l: List<String>) // in Java: List<String> (String is final)
fun foo(l: List<@JvmWildcard String>) // in Java: List<? extends String>
interface Open {}
fun bar(p: List<Open>) // in Java: List<? extends Open> (Open is not final)
@JvmSuppressWildcards
fun bar(p: List<Open>) // in Java: List<Open>
So applying this to your question, if you were still having issues:
@JvmSuppressWildcards
public fun getObservable(): Observable<List<FooBar>> {
return Observable.just(theList)
}
Upvotes: 6