2

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.

Raphael
  • 9,779
  • 5
  • 63
  • 94

1 Answers1

1

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.

Raphael
  • 9,779
  • 5
  • 63
  • 94
  • 1
    `CLASS` means it becomes a part of the class, which the runtime will have to load and interpret, and only then discard so it's not available via reflection. A class that has these annotations would (I suppose) have to have a format version number 52 or higher, which Android may reject. – Marko Topolnik Apr 04 '18 at 11:14
  • @MarkoTopolnik I guess it *could* just ignore all CLASS annotations, but it might not. Your point about the format version is valid; I don't have enough experience with shipping for Android to estimate the issues here. Depends on the Android versions you want to support, I guess? 4.4 is still around a lot, but ancient. :/ Anyway, I couldn't find out (by Googling) if (modern) Android supports type annotations. Don't have Android Studio handy to try, so it's best to consider this a JVM-only answer. – Raphael Apr 04 '18 at 11:42
  • 1
    Android is stuck on compatibility with JDK 7 so it might very well complain to a library with JDK 8 class format. There may be workarounds for this, though, like separate builds for development-time dependency and for APKs. – Marko Topolnik Apr 04 '18 at 12:03
  • @MarkoTopolnik I'm perpetually confused (and irritated) about Google's strategy there. I may get back to you about those workarounds! For now, FWIW, I proposed an [addition to the Kotlin docs](https://github.com/JetBrains/kotlin-web-site/pull/1040) about this issue. Feedback appreciated! – Raphael Apr 04 '18 at 23:00