284

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)
Sai
  • 15,188
  • 20
  • 81
  • 121

8 Answers8

354

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.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
miensol
  • 39,733
  • 7
  • 116
  • 112
102

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()
26

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 .

Levon Petrosyan
  • 8,815
  • 8
  • 54
  • 65
m.yuki
  • 815
  • 1
  • 10
  • 19
  • For those using kotlin dsl for gradle, define the plugin via: `id("org.jetbrains.kotlin.plugin.noarg") version "1.5.31"` – PaulNUK Nov 10 '21 at 11:02
  • Thank you for writing down this solution! This turned out to be the best workaround for a serialisation issue I ran into with fasterxml/jackson when updating Kotlin from 1.5.3 to 1.6.0, until the dependency is fixed – Rabie Jradi Jan 06 '22 at 18:13
  • it says it can be called only by using reflection – user2836943 Oct 11 '22 at 06:26
18

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).

Gui13
  • 12,993
  • 17
  • 57
  • 104
  • The last commend is wrong. At least for the Gson serializer, in fact, Gson uses the unsafe mechanism to create objects and it will not call your constructor. I have just answered a related question here https://stackoverflow.com/questions/59390294/what-should-i-do-if-i-dont-want-a-devired-class-call-base-classs-constructor-i/59393841#59393841 – Võ Quang Hòa Dec 18 '19 at 14:37
11

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")
yOshi
  • 820
  • 7
  • 12
10

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)
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
8

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.

Gastón Saillén
  • 12,319
  • 5
  • 67
  • 77
7

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)
Micer
  • 8,731
  • 3
  • 79
  • 73