skip to content

How can you make Kotlin treat the return of a Java method as a proper non-null or nullable type instead of a platform type, and which annotations does Kotlin recognize?

level: middleimportance: should knowfreq 60%

answer

  1. JetBrains/JSR-305/androidx annotations honored
  2. @NotNull->String, @Nullable->String?
  3. -Xjsr305=strict|warn|ignore
  4. @ParametersAreNonnullByDefault for packages
  5. Annotate once -> safe at every call site

basics

~10 s

Add nullability annotations like @Nullable or @NotNull on the Java side. Kotlin reads them and turns the value into a real nullable or non-null type, bringing back compile-time checks.

solid answer

~40 s

Kotlin honors a range of nullability annotations on Java declarations and converts them from platform types into proper Kotlin types. Recognized families include JetBrains (`org.jetbrains.annotations.@Nullable/@NotNull`), JSR-305 (`javax.annotation.@Nonnull` / `@CheckForNull`), Android (`androidx.annotation`), Jakarta/Eclipse, Lombok-generated, and Checker Framework. A `@NotNull String` becomes Kotlin `String`; a `@Nullable String` becomes `String?`. For whole packages you can apply JSR-305 defaults via `@ParametersAreNonnullByDefault` or a custom `@TypeQualifierDefault` meta-annotation, controlled by the `-Xjsr305` compiler flag (`strict`/`warn`/`ignore`). You can also recover safety on the Kotlin side without touching Java by explicitly declaring the variable type (`val x: String? = javaCall()`). Annotations are the durable fix because they restore checking at every call site, not just one.

code

kotlin · 4 lines
kotlin
// Java: @Nullable String find();  @NotNull String id();
val n: String? = svc.find()    // forced nullable by annotation
val i: String  = svc.id()      // forced non-null by annotation
// Compiler flag: kotlinc -Xjsr305=strict ...

go deeper

for a junior

Knows adding @Nullable/@NotNull makes Kotlin enforce nullability instead of using platform types.

for a middle

Lists multiple recognized annotation families and the resulting Kotlin type, plus the Kotlin-side explicit-type fallback.

for a senior

Explains package defaults via JSR-305 and the -Xjsr305 enforcement modes for staged migrations.

for a principal

Sets an org policy: annotate owned Java, facade third-party libs, choose a jsr305 mode, and gate it in CI.

## Goal: turn `String!` back into `String` or `String?` Platform types exist only because the Java declaration lacks nullability information. Supply that information and Kotlin stops treating the value as a platform type. ## Annotations Kotlin understands Kotlin recognizes several annotation families on Java code (binary or source). The most common: - **JetBrains**: `org.jetbrains.annotations.@NotNull` / `@Nullable` — the canonical pair. - **JSR-305**: `javax.annotation.@Nonnull`, `@CheckForNull`, `@ParametersAreNonnullByDefault`. - **Android**: `androidx.annotation.@NonNull` / `@Nullable`. - **Jakarta / Eclipse JDT / Checker Framework / Lombok-generated** equivalents. Effect: ``` @NotNull String -> Kotlin String (non-null, compile-time enforced) @Nullable String -> Kotlin String? (must use ?. / ?: etc.) ``` Once annotated, the IDE no longer shows the `!` suffix and the compiler enforces null safety normally. ## Package- and module-wide defaults (JSR-305) Annotating every member is tedious. JSR-305 lets you set a **default** with a `@TypeQualifierDefault` meta-annotation, e.g. `@ParametersAreNonnullByDefault` on a `package-info.java`, so all parameters in that package are treated as non-null unless overridden by `@Nullable`. You can author custom defaults (e.g. `@MyNonnullApi`) and apply them at package or class scope. ## The `-Xjsr305` compiler flag How strictly Kotlin enforces JSR-305 annotations is configurable: - `-Xjsr305=strict` — treat them as real Kotlin types (errors on misuse). - `-Xjsr305=warn` — report warnings only (a common migration default). - `-Xjsr305=ignore` — ignore them (back to platform types). You can also target specific annotation qualifiers with `under-migration`/`@UnderMigration` to roll out gradually. ## Kotlin-side recovery without touching Java If you cannot annotate the Java source, declare the boundary type explicitly: ```kotlin val name: String? = legacyApi.find() // force nullable, handle with ?. val id = requireNotNull(legacyApi.id()) { "id required" } // assert non-null ``` This restores safety at that one site; annotations restore it at **all** sites, so prefer annotating shared/library Java when you own it. ## Summary table - Own the Java? -> add `@NotNull`/`@Nullable` (or package defaults). - Third-party Java? -> declare explicit Kotlin types at the boundary and guard with `requireNotNull`. - Tune enforcement with `-Xjsr305`.

  • If a third-party Java library has no annotations, what is the most robust Kotlin-side fix?
    Declare explicit nullable types at the boundary (`val x: T? = lib.call()`) and narrow with `requireNotNull`/`?:`, optionally wrapping the lib behind your own annotated facade.
  • What does `-Xjsr305=warn` buy you during a migration?
    Kotlin reports nullability violations as warnings instead of errors, letting a large codebase compile while teams progressively fix call sites.

saying these in an interview costs you the question

  • Believing Kotlin ignores all Java annotations
  • Thinking only JetBrains annotations are recognized
  • Confusing `@Nullable` (allows null) with `@NotNull` (forbids it)
  • Not knowing `-Xjsr305` exists or what its modes mean
  • Claiming you must edit Java to ever get safety (Kotlin-side typing also works)

context