Kotlin Serializable Classes

We are free to write our own serializable classes. All we need to do is have our class implement the java.io.Serializable interface to mark it as a candidate for serialization. All non-transient fields are written to the output stream and restored by the input stream. Here is a program that demonstrates using serialization with our own classes.

import java.io.*

data class Cook(val name : String = "Bob",
                val job : String = "Cook",
                @Transient val age : Int = 44) : Serializable

fun main(args : Array<String>){
    val file = "bob.ser"

    val tiredBob = Cook()
    println("Before Serialization")
    println(tiredBob)

    ObjectOutputStream(FileOutputStream(file)).use{ it -> it.writeObject(tiredBob)}

    println("Bob has been serialized")
    println()
    println("Time to wake Bob up")

    ObjectInputStream(FileInputStream(file)).use { it ->
        val restedBob = it.readObject()

        when (restedBob){
            is Cook -> {
                println("Does Bob remember his age?")
                println(restedBob)
            }
            else -> println("Failed to restore Bob")
        }
    }
}

Our program defines a Cook data class on lines 3-5. The class implements Serializable so it will work with the JVM serialization mechanism. The age property is annotated with @Transient, but more on that later.

The main method creates a tiredBob variable on line 10. On line 14, we open the file bob.ser by passing the name of the file to the FileOutputStream object. The FileOutputStream object is then passed to the constructor of the ObjectOutputStream object. We apply the use() function to make sure the file is closed when finished. The tiredBob object is written to disk by invoking the writeObject() method on the ObjectOutputStream object.

Restoring Bob is done on lines 20-30. Once again, we start by opening the bob.ser file by creating a FileInputStream object and passing the name of the file the constructor. The FileInputStream object is passed to the constructor of the ObjectInputStream object. We chain this operation with the use() function again to ensure the file is closed.

Line 21 restores Bob to memory by calling readObject(). The return type of readObject() is Any, so it’s up to us to down cast the object back into Cook. We do this on lines 23-28. On line 26, we print Bob to the console, but his age is 0. That’s because the age property is transient and therefore excluded from the serialization mechanism.

Transient Properties

Transient properties are defined by adding the @Transient annotation in front of the property (line 5). It’s used because the JVM only serializes primitives and Serializable objects. I once ran into a program where a class was mixed with Swing UI components and the state of the object needed to get sent over network sockets. The UI components were not serializable, so they were marked transient. Otherwise, the JVM would have failed to serialize the object and would have raised an exception.

This was a rather poor design, by the way. The class should have been designed with composition and have the data class separated from the UI components. However, that’s not how this program had been written. Either way, there are certain times where we would want to exclude serializable fields. A password field is a prime example of what should be marked transient.

However, it’s up to the developer to decide what should be included and not included in the serialized object. Kotlin provides the @Transient annotation to accomplish the task. Any object that isn’t @Transient will get included in the serialized object.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: