Using the interop automatisms Kotlin has for nullability, a method like this gets the proper signature in Kotlin:
@NonNull
public String foo(@NonNull String bar) {
return "bar";
}
Now lift the principle to collections (or other generics, I guess):
@NonNull
public Set<String> foo(@NonNull Collection<String> bar) {
return new HashSet<String>();
}
This shows in Kotlin as
foo(bar: (Mutable)Collection<String!>) : (Mutable)Set<String!>
I'm fine with (Mutable)
, but how do I get rid of the platform types in the type parameters? That is, how do I write or annotate the Java function so that I see Set<String>
(or Set<String?>
, for that matter) from Kotlin?
Using Set<@NonNull String>
is not allowed ("'@NonNull' not applicable to type use").
If it makes a difference, I use the Findbugs annotations (via Spotbugs). My perspective is that of a (Java) library provider who wants to enable as seamless use from Kotlin as possible.
Turns out it's an implementation issue of the annotations I used, not a conceptual one.
As of Spotbugs Annotations 3.1.2, the annotations @NotNull
and @NonNull
are not declared for targets ElementType.TYPE_USE
.
Jetbrains annotations are declared with that flag, to they can be used on type parameters:
@NotNull
public Set<@NotNull String> foo(@NotNull Collection<@NotNull String> bar) {
return new HashSet<>();
}
While this looks a little unwieldy in Java, we get the desired Kotlin signature:
foo(bar: (Mutable)Collection<String>) : (Mutable)Set<String>
Note that annotating type parameters requires source language level Java 8+.
A note on Android and other situations of being stuck at low langauges levels. Since the annotations have retention level CLASS
, I would not expect any runtime problems if an app used a thus annotated library. I have not tested it, though; comments appreciated.