Empty second ctor in Kotlin - kotlin

data class UserRto(val lastName: String, val firstName: String, val email: String, val password: String) {
constructor() : this("", "", "", "")
}
Is this the easiest way to get a second ctor without arguments (for json desrialization)?

There is a convention (just for that case :) that a parameterless constructor is generated if all parameters have default values:
//Kotlin
data class UserRto(val lastName: String = "",
val firstName: String = "",
val email: String = "",
val password: String = "")
//Java
new UserRto();
new UserRto("a", "a", "a", "a");
Your solution with an explicit empty constructor has an advantage that all parameters must be provided, or non. But it is not a big deal in most cases and it is rarely used.

You do not specify which JSON deserialization library you are using. It is likely that you do not need this secondary constructor at all and can work directly with the class constructor that contains all of the properties as parameters.
For Jackson, use the Jackson-Kotlin module which automatically handles all of Kotlins unqiue cases including ability to call a constructor or factory with all of the parameters being properties (and in 2.8.x this includes default values for parameters being used for missing properties in the JSON)
For Gson, I think Kotson might do the same.
Google might find others for these or other libraries as well.
Then you would only need:
data class UserRto(val lastName: String, val firstName: String, val email: String, val password: String)
And with the Jackson-Kotlin module you would simply:
val user: UserRto = jacksonObjectMapper().readValue(jsonString)

Related

Kotlin get all property value of data class

