Access lateinit variable in Companion class [duplicate] - kotlin

I have a singleton class which i have implemented it in java fashion :
companion object {
#Volatile private lateinit var instance: TrapBridge
fun bridge(): TrapBridge {
if (!this::instance.isInitialized) {
synchronized(this) {
if (!this::instance.isInitialized) {
instance = TrapBridge()
}
}
}
return instance
}
}
now the problem is i can't use isInitialized property because it throws NoSuchFieldError exception :
java.lang.NoSuchFieldError: No field instance of type Lcom/sample/trap/model/TrapBridge; in class Lcom/sample/trap/model/TrapBridge$Companion; or its superclasses (declaration of 'com.sample.trap.model.TrapBridge$Companion' appears in /data/app/com.sample.trapsample-L9D8b2vxEQfiSg9Qep_eNw==/base.apk)
and i think it's because instance is class variable and not instance variable so i can't reference it with this keyword :/
also i can't check if it's null because it throws UninitializedPropertyAccessException :
lateinit property instance has not been initialized

Unfortunately this is a known issue, tracked here on the official Kotlin issue tracker.

I had the same issue and found another way to do this:
#Volatile
private lateinit var box: BoxStore
class BoxKeeper private constructor() {
companion object {
var instance: BoxStore
get() = box
set(_) {}
fun init(context: Context) {
if (::box.isInitialized.not())
box = MyObjectBox.builder().androidContext(context).build()
}
}
}

Related

MockK: mocking an jpa repository.save call

My code saves an object to database in some bigger method, but I don't need to test this.
So I want to mock the Repository.save method. But the save method returns the saved object.
I tried the following:
#MockK
private lateinit var mockJobRepository: JobRepository
val jobSlot = slot<Job>()
// ...
every { mockJobRepository.save<Job>(capture(jobSlot)) }
returns(jobSlot.captured)
But it throws an runtime error:
"lateinit property captured has not been initialized"
How do I just return the given argument in the mock?
Have you tried
private val mockJobRepository = mockk<JobRepository>()
?
I've notice #Mockk annotations on lateinit vars can be finicky
When using annotations, you have to tell Mockk at some point to initialize the annotated properties. Assuming you're using JUnit 5, you can do it by initializing mocks in #BeforeEach:
class Test {
#MockK
private lateinit var emailService: EmailService
#BeforeEach
fun setUp() {
MockKAnnotations.init(this)
}
}
...or just use the Mockk-Extension for JUnit:
#ExtendWith(MockKExtension::class)
class Test {
#MockK
private lateinit var emailService: EmailService
}
Btw. less verbose option than capturing the argument would be returnsArgument:
every { mockJobRepository.save<Job>(any()) } returnsArgument 0

Confused about Kotlin's companion object definition

