I'm converting a Java project into Kotlin. I've converted a User object into Kotlin and when I run the existing JUnit tests in Java I'm getting a error between two instances of the Kotlin User object.
User.kt:
data class User (
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
var id: Long? = null,
...
)
TestUtil.java
import static org.assertj.core.api.Assertions.assertThat;
public class TestUtil {
public static void equalsVerifier(Class clazz) throws Exception {
Object domainObject1 = clazz.getConstructor().newInstance();
// Test with an instance of the same class
Object domainObject2 = clazz.getConstructor().newInstance();
assertThat(domainObject1).isNotEqualTo(domainObject2);
}
}
The assertThat(domainObject1).isNotEqualTo(domainObject2) test fails, as I believe in Java comparison is not done correctly on the Kotlin class. If I run this through a debugger, I can see that domainObject1 and domainObject2 are different instances.
Is it possible to get this test case to pass? The same test case is used for other Java classes, so it has to work for both Java and Kotlin classes.
The isNotEqualTo calls equals. The Kotlin class implements correct equals method for data class. So domainObject1.equals(domainObject2) is true. This behavior is correct.
just look at the AssertJ document:
isNotSameAs(Object other):
Verifies that the actual value is not the same as the given one,
ie using == comparison.
I think you should try:
assertThat(domainObject1).isNotSameAs(domainObject2);
In Kotlin, equals() is generated automatically for data class to check for equality of the properties.
Quote from "Kotlin in Action":
The generated equals() method checks that the values of all the properties are equal. ... Note that properties that aren’t declared in the primary constructor don’t take part in the equality checks and hashcode calculation.
If you want to pass the test case without modifying it, you may override equals() of your data class to check for referential equality.
override fun equals(other: Any?) = this === other
Note that it may affect your other code, if there is any function which relies on structural equality of your data class. So, I suggest that you refer to #shawn's answer to change your test case instead.
Related
I am trying to understand concept of inline classes - they are a simple object wrapper of single property that is being inlined during runtime.
That means, that the actual initialization of the class is not happening at runtime
I was trying to write simple test which directly will show my above explanation during JUnit test as below:
companion object {
private const val NAME = "JACK"
}
inline class NameInlineClass(val value: String)
#Test
fun unwrapping() {
val nameInlineClass = NameInlineClass(NAME)
val name = nameInlineClass
assertEquals(name, NAME)
}
This test fails unfortunately which leads me to the question why during assertEquals() the actual unwrapped String value is not being compared, but the actual inline class (which should be unwrapped during runtime)?
What you probably wanted to do was val name = nameInlineClass.value, but I'll try to explain the error.
See Representation from docs (includes code sample):
In generated code, the Kotlin compiler keeps a wrapper for each inline
class. Inline class instances can be represented at runtime either as
wrappers or as the underlying type. This is similar to how Int can be
represented either as a primitive int or as the wrapper Integer.
That means as long as you don't reference the wrapping object or its type explicitly, value will not be boxed. We can check it by inspecting bytecode (decompiled back to Java for readability):
// kotlin source
fun unwrapping() {
val nameInlineClass = NameInlineClass(NAME)
val name = nameInlineClass // this line gets dropped by compiler by the way
assertEquals(name, NAME)
}
// java representation of bytecode
public final void unwrapping() {
String nameInlineClass = NameInlineClass.constructor-impl("JACK");
Assert.assertEquals(NameInlineClass.box-impl(nameInlineClass), "JACK");
}
I won't paste entire generated NameInlineClass body, but constructor-impl is static method that only checks for null of value, and box-impl creates the wrapper object.
You can see nameInlineClass is indeed a String - that means inline works and no extra object was allocated.
Only when you reference nameInlineClass instead of nameInlineClass.value compiler determines that this object needs representation and "boxes" the value with wrapper NameInlineClass class.
Kotlin has three types that are very similar in nature:
Void
Unit
Nothing
It almost seems like they're making the JavaScript mistake:
null
undefined
void(0)
Assuming that they haven't fallen into the same mistake, what are they all for, and how do they differ?
The Void type is from Java. You generally won't use this from Kotlin unless you're using some Java-library that uses it.
The Unit type is what you return from a function that doesn't return anything of interest. Such a function is usually performing some kind of side effect. The unit type has only one possible value, which is the Unit object. You use Unit as a return type in Kotlin when you would use void (lowercase v) in Java.
The Nothing type has no values. If a function has return type Nothing, then it cannot return normally. It either has to throw an exception, or enter an infinite loop. Code that follows a call to a function with return type Nothing will be marked as unreachable by the Kotlin compiler.
Because Nothing has no values, Nothing? is actually the type that captures only the null value in Kotlin.
Unit
Unit is like void
In Kotlin, when a function does not return any meaningful value, it is declared to return Unit, just like void in Java:
fun greet(): Unit { println("Good day!") }
It's a convention to skip writing Unit when a function returns Unit because Unit is considered the default return type by the compiler:
fun greet() { println("Good day!") }
Unit is a Singleton
The Unit is a class with only a single object (singleton pattern) and that object is the Unit itself. It is declared in the kotlin package using an object declaration as shown below:
public object Unit {
override fun toString() = "kotlin.Unit"
}
Unit in Functional Programming
Kotlin has first-class support for functional programming. It's common to have a Unit in a functional programming language. It makes the function types more readable by enabling all the functions to be declared as having a return value, even when a function does not return a value:
val greet: () -> Unit = { println("Good day!") }
Here, () -> Unit is a function type and the Unit after the -> indicates that this function type does not return any meaningful value. Mentioning the Unit cannot be skipped in function types.
Unit for Extending Generics
Every function has to return a value. Kotlin decided to represent this with a class rather than with a special type void as in Java. The reason for using a class is that the type system can be made more consistent by making it a part of the type hierarchy.
For example, let's say we have a generic interface called Worker<T> that performs some work. The doWork() function of this interface does some work and has to return a value T:
interface Worker<T> {
fun doWork(): T
}
But sometimes, we might want to use this interface for some work where we don't need to return any value, for example, the work of logging, in the LogWorker class shown below that extends the Worker interface:
class LogWorker : Worker<Unit> {
override fun doWork() {
// Do the logging
}
}
This is the magic of Unit where we are able to use the pre-existing interface that was originally designed to return a value. Here we make the doWork() function return the Unit value to serve our purpose in which we don't have anything to return. So, it's useful when you override a function that returns a generic parameter.
Notice that we have also skipped mentioning Unit return type for the doWork() function. There's no need to write a return statement either.
Nothing
Nothing's Value Never Exists
In Kotlin, the class Nothing represents a value that never exists. There can never be any value/object of this class because its constructor is kept private. It's defined in the kotlin package as follows:
public class Nothing private constructor()
Nothing is used for the return type of a function that never returns a value. For example, a function with an infinite loop or a function that always throws an exception. The error() function from Kotlin standard library is an example that always throws an exception and returns Nothing. Here is the code for it:
fun error(message: Any): Nothing = throw IllegalStateException(message.toString())
Nothing is the Bottom Type
In type theory, the type that has no values is called a bottom type and it is a subtype of all other types. So, Nothing is the subtype of all types in Kotlin, just like Any? is the supertype of all types. So, the value(that never exists) of type Nothing is assignable to the variables of all types, for example:
val user: User = request.user ?: error("User not found")
Here, we are calling the error() function that we defined earlier, if the user is null, using the elvis operator(?:). The error() function returns the value of type Nothing but it can be assigned to the variable of type User because Nothing is a subtype of User, just like it is a subtype of any other type. The compiler allows this because it knows that the error() function will never return a value, so there is no harm.
Similarly, you can return Nothing from a function that has any other return type:
fun getUser(request: Request): User {
return request.user ?: error("User not found")
}
Here, even though the getUser() function is declared to return a User, it may return Nothing, if the user is null.
Nothing in Null Object Pattern
Consider the following example of a function that deletes the files given in a list:
fun deleteFiles(files: List<File>? = null) {
if (files != null) files.forEach { it.delete() }
}
The problem with the design of this function is that it doesn't convey whether the List<File> is empty or null or has elements. Also, we need to check whether the list is null before using it.
To solve this problem, we use the null object design pattern. In null object pattern, instead of using a null reference to convey the absence of an object, we use an object which implements the expected interface, but leaves the method body empty.
So, we define the object of the interface List<Nothing>:
// This function is already defined in the Kotlin standard library
fun emptyList() = object : List<Nothing> {
override fun iterator(): Iterator<Nothing> = EmptyIterator
...
}
Now we use this null object in our deleteFiles() function as a default value of our parameter:
fun deleteFiles(files: List<File> = emptyList()) {
files.forEach { it.delete() }
}
This removes the uncertainty of null or empty and makes the intent clearer. It also removes the null checks because the functions on the null object are empty, they will be called but they are no-ops (no operation in them, so they will do nothing).
Nothing for Covariant Generics
In the example above, the compiler allows us to pass List<Nothing> where List<File> is expected. This is because the List interface in Kotlin is covariant since it's defined using the out keyword, that is, List<out T>. And as we learnt, Nothing is a subtype of all types, Nothing is a subtype of File too. And due to covariance, List<Nothing> is a subtype of List<File>, List<Int>, List<User> and so on... List<AllTypes>. This applies to any type with the covariant generics(out), not just List.
Nothing for Better Performance
Just like the function emptyList() used in our example, there are predefined functions like emptyMap(), emptySet(), emptySequence() that return null objects. All these are defined using Nothing. You can define your own objects like this.
The advantage here is that these return singleton objects, for example, you can call the same emptyList() function for getting an empty instance, whether it is for assigning to List<File>, List<Int> and ... List<AllTypes> and in multiple places. Since the same object is returned every time, it saves the cost of object creation and memory allocation.
Void
Void for Extending Generics in Java
The Void class is from the java.lang package while the Unit and Nothing are from the kotlin package. Void is not intended to be used in Kotlin. Kotlin has its own class in the form of Unit.
Void is used in Java for extending generic interfaces like our Worker interface example written for Unit where we have to return a value. So for converting our Kotlin code to Java, we can use Void the same way we have used Unit for our Worker example and rewrite the code in Java as follows:
interface Worker<T> {
T doWork();
}
class LogWorker implements Worker<Void> {
#Override public Void doWork() {
// Do the logging
return null;
}
}
Notice that when using Void, we have to use Void as a return type(can't skip) as well as need to write the return statement whereas for Unit we can skip both. This is another reason to avoid using Void in Kotlin code.
Conclusion
So, Unit and Nothing are not a mistake by Kotlin designers in my opinion and are not as questionable as null, undefined and void(0) in Javascript. Unit and Nothing make the functional programming a breeze while providing other useful features mentioned. They are common in other functional programming languages too.
That's it!
Void is uninstantiable type. It is a plain Java class and has no special meaning in Kotlin.
Unit type has only one value. Replaced Java void (notice: not Void). More info in Kotlin docs.
Nothing has no instances (just like Void). It represents "a value that never exists". In Kotlin if you throw an error it is a Nothing (see Kotlin docs).
I would like to semantically constrain a map to only accept "data" class object types as the value in kotlin like so:
class Test(
val test : Int
)
data class Test2 (
val test : Int
)
fun test(map : Map<String, /* compile error on Test, but accept Test2 or any other data class */>) {
}
I'm mainly trying to do this so that I can keep everything in the map cloneable, but when I do this:
fun <T: Cloneable> test(map : Map<String, T>) {
// test clone
map.map { it.key.uuid to it.value.clone() } .toMap() // error on .clone() Cannot access 'clone': it is protected in 'Cloneable'
}
but I thought implementing the Cloneable interface made your clone method public? Essentially I'm looking for a compile time guarantee that all data is copyable in that method invocation, (is a primitive type, a data class that I can call .copy() on, or any object that has implemented Cloneable). Is my only option reflection and runtime assertions?
I thought implementing the Cloneable interface made your clone method public?
No, it's simply a marker interface, which tells the protected Object.clone() method not to throw a CloneNotSupportedException. In practice, classes that implement Cloneable will usually override clone() and make it public, but that's not necessary. And of course that's no help when you don't know the exact type!
The cloning mechanism was an early part of Java, and not very well-designed. (Effective Java calls it “a highly atypical use of interfaces and not one to be emulated”.) But it's still used, so we're stuck with it…
(See also these related answers.)
I don't know whether this is the best way or not, but how about you to use property like below.
SomeClass::class.isData
Kdoc says
true if this class is a data class.
I've bumped into this code and I'm not sure why would anyone do this. Basically the author decided for making the class constructor private so that it cannot be instantiated outside the file, and added a public method to a companion object in the class that creates a new instance of this class. What is the benefit of this approach?
This is what I found:
class Foo private constructor(private val arg1: Any) {
//more code here..
companion object {
fun newFoo(arg1: Any) = Foo(arg1 = arg1)
}
}
Why is it better than this?
class Foo(private val arg1: Any) {
//more code here..
}
There are several benefits to providing a factory method instead of a public constructor, including:
It can do lots of processing before calling the construstor. (This can be important if the superclass constructor takes parameters that need to be calculated.)
It can return cached values instead of new instances where appropriate.
It can return a subclass. (This allows you to make the top class an interface, as noted in another answer.) The exact class can differ between calls, and can even be an anonymous type.
It can have a name (as noted in another answer). This is especially important if you need multiple methods taking the same parameters. (E.g. a Point object which could be constructed from rectangular or polar co-ordinates.) However, a factory method doesn't need a specific name; if you implement the invoke() method in the companion object, you can call it in exactly the same way as a constructor.
It makes it easier to change the implementation of the class without affecting its public interface.
It also has an important drawback:
It can't be used by subclass constructors.
Factory methods seem to be less used in Kotlin than Java, perhaps due to Kotlin's simpler syntax for primary constructors and properties. But they're still worth considering — especially as Kotlin companion objects can inherit.
For much deeper info, see this article, which looks at the recommendation in Effective Java and how it applies to Kotlin.
If you want to change Foo into an interface in the future the code based on the method will keep working, since you can return a concrete class which still implements Foo, unlike the constructor which no longer exists.
An example specific to android is, that Fragments should be constructed with an empty constructed, and any data you'd like to pass through to them should be put in a bundle.
We can create a static/companion function, which takes in the arguments we need for that fragment, and this method would construct the fragment using the empty constructor and pass in the data using a bundle.
There are many useful cases, for example what Kiskae described. Another good one would be to be able to "give your constructors names":
class Foo<S: Any, T: Any> private constructor(private val a: S, private val b: T) {
//more code here...
companion object {
fun <S: Any> createForPurposeX(a: S) = Foo(a = a, b = "Default value")
fun createForPurposeY() = Foo(a = 1, b = 2)
}
}
Call site:
Foo.createForPurposeX("Hey")
Foo.createForPurposeY()
Note: You should use generic types instead of Any.
I'm trying to get annotations from Kotlin data class
package some.meaningless.package.name
import kotlin.reflect.full.memberProperties
annotation class MyAnnotation()
#MyAnnotation
data class TestDto(#MyAnnotation val answer: Int = 42)
fun main(args: Array<String>) {
TestDto::class.memberProperties.forEach { p -> println(p.annotations) }
println(TestDto::class.annotations)
}
I need to process class annotation to make a custom name serialization of GSON however no matter how I declare annotation class it never gets detected
The program always outputs
[]
[#some.meaningless.package.name.MyAnnotation()]
which means only class level annotations are present
Ok,
it seems that the culprit was, that Kotlin annotations have default #Target(AnnotationTarget.CLASS) which is not stressed enough in documentation.
After I added #Target to the annotation class it now works properly
#Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
annotation class MyAnnotation()
Now it prints out
[#some.meaningless.package.name.MyAnnotation()]
[#some.meaningless.package.name.MyAnnotation()]
As a side affect it will force the compiler to check that the annotation is applied as required, in current version of Kotlin, if explicit #Targetis not present only class level annotations are kept but no validity checks performed.
As Kotlin reference said as below:
If you don't specify a use-site target, the target is chosen according to the #Target annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following: param > property > field.
To make the annotation annotated on a property, you should use site target, for example:
#MyAnnotation
data class TestDto(#property:MyAnnotation val answer: Int = 42)
However, annotations with property target in Kotlin are not visible to Java, so you should double the annotation, for example:
#MyAnnotation // v--- used for property v--- used for params in Java
data class TestDto(#property:MyAnnotation #MyAnnotation val answer: Int = 42)