POJO field declaration, set to init value or null - kotlin

In my POJO, i usually declare the fields like this
class SampleModel {
var field1: String? = null
var field2: Int? = null
<more fields here>
}
If I declare like this, I will need to check if the field is null or not.
But if like this:
class SampleModel {
var field1 = ""
var field2 = 0
<more fields here>
}
I can use it directly.
Does it matter on which declaration to use?
Like in terms of memory, performance, or anything that a good practice to do?
Lets say I have 100 fields.
Then I use Moshi or Gson for the deserializer.

In the end even beyond performance considerations is quality of code. If the fields will never actually be null in your use cases then I would not use nullable types. You are forcing yourself to do extra work (albeit Kotlin makes it somewhat easier) to cater for a scenario that it seems like you're saying isn't possible?
On the other side; if a field in the serialized were to be missing in this scenario you may not immediately catch it because the field in the class has a default value. If you're confident in the data being provided though this shouldn't be a problem.

IMO, memory and performance should not be taken into account when you are choosing between these two approaches. It depends on how you want the class to behave. To have a default value (approach 2) or null (approach 1). It matters when you need to handle logic of this class.

Related

Null safety issues with Gson in kotlin

I have a data class:
data class Temp(
val value: Int
)
When I run the following code:
val temp1 = Gson().fromJson("", Temp::class.java)
val temp2 = temp1.value
println(temp2)
I get null pointer exception.
Doesn't this violate the null safety of kotlin?
As far as I can remember, this has to do with the way that GSON makes use of reflection, which essentially can bypass kotlin null-safety, so the best thing you can do is mark all fields as potentially nullable and be safe, alternatively you could consider writing custom type adapters too, but that could be a bit much, as this null safety is only really valid for compile-time, but isn't really guaranteed during runtime
Generally, if you're making use of a third-party api which can change at any time, it's probably a good idea to consider the fact that stuff could be changed at any given time, changes in variable names or variables being removed, etc. If you're using your own api's, this is probably a bit different, as you'd (hopefully) have more control over the change, still doesn't hurt to manually implement null-safety though, assume everything can be null

Mockk: how to do assertEquals with using "any Class" as a field value of the expected object?

I'm trying to write a JUnit 5 test in Kotlin using Mockk. Assuming I have the following code that I want to test (it's a simplified example):
class AccountFactory {
fun createAccount(): Account {
return Account(
id = 1,
createdAt = Timestamp.from(Instant.now())
)
}
}
and my test looks like this:
#Test
fun createAccount() {
val actual = accountFactory.createAccount()
val expected = Account(id = 1, createdAt = ???)
assertEquals(expected, actual)
}
So I cannot figure out, how can I assign "any Timestamp" to createdAt field of the expected object? Checked Mockk docs, there are some examples using any() but only for mocked method arguments. Is it even possible to use something like this for assertions? If no, what is the better way of verifying the actual object other than checking every field value separately (which is not ideal in case new fields are added to Account later)?
You can divide the assertion into multiple ones as follows:
You check that the id is the same assertEquals(1, actual.getId())
You check that the Timestamp is not null assertNotNull(actual.getCreatedAt())
You check that the Timespamp belongs to the right class assertEquals(Timestamp.class, actual.getCreatedAt().class)
The above is the idea in pseudo-code as I do not know Kotlin. Anyway, the theory holds. You can't assert the two objects to be equals because of the timestamp, therefore you first check the constant value(s), then you make sure the timestamp is not Null and it is actually of the intended class. Furthermore, you might decide to assert the date from the timestamp is the same, though I would recommend you not to.
Cheers,
D

Kotlin: Prevent mixup of same typed parameters

How can I save the cats from being served for dinner?
data class Animal(
val name: String
)
data class ToDo(
val toEat: List<Animal>,
val toFeed: List<Animal>,
)
val cats = listOf(Animal("fluffy"))
val chickens = listOf(Animal("chic"))
// help the kittens!!!
ToDo(cats, chickens)
Note: This is a simplified example and I cant change the Type of cats/chickens to something like Cat/Chicken.
OOP solution
You could do the following:
Animal should be an interface.
Cat and Chicken should be two different implementation of Animal.
You could define an Interface named Eatable which will have concrete implementations.
Change val toEat: List<Animal> in val toEat: List<Eatable>
Cat will implement Animal and not Eatable
Another solution
Sorry but i read just now that you cannot define 2 different classes for Cat and Chicken.
You should still define this in Animal (pseudocode):
boolean eatable = false;
fun isEatable(): boolean {
return eatable;
}
So you can define Animal.eat(Animal) to check if the animal you are trying to eat could be eaten.
If you can't give them different types, then I don't think there's any way the compiler could spot this problem.  However, you could make it more obvious by simply giving the parameter names:
ToDo(toEat = chickens, toFeed = cats)
That way, it's very clear which list goes with which parameter.  (It also means that the order of the parameters doesn't matter; you can swap them, as long as each is given once.)
It would still compile if you mixed them up:
ToDo(toEat = cats, toFeed = chickens)
…but at least that would be obvious and doesn't need you to check the documentation to see the problem.
A caller could still choose to omit the parameter names, though.  To prevent that, you'd have to restructure the ToDo class.  For example, you could use the builder pattern, and give something like:
ToDo().toEat(chickens).toFeed(cats)
Or you could simply remove the parameters from the constructor, requiring the caller to set properties by name, e.g.:
ToDo().apply{ toEat = chickens; toFeed = cats }
Those are a little more long-winded to call, of course, but force the caller to give the property names explicitly — again, making the problem fairly obvious to human readers (if not to the compiler).