When i reach the companion object section in the ebook "Kotlin in action" it said that:
"if you need to write a function that can be called
without having a class instance but needs access to the internals of a class, you can write it as a member of an object declaration inside that class"
As my understanding this means a function of the companion object can access the method and properties of the class that contain it. But when i try to implement this i can't access the members of the class from its companion object'function:
class Normal() {
var name: String = "hallo"
companion object {
fun printName() {
println(name) // ERROR!!! unresolved reference name
}
}}
Did i misunderstood about this concept?
Method inside companion are kind of static by default(compared to Java & also this is how you achieve static kind of things in Kotlin) and you can not access normal variable from static method.
Same is happening here.
Edit:-
The definition in book is confusing, A companion object is not part of an instance of a class. You can't access members from a companion object, just like in Java you can't access members from a static method. But in case of utility classes where you just need to perform some operation you can call Static method which create a new instance of class and the perform some functions.
For example you can check answer by #user8320224, I am also quoting his code here,
class Normal {
private var name: String = "hallo"
private fun printName() {
println(name)
}
companion object {
fun factoryNormal(): Normal {
val normal = Normal()
normal.printName()
normal.name = "new name"
normal.printName()
return normal
}
}
}
Static members have access to the internals of a class, for example private members
class Normal() {
private var name: String = "hallo"
private fun printName() {
println(name)
}
companion object {
fun factoryNormal(): Normal {
val normal = Normal()
normal.printName()
normal.name = "new name"
normal.printName()
return normal
}
}}
companion object is the same as public static final class in Java. Therefore you can't access to var name.
Maybe this will help you:
class Normal() {
companion object {
#JvmStatic
var name: String = "hallo"
// This annotation will be helpful if you are calling
// this from Java, so it goes like Normal.printName();
#JvmStatic
fun printName() {
println(name)
}
}
}
Now you can use this in Kotlin:
Normal.name = "new name"
Normal.printName()
and if you want to use this in Java, then:
Normal.setName("new name");
Normal.printName();
A companion object is the same as "static" in Java. It doesn't actually have any instance of your class in it. So if your printname() method just said println("Hello again!") you could do the following:
println(Normal().name) // creates a new instance of Normal class and prints "hallo"
Normal.printname() // Does not create a new instance of Normal class but instead just prints "Hello again!" since we can access static methods without requiring an instance of a class itself.
Note that we didn't actually create a new Normal in that second line (no constructor brackets). The printname() method can be thought of as belonging to the definition of a class, rather than an example or instance of that class.
It's rather like the manual for a car; it can reference and talk about the internals of a car, but you need to have an actual car to do anything fun with the manual.
We can access the internals of an instance of the class, if we have one. So passing in an instance of the class would work:
class Normal() {
private var name: String = "hallo"
companion object {
fun printName(normal : Normal) {
println(normal.name) // Note that I made the "name" var private
}
}}
The companion object can also access anything that's within the companion object itself, so this would also work:
class Normal() {
companion object {
private var name: String = "hallo"
fun printName() {
println(name) // Note I moved the "name" var into the companion object
}
}}
And you can combine these:
class Normal() {
private var name: String = "Vilpe89"
companion object {
private var greeting: String = "Hello "
fun printName(normal : Normal) {
println("$greeting ${normal.name}!")
}
}}
Now you could call the above code like this:
Normal.printname(Normal()) // uses Normal's companion object
// method on an instance of Normal,
// and prints "Hello Vilpe89!"
This is very different to what would happen if they were separate classes:
class Normal() {
private var name: String = "Vilpe89"
}
class Greeting() {
private var greeting: String = "Hello "
fun printName(normal : Normal) {
println("$greeting ${normal.name}!") // This won't compile, because
// Greeting can't see normal.name
// if it's private.
}
}

How to access instance variable in static companion object in Kotlin

I am trying to make utils for performing network operations in kotlin. I have below code where the primary constructor is taking Command and Context.
I am unable to access command variable in command.execute(JSONObject(jsonObj)), getting below error. I am not sure what is causing an issue?
Unresolved reference: command
class AsyncService(val command: Command, val context: Context) {
companion object {
fun doGet(request: String) {
doAsync {
val jsonObj = java.net.URL(request).readText()
command.execute(JSONObject(jsonObj))
}
}
}
}
A companion object is not part of an instance of a class.
You can't access members from a companion object, just like in Java you can't access members from a static method.
Instead, don't use a companion object:
class AsyncService(val command: Command, val context: Context) {
fun doGet(request: String) {
doAsync {
val jsonObj = java.net.URL(request).readText()
command.execute(JSONObject(jsonObj))
}
}
}
You should pass arguments directly to your companion object function:
class AsyncService {
companion object {
fun doGet(command: Command, context: Context, request: String) {
doAsync {
val jsonObj = java.net.URL(request).readText()
command.execute(JSONObject(jsonObj))
}
}
}
}

Kotlin static methods and variables

