Kotlin data class with SerializedName annotations variables in init block

Viewed 3081

I have a data class below. Using coroutines and converting results as UserItem objects with gson.

The problem is, in the init block the object is still uninitialized and the nick, images etc. variables are empty. Where should I write the code in the init block?

data class UserItem(
    @SerializedName("username") val nick: String = "",
    @SerializedName("full_name") val fullName: String = 0,
    @SerializedName("info") val bio: String = "",
    @SerializedName("images") val images: List<String> = 
arrayListOf(),
    var imageType: ImageType = ImageType.NO_PHOTO
){
    companion object {
        @JvmStatic
        val DISPLAY_TYPE_USER = 0
        @JvmStatic
        val DISPLAY_TYPE_INFO = 1
    }

    enum class ImageType {
        NO_PHOTO, SINGLE_PHOTO, MULTIPLE_PHOTO
    }

    init {
        if (images.size == 1)
            imageType = ImageType.SINGLE_PHOTO
        else if (images.size > 1)
            imageType = ImageType.MULTIPLE_PHOTO
    }
}
1 Answers

What you have above works fine for me using kotlin 1.3.11 with a minor detail - @SerializedName("full_name") val fullName: String = 0 cannot be an integer, so I changed it to @SerializedName("full_name") val fullName: String = "".

In fact, running this:

fun main(args: Array<String>) {
  println(UserItem().imageType)
  println(UserItem(images = listOf("foo")).imageType)
  println(UserItem(images = listOf("foo", "bar")).imageType)
}

Outputs:

NO_PHOTO
SINGLE_PHOTO
MULTIPLE_PHOTO

Which according to your logic is correct. When you decompile the UserItem class you can see the following constructor:

public UserItem(@NotNull String nick, @NotNull String fullName, @NotNull String bio, @NotNull List images, @NotNull UserItem.ImageType imageType) {
  Intrinsics.checkParameterIsNotNull(nick, "nick");
  Intrinsics.checkParameterIsNotNull(fullName, "fullName");
  Intrinsics.checkParameterIsNotNull(bio, "bio");
  Intrinsics.checkParameterIsNotNull(images, "images");
  Intrinsics.checkParameterIsNotNull(imageType, "imageType");
  super();
  this.nick = nick;
  this.fullName = fullName;
  this.bio = bio;
  this.images = images;
  this.imageType = imageType;

  // This is what you have in the init block
  if (this.images.size() == 1) {
     this.imageType = UserItem.ImageType.SINGLE_PHOTO;
  } else if (this.images.size() > 1) {
     this.imageType = UserItem.ImageType.MULTIPLE_PHOTO;
  }
}

As you can see, the init block is inlined after the constructor. Maybe I misunderstood the problem?

PS: You can easily check the same by executing "Show kotlin byte code" and this will pop a window with a button "Decompile" which will show you the java code.

Related