Extension property inside class: Unresolved reference: errorResponse - kotlin

In my android project:
// Extension Properties
val Response<*>.errorResponse: ErrorResponse
get() = ErrorUtils.parseError(this)
class TransportService {
companion object {
private val SERVICE_UNAVAILABLE_CODE = 503
private val traderMonitorRestClient = RestClientFactory.createRestClient(TraderMonitorRestClient::class.java)
private val serviceUnavailableErrorResponse: Response<*>
}
and here use extension property
class TradersViewModel(application: Application) : AndroidViewModel(application) {
val errorResponse = response.errorResponse
}
nice it's work,
But if I move errorResponse inside class:
class TransportService {
companion object {
private val SERVICE_UNAVAILABLE_CODE = 503
private val traderMonitorRestClient = RestClientFactory.createRestClient(TraderMonitorRestClient::class.java)
private val serviceUnavailableErrorResponse: Response<*>
private val TAG = TransportService::class.java.name
val Response<*>.errorResponse: ErrorResponse
get() = ErrorUtils.parseError(this)
}
}
then I get compile error in use place:
val errorResponse = response.errorResponse
error:
Unresolved reference: errorResponse

This is because the errorResponse extension is only available in the context of the companion object of TransportService when you define it there.
If your extension function doesn't need the companion's properties or methods, there is no real reason to put the extension there. Don't be afraid of polluting the global scope. Technically, you're only defining this extension on your Response object.
That being said, if you really need the companion object's context for your extension function (e.g. if the body of your extension property uses some methods or properties of the companion), you can manually provide the context on the usage site this way:
val errorResponse = with(TransportService.Companion) { response.errorResponse }
This is not limited to companion objects, you just need to provide an instance of the class that contains the extension to with(instance).

Related

Kotlin: Hashmap of interface methods by the implementing class name

I have a list of clases that implement a specific interface. The ability to construct those clases or not is not static (so it's not possible to use when(className)), and can be configured so I want to be able to create some clases or call some methods based on a hashMap of allowed "constructors". Then if the key identifying a class is in present in the hashmap I can call the corresponding method, otherwise I can safely ignore. Let me illustrate:
Let's say I have an interface like
interface Instanceable {
data class Config(
val bar: Whatever
)
fun getIntance(config: Config): Instanceable
}
Then I have several (let's say 10) classes that implement this interface
class Implementation1() : Instanceable {
companion object {
const val ID = "INSTANCE_1"
}
private lateinit var foo: Whatever
override fun getIntance(config: Config) = Implementation1().also{ this#Implementation1.foo = config.bar }
}
I want to create a hashmap of the methods by the identifiers, so later down the lane I can grab the method from the hashMap by the key ID and just invoke() the value if it's there. Something like:
allowedInstances("INSTANCE_1")?.let{ it.invoke(someConfig) }
In order to do this I tried to create a hashMap of methods like this:
private val allowedInstances = mutableHashMapOf<String, Instanceable.(Instanceable.Config)->Instanceable>()
allowedInstances[Instance1.ID] = Instance1::getIntance
allowedInstances[Instance2.ID] = Instance2::getIntance
allowedInstances[Instance4.ID] = Instance4::getIntance
But it fails with:
Type mismatch.
Required: Instanceable.(Instanceable.Config) → Instanceable
Found: KFunction2<Implementation1, Instanceable.Config, Instanceable>
If I create the hashmap directly and let the compiler infer the types like this:
private val allowedInstances = mutableHashMapOf(
Implementation1.ID to Implementation1::getIntance,
Implementation2.ID to Implementation2::getIntance,
Implementation4.ID to Implementation4::getIntance,
)
Checking the type of the hashmap shows:
HashMap<String, out KFunction2<Nothing, Instanceable.Config, Instanceable>>
In fact I can do:
private val allowedInstances = mutableHashMapOf<String, Nothing.(Instanceable.Config)->Instanceable>()
allowedInstances[Instance1.ID] = Instance1::getIntance
allowedInstances[Instance2.ID] = Instance2::getIntance
allowedInstances[Instance4.ID] = Instance4::getIntance
So the actual question is:
Why the function of the second hashMap parameter has Nothing as the receptor? Why I cannot have the interface Instanceable instead?
Edit: Still not good to have the Nothing there:
allowedInstances["INSTANCE_1"]?.let{ it.invoke(Nothing, someConfig) }
//Fails with: Classifier 'Nothing' does not have a companion object, and thus must be initialized here
Edit 2: All of the errors are in compile time
Your function type
Instanceable.(Instanceable.Config) -> Instanceable
is describing an extension function on an instance of Instanceable. You need to omit the receiver from the function type to be able to match your constructors' signature:
(Instanceable.Config) -> Instanceable
Edit: The other half of the problem is that you define getInstance() as a member function of the class. So you have to create an invalid instance of your class to use to create a valid instance, which doesn't make sense.
I would delete the getInstance() function from your interface, and put the equivalent code in the constructor of your class. Then you can define a function type in your Map that constructs your items.
interface Instanceable {
data class Config(
val bar: Whatever
)
// REMOVE this: fun getIntance(config: Config): Instanceable
}
class Implementation1(config: Config) : Instanceable {
companion object {
const val ID = "INSTANCE_1"
}
private val foo: Whatever = config.bar
}
private val allowedInstances = mutableHashMapOf<String, (Instanceable.Config)->Instanceable>()
allowedInstances[Instance1.ID] = ::Implementation1
// and so on...
// If there's an implementation that has no config, you can use a lambda:
class NoConfigImplementation : Instanceable {
companion object {
const val ID = "INSTANCE_2"
}
}
allowedInstances[NoConfigImplementation.ID] = { _ -> NoConfigImplementation() }

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

Access lateinit variable in Companion class [duplicate]

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

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

What are the advantages of a companion object over a plain object?

Kotlin code like this:
class Foo {
companion object {
fun a() : Int = 1
}
fun b() = a() + 1
}
can trivially be changed to
object FooStatic {
fun a() : Int = 1
}
class Foo {
fun b() = FooStatic.a()
}
I'm aware that the companion object can be used to allow use as real java static function, but are there any other advantages to using the companion object?
One of the key differences is visibility of the members.
In a companion object, visibility to the containing class is as-if the members were part of the class - this is not the case for a raw object.
The example below shows that you cant use an "object" to implement private static internals of a class.
package com.example
class Boo {
companion object Boo_Core {
// Public "static" call that non-Boo classes should not be able to call
fun add_pub(a:Int) = a+1;
// Internal "static" call that non-Boo classes should not be able to call
private fun add_priv(a:Int) = a+1;
}
// OK: Functions in Boo can call the public members of the companion object
fun blah_pub(a:Int) = add_pub(a)
// OK: Functions in Boo can call the private members of the companion object
fun blah_priv(a:Int) = add_priv(a)
}
//Same idea as the companion object, but as an "object" instead.
object Foo_Core {
fun add_pub(a:Int) = a+1
private fun add_priv(a:Int) = a+1;
}
class Foo {
// OK Foo can get Foo_Cors add_pub
fun blah_pub(a:Int) = Foo_Core.add_pub(a);
// ERROR: can not get to add_priv
// fun blah_priv(a:Int) = Foo_Core.add_priv(a);
}
class AnInterloper {
// OK Other classes can use public entries in Foo.
fun blah_foo_pub(a:Int) = Foo_Core.add_pub(a);
// ERROR Other classes can use public entries in Foo.
// fun blah_foo_priv(a:Int) = Foo_Core.add_priv(a);
// OK: Other classes can use public Boo classes
fun blah_boo_pub(a:Int) = Boo.add_pub(a);
// ERROR: Other classes can not use private Boo classes
// fun blah_boo_priv(a:Int) = Boo.add_priv(a);
}