How to define a no-argument constructor in Kotlin file with #Parcelize annotation [duplicate] - kotlin

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)

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.

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

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 .

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

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

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)

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.

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)

Related

Retrieve Item from realm sort by id

I've a realm class A in my android project -
open class A(
var id: Int? = null,
var level: String? = null,
var state: String? = null,
var updated_at: String? = null,
var created_at: String? = null,
var person: Person? = null
): RealmObject()
and Person -
open class Person(
var id: Int? = null,
var name: String? = null,
var email: String? = null,
var url: String? = null
): RealmObject()
I can retrieve list of items of class A sorted by Class A's id attribute -
fun getItemsOfA() : List<A> {
val listToBeReturn: MutableList<A> = mutableListOf()
DBManager.getRealm().executeTransection { realm ->
val tempList = realm.where(A::class.java).sort("id").findAll()
for (item in tempList) {
listToBeReturn.add(item)
}
And I'm getting sorted list. But I want to have a sorted list by the Person's id attribute instead of A's id. Any insight on this.
How can I achieve these?
Thanks & Regards

Map an object that having list inside to another object with the list

I am trying to map an object1 to another object2. but the object1 have a list in it.
This is my code. but when but I am getting error saying can not be cast.
This is the object I am getting from API
interface Api {
#GET("/api/")
fun getUsers(#Query("results") results: Int): Single<Dto.Users>
sealed class Dto {
data class Users(
#SerializedName("results") var resultDto: List<Result>
) : Dto()
data class Result(
var cell: String,
var email: String,
var gender: String,
var name: Name,
var nat: String,
var phone: String
) : Dto()
data class Name(
var first: String,
var last: String,
var title: String
) : Dto()
}
}
Another data class to map with.
sealed class Entity {
data class Users(
val results: List<Result>
) : Entity()
data class Result(
var cell: String,
var email: String,
var gender: String,
var name: Name,
var nat: String,
var phone: String
) : Entity()
data class Name(
var first: String,
var last: String,
var title: String
) : Entity()
}
This is extension function I am using to convert dto to entity.
Api.Dto.Users.map() = Entity.Users(
resultDto.map { result ->
Entity.Result(
result.cell,
result.email,
result.gender,
Entity.Name(result.name.first, result.name.last, result.name.title),
result.nat,
result.phone
)
}
)
And how I am using the extension function to convert dto to entity.
val data = dataFromServer.applyIoScheduler().map { userObj -> { userObj.map() } }
I tried to setup your example. As mentioned you missed Api, Dto, Entity. But after adding them, I got a working example (can compile). Because of the equal class name, it's not easy to understand it. Maybe you also struggled with it and linked the wrong types? Was this your intension?:
open class Entity {
data class Users(
var resultDto: List<Entity.Result>
) : Dto()
data class Result(
var cell: String,
var email: String,
var gender: String,
var name: Entity.Name,
var nat: String,
var phone: String
) : Dto()
data class Name(
var first: String,
var last: String,
var title: String
) : Dto()
}
open class Dto {
data class Users(
val results: List<Dto.Result>
) : Entity()
data class Result(
var cell: String,
var email: String,
var gender: String,
var name: Dto.Name,
var nat: String,
var phone: String
) : Entity()
data class Name(
var first: String,
var last: String,
var title: String
) : Entity()
}
fun Dto.Result.map(): Entity.Users {
return Entity.Users(
listOf(this).map { result ->
Entity.Result(
result.cell,
result.email,
result.gender,
Entity.Name(result.name.first, result.name.last, result.name.title),
result.nat,
result.phone
)
})
}

How to check existence of object in sublist in kotlin

How to verify the existence of sub-child object inside the parent object using kotlin
I am trying to find if the parent object (Module.kt) has an object of it's sub child list
Parent class : Module.kt
data class Module
(
var id: String? = ObjectId().toHexString(),
var name: String = "",
var description: String = " ",
var frames : MutableList<Frame> = mutableListOf<Frame>(),
var functions : MutableList<Function> = mutableListOf<Function>(),
var created_at: Date = Date(System.currentTimeMillis()),
var updated_at: Date = Date(System.currentTimeMillis())
)
Child class : Frame.kt
data class Frame (
var id: String? = ObjectId().toHexString(),
var name:String = "",
var level:String = "",
var moduleID:String = "",
var subFrames : MutableList<Frame> = mutableListOf()
)
Example : Cheking the existence of a submenu in the root menu
example image explanation
Use MutableMap instead
data class Module
(
var id: String? = ObjectId().toHexString(),
var name: String = "",
var description: String = " ",
var frames :MutableMap<String,Frame> = mutableMapOf(),
var functions : MutableList<Function> = mutableListOf<Function>(),
var created_at: Date = Date(System.currentTimeMillis()),
var updated_at: Date = Date(System.currentTimeMillis())
)
data class Frame (
var id: String? = ObjectId().toHexString(),
var name:String = "",
var level:String = "",
var moduleID:String = "",
var subFrames : MutableMap<String,Frame>? = mutableMapOf()
)
var module = Module()
module.frames["LAB"]?.subFrames?.get("CODE")?.subFrames?.get("HTML")?.name

In kotlin can i Init an object and set a paramater in one line

class:
class CameraBrandDto(override val id: Long = 0, override var dateCreated: Date = Date(), override var dateUpdated: Date = Date()) : DataTransportObject {
override var clazz = this.javaClass.simpleName.replace("Dto", "")
#NotBlank
#Size(max = 13)
var name: String = ""
var models: MutableSet<DtoMin> = mutableSetOf(DtoMin(0, "UNDEFINED", "UNDEFINED", Date(), Date()))
}
I would like to accomplish this in one line
val axisDto = CameraBrandDto()
axisDto.name = "AXIS"
is this possible???
Yes, just use the standard library function .apply { ... }, which executes the lambda with receiver on the object and returns that object:
val axisDto = CameraBrandDto().apply { name = "AXIS" }

Kotlin create object with params syntax

I have an object
class Person {
#JsonProperty("name")
var name: String? = null
#JsonProperty("id")
lateinit var id: String}
There is an only empty constructor and I want to create a person so I wrote:
val person = Person()
person.name = "someName"
person.id = "SomeId"
I'm pretty sure that there is a prettier syntax, something like
val person = Person {name = "someName" , id = "someId"}
but I can't find an example.
am I missing something? should I create a secondary constructor to use this syntax or is there another way?
Please check apply method.
Your code will be like this:
val person = Person().apply {name = "someName", id = "someId"}
Another way - you can change declaration of Person to (e.g. just change brackets, replace var to val and remove lateinit):
class Person (#JsonProperty("name") val name: String? = null,
#JsonProperty("id") val id: String )
Then you will able to do this:
val person = Person(name = "someName", id = "someId")
You can achieve it with the constructor parameter.
class Person(
#JsonProperty("name")
var name: String? = null,
#JsonProperty("id")
var id: String
)
val person = Person(name = "someName", id = "someId")
Another way is make your class and desired variables open to be overridden.
open class Person {
#JsonProperty("name")
open var name: String? = null
#JsonProperty("id")
open var id: String = ""
}
val person = object : Person() {
override var name: String? = "SomeName"
override var id = "SomeId"
}