JVM already provides a safety net in the form of bytecode verification, buffer overflow, type safety, etc.; Kotlin took this to a step further and baked null safety right into the type system. Which means we can deal with null at compile time rather than bumping into Null Pointer Exception. Nevertheless, we can still encounter NPE by:

Invoking external Java’s code which in turn can throw NPE.

Using !! operator

operator Explicitly throwing NPE

Using uninitialised this in a constructor (data inconsistency)

In this post, we will focus on how to take advantage of null safety mechanism when invoking Java’s code.

Java’s declarations are treated as platform(flexible) types in Kotlin. These types cannot be mentioned explicitly in the program, i.e. if we try to declare a variable of platform type, we will receive compilation error. E.g.

From Kotlin’s compiler perspective, it is a type that can be used as both nullable and non-nullable. Hence, there is no syntax in the language to represent them. The following mnemonic notation can be used to denote them:

When we try to invoke Java’s code from Kotlin; null checks are relaxed due to platform types. The way to leverage existing null-safety mechanism is by representing platform types as an actual Kotlin type (nullable or non-nullable). Digging in the source code of Kotlin’s compiler one can find various flavour of nullability annotation that aims to achieve this. Let’s see an example on how to use them.

We have a class called Message.java

When we invoke getEchoMessage() from kotlin, the compiler infers it as platform type. The infer type String! means the variable message may or may not have a String value. Due to this reason, the compiler cannot enforce us to do null handling on platform types.

Looking at the source code of getEchoMessage() one can spot that it always returns a non-nullable value. We can use @Nonnull annotation to document this. E.g.

Now the Kotlin compiler will no longer infer it as a platform type.

We can use one of the following values of When with @Nonnull:

When.ALWAYS – type will always be non-nullable. This is default option.

– type will always be non-nullable. This is default option. When.MAYBE/NEVER – type may be nullable.

– type may be nullable. When.UNKNOWN – type is resolved as platform one.

E.g.

Refactoring large codebase – leverage JSR-305 support

Note: Starting from Kotlin 1.1.50 we can use custom nullability qualifiers (both @TypeQualifierNickname and @TypeQualifierDefault are supported, for more details see this).

Let’s say we have a package in which majority of classes have methods that:

returns a non-nullable value.

takes non-nullable parameters.

Rather than editing each and every source file, we can introduce package level nullability/non-nullability behaviour and only override the exceptional cases. Let see how to do it.

One can start by creating a custom annotation, let’s call it @NonNullableApi

Note: When creating custom annotation such as @NonNullableApi it is mandatory to annotate it with both @TypeQualifierDefault and JSR-305 annotation such as @Nonull , @Nullable , @CheckForNull , etc.

E.g.

The following values of ElementType can be used with @TypeQualifierDefault(...) :

ElementType.FIELD – for fields

– for fields ElementType.METHOD – for methods return types

– for methods return types ElementType.PARAMETER – for parameters value

Next we need to apply our annotation for a particular package by placing it inside package-info.java . E.g.

After that we may override default behaviour (if needed) for a particular class/method parameter. E.g.

public String greet2(@Nonnull(when = When.MAYBE) String name) { return String.format("%s%s !!", greetingMessage, name); }

Finally, we need to configure JSR-305 checks by passing the compiler flag -Xjsr305 in build.gradle (or in specify file for different build tool).

The following compiler flags are supported:

-Xjsr305=strict – produce compilation error (experimental feature).

– produce compilation error (experimental feature). -Xjsr305=warn – produce compilation warnings (default behaviour)

– produce compilation warnings (default behaviour) -Xjsr305=ignore – do nothing.

Note: You can also pass those flags directly via command line in the absence of build tool.

E.g. -Xjsr305=warn

E.g.( -Xjsr305=strict )

You can find the complete source for this post here

Spring Framework 5 + null safety

Spring framework 5 introduced null-Safety in their code-base (see this & this). Bunch of annotations like @NonNullApi, @NonNullFields, etc. were introduced inside the package org.springframework.lang . These annotations use the similar approach described above i.e. they are meta-annotated with JSR-305. Kotlin developers can use projects like Reactor, Spring-data-mongo, Spring-data-cassandra, etc. with null-safety support. Please note, currently null-safety is not targeted for:

Varargs.

Generic type arguments.

Array elements nullability.

However, there is an ongoing discussion which aims to cover them.