Is there a syntactic sugar in Kotlin to iterate on each field/property value of a data class?
Sample:
data class User(
var firstName: String = DEFAULT_VALUE_STRING,
var middleName: String = DEFAULT_VALUE_STRING,
var lastName: String = DEFAULT_VALUE_STRING
)
val user = User()
Then check if any of the property's value is empty, considering all of it is String data type with something like this
if (user.properties.any{ it.isBlank() }) {
// TODO ...
}
Probably the closest you'll get is checking all the values of all the generated componentX() functions (since they're only created for the constructor parameter properties, the "data" in a data class) but yeah that involves reflection.
If I were you, I'd create an interface with a properties property and make all your data classes implement that - something like this:
import kotlin.reflect.KProperty0
interface HasStringProperties {
val properties: List<KProperty0<String>>
}
data class User(
var firstName: String = "",
var middleName: String = "",
var lastName: String = ""
) : HasStringProperties {
override val properties = listOf(::firstName, ::middleName, ::lastName)
}
fun main() {
val user = User("Funny", "", "Name")
println(user.properties.any {it.get().isBlank()})
}
So no, it's not automatic - but specifying which properties you want to include is simple, and required if you're going to access it on a particular class, so there's an element of safety there.
Also, because you're explicitly specifying String properties, there's type safety included as well. Your example code is implicitly assuming all properties on your data classes will be Strings (or at least, they're a type with an isBlank() function) which isn't necessarily going to be true. You'd have to write type-checking into your reflection code - if you say "I don't need to, the classes will only have String parameters" then maybe that's true, until it isn't. And then the reflection code has to be written just because you want to add a single age field or whatever.
You don't actually have to use property references in Kotlin either, you could just grab the current values:
interface HasStringProperties {
val properties: List<String>
}
data class User(
var firstName: String = "",
var middleName: String = "",
var lastName: String = ""
) : HasStringProperties {
// getter function creating a new list of current values every time it's accessed
override val properties get() = listOf(firstName, middleName, lastName)
}
fun main() {
val user = User("Funny", "", "Name")
println(user.properties.any {it.isBlank()})
}
It depends whether you want to be able to reference the actual properties on the class itself, or delegate to a getter to fetch the current values.
And of course you could use generics if you want, list all the properties and use filterIsInstance<String> to pull all the strings. And you could put a function in the interface to handle a generic isEmpty check for different types. Put all the "check these properties aren't 'empty'" code in one place, so callers don't need to concern themselves with working that out and what it means for each property

Meaning of val / var when using Kotlin Primary constructor

I have seen Kotlin-examples using a Primary-constructor like this:
class Person(firstName: String, lastName: String) {}
And I have seen example with the var or val keyword, like this:
class Person(val firstName: String, val lastName: String) {}
What the difference? When do I have to use which variation?
Regarding the documentation, with var or val in the constructor you create a property in the class. If you do not write it, then it is only a parameter that is passed to the constructor. As an example:
class Person(val firstName: String, lastName: String) {
// firstName and lastName accessible
fun getFirstName() = firstName // firstName accessible
fun getLastName() = lastName // lastName not accessible
}
So if you want to continue to use the firstName and lastName, I would make a property out of it.

How to establish getter & setter for secondary constructor in data class for kotlin?

I need a data class with two different constructors as shown. But how do I do getter & setter for the secondary constructor of data class in Kotlin? I tried multiple changes, not able to figure it out. In the below snippet, I am not getting the right import for get() and set()
data class user(var phone: String) {
constructor(phone: String, name : String) : this(phone) {
var name: String = name
get()= field
set(value) {
field = value
}
}
}
It appears you want two constructors, one which only requires a "phone" argument and another which requires both a "phone" and "name" argument. Overall, your data class will have two properties regardless of which constructor is used: phone and name. You could accomplish this with the following:
data class User(var phone: String) {
var name: String = ""
constructor(phone: String, name: String) : this(phone) {
this.name = name
}
}
However, as this is Kotlin, you should prefer default parameter values over overloaded functions/secondary constructors:
data class User(var phone: String, var name: String = "")

Why to put val or var in kotlin class constructors

Just learning Kotlin In the first code down below there is the val keyword right in the other code there is not,
what is the different here if the val and var is omitted?
class Person(val firstName: String, val lastName: String) {
}
class Person(firstName: String, lastName: String) {
}
If val or var is omitted then they won't be properties, but parameters passed to constructor. You won't be able to work with them outside of constructor.
If you omit val or var in in a constructor, then the only places that can access these parameters are initialization statements that are evaluated at construction time. See https://kotlinlang.org/docs/reference/classes.html
This is useful when you want to do something with a value before storing it. In Java you would put that code a constructor body
class Person(firstName: String, lastName: String) {
// directly in val / var declarations
val firstName = firstName.capitalize()
val lastName = lastName
// in init blocks
val fullName: String
init {
fullName = "$firstName $lastName"
}
// secondary constructors can only see their own parameters
// and nothing else can access those
constructor(fullName: String) : this("", fullName)
}
But it also works for delegation using by
interface Named {
fun getName(): String
}
class Human(private val fname: String, private val lname: String) : Named {
override fun getName() = "$fname + $lname" // functions need val since
// value is resolved after construction
}
class Person2(firstName: String, lastName: String) : Named by Human(firstName, lastName)
class Person3(human: Human) : Named by human {
constructor(firstName: String, lastName: String): this(Human(firstName, lastName))
}
Or in property delegation
class Person4(firstName: String, lastName: String) {
val fullName: String by lazy { "$firstName $lastName" }
}
Note: the closure is captured at initialization time, the values are therefore still available when lazy evaluates eventually.

Scala data model for read-only entities

I'm working on modeling entities that will be persisted in a DB. Using a User entity as an example, I'd like to work with them in this way:
val userBeforePersisting = new User("Joe", "joe#gmail.com")
// DB access code (where rs is a ResultSet)
val foundUser = new User(rs.getLong("id"), rs.getString("name"), rs.getString("email"))
I'd like to use the same User code (i.e. minimize code duplication), while having two types of users:
Pre-persisted users do not have an ID
Persisted users retrieved from the DB have an ID
I'd like to enforce this as strictly as possible at compile-time.
I'd like to be able to treat all Users the same, except if I try and get an ID from an un-persisted User, an error will be raised or it would not compile.
I'd like to avoid having to make separate classes like this
class NewUser(val name: String, val email: String)
class PersistedUser(val id: Long, val name: String, val email: String)
I don't like this solution because of the code duplication (name and email fields).
Here's kind of what I'm thinking:
class User(val id: Long, val name: String, val email: String) {
this(name: String, email: String) = this(0l, name, email)
this(id: Long, name: String, email: String) = this(id, name, email)
}
But then my un-persisted users have an id of 0l.
Here's another approach:
trait User {
val name: String
val email: String
}
class NewUser(val name: String, val email: String) extends User
class PersistedUser(val id: Long, val name: String, val email: String) extends User
This gives me the compile-time checks that I'd like. I'm not sure if there are any draw-backs to this.
Maybe I could try something like this:
class User(val name: String, val email: String)
trait Persisted { val id: Long }
class PersistedUser(val id: Long, val name: String, val email: String)
extends User(name, email)
with Persisted
Any thoughts to these approaches? I've never done it this way, so I'm not sure if I understand all the consequences.
Sounds like a possible use of Option.
class User(val id: Option[Long], val name: String, val email: String)
So persisted users have an id of Some(id) whereas non-persisted users have None.
As a convenience, you could grant id a default value of None:
class User(val id: Option[Long] = None, val name: String, val email: String)
// When you have an id...
val foundUser = new User(Some(rs.getLong("id")),
name = rs.getString("name"), email = rs.getString("email"))
// When you don't
val userBeforePersisting = new User(name = "Joe", email = "joe#gmail.com")
// However this will throw a runtime error:
val idThatDoesntExist: Long = userBeforePersisting.id.get
This should also work with your multi-constructor example:
class User(val id: Option[Long], val name: String, val email: String) {
def this(name: String, email: String) = this(None, name, email)
def this(id: Long, name: String, email: String) = this(Some(id), name, email)
}
I thought Option might make sense because you'd like to express in the same class that a certain field can either have a value or not. The only other way seems to be to have two classes (possibly one inheriting from the other) with only one having an id field.