How to create empty constructor for data class in Kotlin Android

AndroidKotlin

Android Problem Overview


I have 10+ variables declared in Kotlin data class, and I would like to create an empty constructor for it like how we typically do in Java.

Data class:

data class Activity(
    var updated_on: String,
    var tags: List<String>,
    var description: String,
    var user_id: List<Int>,
    var status_id: Int,
    var title: String,
    var created_at: String,
    var data: HashMap<*, *>,
    var id: Int,
    var counts: LinkedTreeMap<*, *>,
)

Expected usage:

val activity =  Activity();
activity.title = "New Computer"
sendToServer(activity)

But the data class requires all arguments to be passed while creating a constructor. How can we simplify this like the Java POJO class constructor?

val activity =  Activity(null,null,null,null,null,"New Computer",null,null,null,null)
sendToServer(activity)

Android Solutions


Solution 1 - Android

You have 2 options here:

  1. Assign a default value to each primary constructor parameter:

     data class Activity(
         var updated_on: String = "",
         var tags: List<String> = emptyList(),
         var description: String = "",
         var user_id: List<Int> = emptyList(),
         var status_id: Int = -1,
         var title: String = "",
         var created_at: String = "",
         var data: HashMap<*, *> = hashMapOf<Any, Any>(),
         var id: Int = -1,
         var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
     ) 
    
  2. Declare a secondary constructor that has no parameters:

     data class Activity(
         var updated_on: String,
         var tags: List<String>,
         var description: String,
         var user_id: List<Int>,
         var status_id: Int,
         var title: String,
         var created_at: String,
         var data: HashMap<*, *>,
         var id: Int,
         var counts: LinkedTreeMap<*, *>
     ) {
         constructor() : this("", emptyList(), 
                              "", emptyList(), -1, 
                              "", "", hashMapOf<Any, Any>(), 
                              -1, LinkedTreeMap<Any, Any>()
                              )
     }
    

If you don't rely on copy or equals of the Activity class or don't use the autogenerated data class methods at all you could use regular class like so:

class ActivityDto {
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
}

Not every DTO needs to be a data class and vice versa. In fact in my experience I find data classes to be particularly useful in areas that involve some complex business logic.

Solution 2 - Android

If you give default values to all the fields - empty constructor is generated automatically by Kotlin.

data class User(var id: Long = -1,
                var uniqueIdentifier: String? = null)

and you can simply call:

val user = User()

Solution 3 - Android

the modern answer for this should be using Kotlin's no-arg compiler plugin which creates a non argument construct code for classic apies more about here

simply you have to add the plugin class path in build.gradle project level

    dependencies {
    ....

    classpath "org.jetbrains.kotlin:kotlin-noarg:1.4.10"

    ....
    }

then configure your annotation to generate the no-arg constructor

apply plugin: "kotlin-noarg"

noArg {
      annotation("your.path.to.annotaion.NoArg")
      invokeInitializers = true
}

then define your annotation file NoArg.kt

 @Target(AnnotationTarget.CLASS)
 @Retention(AnnotationRetention.SOURCE)
 annotation class NoArg

finally in any data class you can simply use your own annotation

@NoArg
data class SomeClass( val datafield:Type , ...   )

I used to create my own no-arg constructor as the accepted answer , which i got by search but then this plugin released or something and I found it way cleaner .

Solution 4 - Android

Along with @miensol answer, let me add some details:

If you want a Java-visible empty constructor using data classes, you need to define it explicitely.

Using default values + constructor specifier is quite easy:

data class Activity(
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
) {
    constructor() : this(title = "") // this constructor is an explicit
                                     // "empty" constructor, as seen by Java.
}

This means that with this trick you can now serialize/deserialize this object with the standard Java serializers (Jackson, Gson etc).

Solution 5 - Android

If you give a default value to each primary constructor parameter:

data class Item(var id: String = "",
            var title: String = "",
            var condition: String = "",
            var price: String = "",
            var categoryId: String = "",
            var make: String = "",
            var model: String = "",
            var year: String = "",
            var bodyStyle: String = "",
            var detail: String = "",
            var latitude: Double = 0.0,
            var longitude: Double = 0.0,
            var listImages: List<String> = emptyList(),
            var idSeller: String = "")

and from the class where the instances you can call it without arguments or with the arguments that you have that moment

var newItem = Item()

var newItem2 = Item(title = "exampleTitle",
            condition = "exampleCondition",
            price = "examplePrice",
            categoryId = "exampleCategoryId")

Solution 6 - Android

From the documentation

> NOTE: On the JVM, if all of the parameters of the primary constructor > have default values, the compiler will generate an additional > parameterless constructor which will use the default values. This > makes it easier to use Kotlin with libraries such as Jackson or JPA > that create class instances through parameterless constructors.

Solution 7 - Android

Non-empty secondary constructor for data class in Kotlin:

data class ChemicalElement(var name: String,
					       var symbol: String,
					       var atomicNumber: Int,
					       var atomicWeight: Double,
					       var nobleMetal: Boolean?) {

    constructor(): this("Silver",
                        "Ag", 
                        47,
                        107.8682,
                        true)
}

fun main() {
    var chemicalElement = ChemicalElement()
    println("RESULT: ${chemicalElement.symbol} means ${chemicalElement.name}")
    println(chemicalElement)
}

// RESULT: Ag means Silver
// ChemicalElement(name=Silver, symbol=Ag, atomicNumber=47, atomicWeight=107.8682, nobleMetal=true)

Empty secondary constructor for data class in Kotlin:

data class ChemicalElement(var name: String,
					       var symbol: String,
					       var atomicNumber: Int,
					       var atomicWeight: Double,
					       var nobleMetal: Boolean?) {

    constructor(): this("",
                        "", 
                        -1,
                        0.0,
                        null)
}

fun main() {
    var chemicalElement = ChemicalElement()
    println(chemicalElement)
}

// ChemicalElement(name=, symbol=, atomicNumber=-1, atomicWeight=0.0, nobleMetal=null)

Solution 8 - Android

I'd suggest to modify the primary constructor and add a default value to each parameter:

data class Activity(
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
)

You can also make values nullable by adding ? and then you can assing null:

data class Activity(
    var updated_on: String? = null,
    var tags: List<String>? = null,
    var description: String? = null,
    var user_id: List<Int>? = null,
    var status_id: Int? = null,
    var title: String? = null,
    var created_at: String? = null,
    var data: HashMap<*, *>? = null,
    var id: Int? = null,
    var counts: LinkedTreeMap<*, *>? = null
)

In general, it is a good practice to avoid nullable objects - write the code in the way that we don't need to use them. Non-nullable objects are one of the advantages of Kotlin compared to Java. Therefore, the first option above is preferable.

Both options will give you the desired result:

val activity = Activity()
activity.title = "New Computer"
sendToServer(activity)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSaiView Question on Stackoverflow
Solution 1 - AndroidmiensolView Answer on Stackoverflow
Solution 2 - Androidkosiara - Bartosz KosarzyckiView Answer on Stackoverflow
Solution 3 - AndroidmxmlView Answer on Stackoverflow
Solution 4 - AndroidGui13View Answer on Stackoverflow
Solution 5 - AndroidyOshiView Answer on Stackoverflow
Solution 6 - AndroidGastón SaillénView Answer on Stackoverflow
Solution 7 - AndroidAndy JazzView Answer on Stackoverflow
Solution 8 - AndroidMicerView Answer on Stackoverflow