Translate API response to nullable String

An API I consume returns (among other fields) a mandatory telephone1 and an optional telephone2. However, the JSON I fetch always contains both fields and a missing entry is displayed as an empty string.
{
"telephone1": "+1 555 1234",
"telephone2": ""
}
When the response is mapped to a pojo, is it preferable to translate the empty string to null? Such that:
data class(
val telephone1: String,
val telephone2: String?
}
To me, this better communicates the possible states. Should I, though? Are there drawbacks?
At the first sight, problem boils down to different checks before further data processing: x == null or x.isEmpty(). But while nullability check is generally enforced by kotlin compiler (unlike unemptiness), it seems to be a better option.
But there are still some situations when usage of null (without any compiler errors) may lead to problems in runtime (mainly related to interop with languages without enforced nullability): like implicit convertion of null to literal string "null" (when concatenating with another string), or even NPE when passed to method accepting String! (platform type) and not annotated properly.
Sticking to DDD principles, the better option would be declaration of separate datatypes:
sealed class OptionalPhoneNumber
data class PhoneNumber(val value: String) : OptionalPhoneNumber() //You may also add some checks in init block that `value` is really a phone number, not just a set of random chars
object EmptyPhoneNumber : OptionalPhoneNumber()
and defining your data class as:
data class Data (
val telephone1: PhoneNumber,
val telephone2: OptionalPhoneNumber
)
Type system will enforce you to do x is PhoneNumber checks, and thanks to smart casts it's further usage will be type-safe:
if (telephone2 is PhoneNumber) {
println(telephone2.value)
}

Corda State Evolution - nullable vs. default properties

In Corda, adding new properties to states (state evolution) requires that new properties are nullable in order to remain backwards compatible with previous versions of the state.
data class Version1DummyState(
override val participants: List<AbstractParty>
) : ContractState
data class Version2DummyState(
override val participants: List<AbstractParty>,
val myNewProperty: String? = null
) : ContractState
Since Kotlin also supports properties with default values, I'd like to know why state evolution is restricted to properties of nullable types only, but not non-nullable properties, provided that those properties have a default value?
data class Version2DumyState(
override val participants: List<AbstractParty>,
val myNewProperty: String = "Hello, world."
) : ContractState
My rationale for asking this came from looking at the implicit upgrade sample, in which the obligation state is upgraded to allow the obligor to default on their obligation. true and false accurately represent whether the obligor has defaulted, but null does not. The ability to upgrade with a default value of false seems more natural than using a nullable field.
I think you can make that work by marking the constructor with #JvmOverloads like this:
data class DummyState #JvmOverloads constructor(
override val participants: List<AbstractParty>,
val myNewProperty: String = "blah"
) : ContractState
(don't put version numbers into state class names)
The #JvmOverloads makes the "old" constructors visible to the deserialisation engine for matching.
But, it's probably better to be explicit here with a line of code like:
val inDefault: Boolean get() = myNewProperty ?: false
or
fun priceOr(default: Amount<Currency> = 0.USD) get() = price ?: default
if you really want this.
Backwards compatibility and default values need to be treated quite carefully. A common mistake is to use a default value of zero/empty string/false for newly introduced fields, even when those values are semantically meaningful to the app. That is, knowing that the old message didn't specify something is valuable information that shouldn't be lost or replaced with fragile sentinel values. Consider the new field "price". Prices can't be negative, so perhaps a developer sets a default value of zero. But pricing something as free is a meaningful thing to do - maybe not in today's business scenario, but perhaps tomorrow? Now you have a problem.
Kotlin's type system and syntax is very good at dealing with missing values. It's so easy to substitute a default at the use-site using the ?: operator, I'd be worried about establishing a convention of always supplying a default at the construction site that junior devs follow without being aware of the potential consequences. Explicitly exposing the fact that a default may be substituted forces people to think about whether that's really logical.