Java Records and Kotlin Data Classes

Java 14 comes with a new language feature called Records. Records make developers life easier by adding all the required code when dealing with data classes. Kotlin provides similar feature (data classes) and this article will highlight the similarities and the differences between them.

We frequently create classes whose main purpose is to hold data. In such a class some standard functionality and utility functions are often mechanically derivable from the data.
In Kotlin, this is called a data class

Data classes are declared by using the data keyword right before class:

data class Point(val x: Int, val y: Int)

The compiler automatically derives the following methods based on the declared properties:
equals()/hashCode()
toString()
copy()

So far it’s similar to what Java Records have except for the copy method. It’s a convenience method that allows to copy the object while altering some of its properties. Consider the following example:

data class Point (val x: Int, val y: Int

fun main(){
    val point = Point(1, 1)
    println(point)
    println(point.copy(x = 10))
    println(point.copy(y = 10))
}

And the output is:

Point(x=1, y=1)
Point(x=10, y=1)
Point(x=1, y=10)

It’s a very convenient feature which helps with immutability on the domain classes.

Another difference is that Kotlin’s data classes allow the properties to be mutable. Let’s take a look at the declaration again:

data class Point(val x: Int, val y: Int)

It declares each property as val which in Java terms is final which means that the following code won’t compile:

val point = Point(1, 1)
point.x = 10;

However, if declared using var (as in variable):

data class Point (var x: Int, var y: Int)

then the code below compiles:

val point = Point(1, 1)
point.x = 10

Mutable vs Immutable objects was a discussion where immutability won and the fact that the properties in a Java Record are all immutable by default is something I cherish. However I miss the convenience of the copy method. Hopefully it will appear in the future releases.

Just for completeness this is the Kotlin equivalent of the example covered in the Java Records article:

data class Rotator(val pitch: Int, val roll: Int, val yaw: Int)
data class Vector(val x: Int, val y: Int, val z: Int)
data class Transform(val rotation: Rotator, val translation: Vector, val scale: Vector) 

fun main() {
    val scale = Vector(1, 1, 1)
    val translation = Vector(100, 0, 0)
    val rotation = Rotator(0, 0, 90)
    val t1 = Transform(rotation, translation, scale) println(t1)
    println(t1.translation.x)
    println(t1.rotation.yaw)
}

JAXB With Kotlin

Kotlin is a programming language that runs on the Java Virtual Machine (JVM) and is designed to interoperate with Java code and thus with the existing frameworks.

For the purpose of this tutorial let’s imagine we develop a library application. As a first step let’s define a class that represents a book. A book has a name, author and description

About the Kotlin language: More on classes

As a second step let’s marshal a Book just to make sure everything is working:

About the Kotlin language: More on functions

Note: Here you can find more information on the Book::class.java expression

Running the application shows an error stating that: unable to marshal type "Book" as an element because it is missing an @XmlRootElement annotation Let’s add that annotation to the Book class and run the application again – this time another error is printed: Book does not have a no-arg default constructor. When we added the Book class we declared only one constructor (the primary one) which has three arguments. Let’s add another one in order to make JAXB happy:

The new constructor calls the primary one with default values. Kotlin has special opinion on null values (see here) and the developer must specially declare the null possibility. Since I agree that null should be avoided as a value, default values are provided in this case. Let’s run the application again. This time the output is:

The book element is empty because we didn’t add @XmlElement to the fields we want to marshal and we did not tell JAXB how to access the properties. Let’s fix that:

And here is the output:

So far so good. We have a working marshaling of a Book. Let’s organize books in a Library by adding a new class that will hold a collection of Books:

About the Kotlin language: More on collections

This time the library name won’t be an element but an attribute. Let’s marshal it:

And here is the output:

About the Kotlin language: More on try-with-resource

Let’s unmarshal it and print the contents of the Library

(yes Kotlin supports multi-line strings. It’s omitted here in sake of brevity)
Note:Since the Unmarshaller returns Object (not always but in this case it does) but we expect Library object then we use “unsafe” cast with as
This is the output: