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.
Generics type checks and castsif (something is List<*>) { something. forEach { println(it) } // The items are typed as `Any?` } The same syntax but with the type arguments omitted can be used for casts that do not take type arguments into account: list as ArrayList .
There are no direct ways to do this in Kotlin. In order to check the generic type, we need to create an instance of the generic class<T> and then we can compare the same with our class.
To use Java generics effectively, you must consider the following restrictions: Cannot Instantiate Generic Types with Primitive Types. Cannot Create Instances of Type Parameters. Cannot Declare Static Fields Whose Types are Type Parameters.
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)
}
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);
}
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With