Java-Kotlin Interoperability – Nullability

How to deal with differences in nullability between Java and Kotlin.

fun main() {
    val car = Car("blue", "Ford", "Focus", "SE", "fabric", 2015) // Using Java class, no difference
    // Remember, there are some differences: Java class may require primitive type, so may need to cater for this; also differences in access modifiers
    // Nullability: Kotlin protects against nullability, Java does not. IntellliJ has @NotNull and @Nullable annotations. For documentation only, Java does not enforce, but at least IDE should push for compliance.
    // If Kotlin sees these annotations it will map @NotNull to non-nullable and @Nullable to nullable
    car.colour = "green"
    println(car)
//    car.colour = null // Will throw IllegalArgumentException at compile-time due to @NotNull annotation in Java class
    var manufacturer = car.manufacturer
    println(manufacturer.javaClass) // So is this String variable nullable?
    manufacturer = null // This would be fine with either no annotation or with @Nullable in Java class
    println(manufacturer) // But...
    var model: String = car.model // Non-nullable Kotlin variable declared. We can use this to protect against null values coming in from Java code
//    model = null // Not allowed!
    var variant: String? = car.variant // If we make this variable nullable
    println(variant?.javaClass) // String? is not a subtype of Any as there is no equivalent in Java, so need to add ? to variant
//    var interior: String = car.interior // Not allowed since return type of getInterior is nullable, but Kotlin variable is non-nullable
    // In Java, if a variable is not defined as either Nullable or notNull it is called a platform type. These can't be created in Kotlin.
    // If there is a platform type Kotlin compiler appends the ! symbol to the end of the type, so look out for these in error messages:
    val colour: Int = car.colour // If you hover over car.colour you will see the Found: String! error message - platform type
    // If Java values are not annotated you should perform the usual null checks in Kotlin code - compiler won't do that for you
}
package academy.learnprogamming.javainteroperability;


import org.jetbrains.annotations.NotNull; // N.B. Had to prompt for download from Maven
import org.jetbrains.annotations.Nullable;

public class Car {

    private String colour;
    private String manufacturer;
    private String model;
    private String variant;
    private String interior;
    private int year;

    public Car(String colour, String manufacturer, String model, String variant, String interior, int year) {
        this.colour = colour;
        this.manufacturer = manufacturer;
        this.model = model;
        this.variant = variant;
        this.interior = interior;
        this.year = year;
    }

    public String getColour() {
        return colour;
    }

    public void setColour(@NotNull String colour) { // @NotNull comes from JetBrains, not Java. Not enforced by Java.
        this.colour = colour;
    }

    public String getManufacturer() {
        return manufacturer;
    }

    public void setManufacturer(@Nullable String manufacturer) {
        this.manufacturer = manufacturer;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getVariant() {
        return variant;
    }

    public void setVariant(String variant) {
        this.variant = variant;
    }

    public @Nullable String getInterior() {
        return interior;
    }

    public void setInterior(String interior) {
        this.interior = interior;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    @Override
    public String toString() {
        return "Car{" +
                "colour='" + colour + '\'' +
                ", manufacturer='" + manufacturer + '\'' +
                ", model='" + model + '\'' +
                ", variant='" + variant + '\'' +
                ", interior='" + interior + '\'' +
                ", year=" + year +
                '}';
    }
}