I want to be able to save a class instance to a public static variable but I can't figure out how to do this in Kotlin.
class Foo {
public static Foo instance;
public Foo() {
instance = this;
}
}
Update: since this answer is getting a decent amount of upvotes, I really wanted to say that you shouldn't do the below, but instead just use object Foo { ... }, like Roman rightly points out in the comment.
Previous answer:
The closest thing to Java's static fields is a companion object. You can find the documentation reference for them here: https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects
Your code in Kotlin would look something like this:
class Foo {
companion object {
lateinit var instance: Foo
}
init {
instance = this
}
}
If you want your fields/methods to be exposed as static to Java callers, you can apply the #JvmStatic annotation:
class Foo {
companion object {
#JvmStatic lateinit var instance: Foo
}
init {
instance = this
}
}
It looks that you want to define a singleton object. It is supported in Kotlin as a first-class concept:
object Foo {
...
}
All the boilerplate code with static field and constructor is taken care by the Kotlin automatically. You don't have to write any of that.
From the Kotlin code you can refer to the instance of this object simply as Foo. From the Java code you can referer to the instance of this object as Foo.INSTANCE, because the Kotlin compiler automatically creates the corresponding static field named INSTANCE.
first you create a simple class then after create a block followed by companion object keyword
for example:
class Test{
companion object{
fun getValue(): String{
return "Test String"
}
}
}
you can call this class function using class name dot function name
for example:
// here you will get the function value
Test.getValue()
You can create a companion object for the class, and if you want the field to be static you can use the annotation #JvmStatic. Companion object have access to private members of the class it is companion for.
See below an example:
class User {
private lateinit var name: String
override fun toString() = name
companion object {
#JvmStatic
val instance by lazy {
User().apply { name = "jtonic" }
}
}
}
class CompanionTest {
#Test
fun `test companion object`() {
User.instance.toString() shouldBe "jtonic"
}
}

How to set lateinit Kotlin property to null

The below class has a very unique lifecycle, which requires me to temporarily null out lateinit properties
class SalesController : BaseController, SalesView {
#Inject lateinit var viewBinder: SalesController.ViewBinder
#Inject lateinit var renderer: SalesRenderer
#Inject lateinit var presenter: SalesPresenter
lateinit private var component: SalesScreenComponent
override var state = SalesScreen.State.INITIAL //only property that I want to survive config changes
fun onCreateView(): View { /** lateinit variables are set here */ }
fun onDestroyView() {
//lateinit variables need to be dereferences here, or we have a memory leak
renderer = null!! //here's the problem: throws exception bc it's a non-nullable property
}
}
Here's how it's used by the framework.
controller.onCreateView() //same instance of controller
controller.onDestroyView() //same instance of controller
controller.onCreateView() //same instance of controller
controller.onDestroyView() //same instance of controller
My lateinit properties are injected by dagger, and I need to set them to null in onDestroyView - or have a memory leak. This however is not possible in kotlin, as far as I am aware (without reflection). I could make these properties nullable, but that would defeat the purpose of Kotlin's null safety.
I'm not quite sure how to solve this. Ideally there could be some type of annotation processor that would generate java code to null out specific variables automatically in onDestroyView?
Kotlin lateinit properties use null as an uninitialized flag value, and there's no clean way to set null in the backing field of a lateinit property without reflection.
However, Kotlin allows you to override the properties behavior using delegated properties. Seems like there's no delegate that allows that in kotlin-stdlib, but if you need exactly this behavior, you can implement your own delegate to do that, adding some code to your utils:
class ResettableManager {
private val delegates = mutableListOf<ResettableNotNullDelegate<*, *>>()
fun register(delegate: ResettableNotNullDelegate<*, *>) { delegates.add(delegate) }
fun reset() { delegatesToReset.forEach { it.reset() } }
}
class Resettable<R, T : Any>(manager: ResettableManager) {
init { manager.register(this) }
private var value: T? = null
operator fun getValue(thisRef: R, property: KProperty<*>): T =
value ?: throw UninitializedPropertyAccessException()
operator fun setValue(thisRef: R, property: KProperty<*>, t: T) { value = t }
fun reset() { value = null }
}
And the usage:
class SalesController : BaseController, SalesView {
val resettableManager = ResettableManager()
#set:Inject var viewBinder: SalesController.ViewBinder by Resettable(resettableManager)
#set:Inject var renderer: SalesRenderer by Resettable(resettableManager)
#set:Inject var presenter: SalesPresenter by Resettable(resettableManager)
fun onDestroyView() {
resettableManager.reset()
}
}