How to convert an Object into a byte array in Kotlin

Viewed 9415

I have a Kotlin object that I need converted into a byte array (byte[]). I understand how to convert a String and a series of other kinds of variables into byte[], but I can't find anything on doing this with an object.

Here is what I've tried:

override fun activateQuestion(instructorUserName: String, host: String, port: Int, questionToActivate: MultipleChoiceQuestion) {
        val socket = DatagramSocket()

        //This is the problem -- `.toByteArray(...)` only works for Strings
        val questionToActivateAsByteArray = questionToActivate.toByteArray(Charsets.UTF_8)

        //send byte[] data 
        val packet = DatagramPacket(questionToActivateAsByteArray, questionToActivateAsByteArray.size, InetAddress.getByName(host), port)
        socket.send(packet)
    }
3 Answers

You can convert to bytearray in the java style. Something like this: Java Serializable Object to Byte Array

edit: to make it easier, its utility functions will look like this:

import java.io.*

@Suppress("UNCHECKED_CAST")
fun <T : Serializable> fromByteArray(byteArray: ByteArray): T {
    val byteArrayInputStream = ByteArrayInputStream(byteArray)
    val objectInput: ObjectInput
    objectInput = ObjectInputStream(byteArrayInputStream)
    val result = objectInput.readObject() as T
    objectInput.close()
    byteArrayInputStream.close()
    return result
}

fun Serializable.toByteArray(): ByteArray {
    val byteArrayOutputStream = ByteArrayOutputStream()
    val objectOutputStream: ObjectOutputStream
    objectOutputStream = ObjectOutputStream(byteArrayOutputStream)
    objectOutputStream.writeObject(this)
    objectOutputStream.flush()
    val result = byteArrayOutputStream.toByteArray()
    byteArrayOutputStream.close()
    objectOutputStream.close()
    return result
}

to use them is just to do something like:

val yourSerializableObject = YourSerializableObject(...)
val objectInByteArrayFormat = yourSerializableObject.toByteArray()
val convertedObject = fromByteArray<YourSerializableObject>(objectInByteArrayFormat)

Don't forget that your object and all its attributes must be serializable

The following is an object serializable class which is helpful to convert the object to bytes array and vice versa in Kotlin.

public class ObjectSerializer {
    companion object {
        public fun serialize(obj: Any?) : String {
            if (obj == null) {
                return ""
            }

            var baos = ByteArrayOutputStream()
            var oos = ObjectOutputStream(baos)
            oos.writeObject(obj)
            oos.close()

            return encodeBytes(baos.toByteArray())
        }

        public fun deserialize(str: String?) : Any? {
            if (str == null || str.length() == 0) {
                return null
            }

            var bais = ByteArrayInputStream(decodeBytes(str))
            var ois = ObjectInputStream(bais)

            return ois.readObject()
        }

        private fun encodeBytes(bytes: ByteArray) : String {
            var buffer = StringBuffer()

            for (byte in bytes) {
                buffer.append(((byte.toInt() shr 4) and 0xF plus 'a').toChar())
                buffer.append(((byte.toInt()) and 0xF plus 'a').toChar())
            }

            return buffer.toString()
        }

        private fun decodeBytes(str: String) : ByteArray {
            var bytes = ByteArray(str.length() / 2)

            for (i in 0..(str.length() - 1)) {
                var c = str.charAt(i)
                bytes.set(i / 2, ((c minus 'a').toInt() shl 4).toByte())

                c = str.charAt(i + 1)
                bytes.set(i / 2, (bytes.get(i / 2) + (c minus 'a')).toByte())
            }

            return bytes
        }
    }
}

Easiest way I've found with Kotlinx's serialization:

Mark your data class with @Serializable (if this isn't working for you, add the necessary plugins and dependencies to your build.gradle files).

@Serializable
data class User(val name: String, val age: Int)

Then when you create an instance of it, you convert it into a Json string into a byte array it via Json.encodeToString(yourInstance).toByteArray().

Example:

val user = User(Mohammed, 25)
val userAsByteArray = Json.encodeToString(user).toByteArray()
Related