How do @Nullable / @NotNull annotations on Java code change how Kotlin sees those values, and which annotation libraries does Kotlin recognize?
answer
- @NotNull -> String, @Nullable -> String?
- Promotes platform type to real type
- Matched by simple name across supported packages
- JetBrains, JSR-305, AndroidX, Spring, Lombok...
- @NotNull is a promise, can still lie -> NPE
basics
~20 sIf the Java code is annotated with @Nullable or @NotNull, Kotlin stops treating the value as a loose platform type and treats it as String? or String. Kotlin recognizes several common annotation libraries like JetBrains, JSR-305, and AndroidX.
solid answer
~40 sWhen a Java member carries a recognized nullability annotation, Kotlin **promotes the platform type into a real Kotlin type**: `@NotNull String` becomes non-null `String`, `@Nullable String` becomes nullable `String?`. This restores full null-safety — you must use `?.`/`!!` on the `@Nullable` one, and the compiler trusts the `@NotNull` one. Kotlin recognizes a fixed set of annotation packages, including JetBrains (`org.jetbrains.annotations`), JSR-305 (`javax.annotation`), Android (`androidx.annotation`, plus older `android.support`), Eclipse JDT, Lombok, and Spring's nullability annotations. The mapping is by simple name (`Nullable`/`NonNull`/`NotNull`), so any of those packages work. Annotated Java is the cleanest interop because it eliminates the silent NPE risk of bare platform types — the contract is enforced at the boundary.
go deeper
Knows @Nullable/@NotNull make Java values appear as String?/String in Kotlin.
Lists several recognized annotation libraries and explains promotion from platform type to a checked type at the boundary.
Notes the promise-not-guarantee nature of @NotNull and recommends annotating owned Java to remove the platform-type trap.
Sets org-wide policy: default-not-null packages, which annotation flavor to standardize on, migration to JSpecify.
## From platform type to real type An **unannotated** Java value gives Kotlin a **platform type** (`String!`) with relaxed checks. A nullability **annotation** removes the ambiguity: - `@NotNull`/`@NonNull` on a Java return -> Kotlin sees **`String`** (non-null). The compiler trusts it. - `@Nullable` on a Java return -> Kotlin sees **`String?`** (nullable). You **must** handle null with `?.`, `!!`, `?:`, or a smart cast after a null check. This matters because it moves the safety check **back to the boundary**: instead of a silent platform type that may NPE later, you get an ordinary Kotlin nullable type and the compiler enforces correctness. ## Recognized annotation libraries Kotlin matches by the annotation's **simple name** across a curated set of supported packages: - **JetBrains** — `org.jetbrains.annotations.Nullable` / `NotNull` - **JSR-305** — `javax.annotation.Nonnull` / `Nullable` (and `@TypeQualifierNickname`/`@TypeQualifierDefault` machinery) - **AndroidX** — `androidx.annotation.Nullable` / `NonNull` (and legacy `android.support.annotation.*`, `com.android.annotations.*`) - **Eclipse JDT** — `org.eclipse.jdt.annotation.*` - **Lombok** — `lombok.NonNull` - **Spring** — `org.springframework.lang.Nullable` / `NonNull` - **Checker Framework**, **FindBugs**, **RxJava** and others ```kotlin // Java: // @Nullable String getMiddleName() { ... } // @NotNull String getLastName() { ... } val mid = user.middleName // Kotlin type: String? -> must null-check val last = user.lastName // Kotlin type: String -> trusted non-null println(mid?.length) // safe call required println(last.length) // no ?. needed ``` ## Why use annotations - Eliminates the **late-NPE** trap of bare platform types. - The contract is **self-documenting** and machine-checked. - For libraries you own, annotating Java is the cheapest way to make Kotlin consumers safe. ## Caveats - A `@NotNull` is only a **promise**; if the Java code lies and returns null, you still NPE — annotations are not runtime-verified by Kotlin in general. - Default behavior can be set package-wide (see JSpecify / `@TypeQualifierDefault`) so you don't annotate every member.
- If a Java method is annotated @NotNull but actually returns null, what happens in Kotlin?Kotlin trusts the annotation and treats it as non-null, so you get an NPE when the null is dereferenced — the annotation is a promise, not a runtime guard.
- Does Kotlin require a specific annotation package, or just a matching name?It matches the simple name (Nullable/NotNull/NonNull) but only within a curated set of supported packages; an arbitrary custom @Nullable in your own package is not automatically honored.
saying these in an interview costs you the question
- Claiming any class named Nullable works regardless of package
- Saying @NotNull makes Kotlin runtime-verify non-nullness everywhere
- Thinking annotations have no effect and it's still a platform type
- Confusing @Nullable promotion with making the whole class nullable