How to create empty constructor for data class in Kotlin Android
AndroidKotlinAndroid 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:
-
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>() )
-
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)