How to access instance variable in static companion object in Kotlin - 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))
}
}
}
}

Related

Why do I need to qualify references to an object inside my companion object with "Companion." from outside the class

I have a companion object with a named object inside of it, but unless I use Companion. kotlin can't resolve the reference
class Cls {
companion object {
object Obj {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // ok
println(Cls.Obj) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj) // ok
}
If I switch to val Obj = object { ... } then neither access works if I try to reference attr, but both allow me to reference Obj
class Cls {
companion object {
val Obj = object {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Obj) // ok
println(Cls.Companion.Obj) // ok
}
I don't understand this behavior. What's going on? My only guesses would be around static initialization ordering problems.
First, Answering the second question.
class Cls {
companion object {
val Obj = object {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Obj) // ok
println(Cls.Companion.Obj) // ok
}
Here the object{} is called as anonymous object which is assigned to the variable as val object It does not have any references.
When you check here, Cls.Obj is of type Any.
So you cannot access like Any.attr because Any is root of all Kotlin class, it will only have default fucntions like hashcode(), equals()...
Since it is an anonymous object, you cannot do type cast.So no way to access attr directly.
To access attr , you can acheive with interface.
interface Foo{
fun attrs():Int
}
class Cls {
companion object {
val Obj = object : Foo{
var attr = 1
override fun attrs(): Int = attr
}
}
}
fun main() {
println(Cls.Obj.attrs()) // Print attr value 1
}
Here is the compiled code looks like of this.
public final class Cls public constructor() {
public companion object {
public final val Obj: kotlin.Any /* compiled code */
}
}
When you see here, Obj is a variable inside which is of type Any.
In Kotlin, you can access variables inside companion object in both ways with or without Companion. Both will work.
println(Cls.Obj) // ok
println(Cls.Companion.Obj) // ok
In java , we need to access like,
Cls.Companion.getObj().
In Kotlin ,Companion word can be ignored. So accessing variables in companion object is the better one without using companion,like below.
println(Cls.Obj) // ok
Coming to First Question
class Cls {
companion object {
object Obj {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // ok
println(Cls.Obj) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj) // ok
}
Here you use object inside companion object, which is a nested object. This is similar to Nested static class in java, but not the same.
public final class Cls public constructor() {
public companion object {
public object Obj {
public final val attr: kotlin.Int /* compiled code */
}
}
}
The above one is the compiled code of the first one. When you check here, you have object inside companion object. But in your second question, you have made that Obj as variable. So you can directly call that variable. But here since it is a nested object, you should use companion keyword to access Obj.
Cls.Companion.Obj is the valid one.
When you access Obj like this Cls.Obj, the compiler checks for variable named 'Obj' inside that companion object. But there is no such variable because its an nested object.
And to make it clear,here is another example.
class Cls {
companion object {
object Obj {
val attr = 1
}
object Obj1{
val attr = 2
}
}
}
Hope it helps you.

Pass a static method as a parameter to another method in Kotlin

As per this question, a function can be passed as a parameter to another function as shown below
fun foo(m: String, bar: (m: String) -> Unit) {
bar(m)
}
fun buz(m: String) {
println("another message: $m")
}
fun something() {
foo("hi", ::buz)
}
Similarly, we can also pass a method from a class
class OtherClass {
fun buz(m: String) {
println("another message: $m")
}
}
foo("hi", OtherClass()::buz)
But what if the method we want to pass is static (within a companion object)?
class OtherClass {
companion object {
fun buz(m: String) {
println("another message: $m")
}
}
}
I am aware that since it is static we can simply call the method directly without having to resort to passing it as a parameter, however, there are still some situations (such as when taking advantage of pre-existing code) where this would be useful.
To access companion object of class use ${className}.Companion. So...
foo("hit", OtherClass.Companion::buz).

Using #AutoAnnotation in Kotlin, complaint method must be static

In reference to https://google.github.io/dagger/multibindings.html, there's this code
#AutoAnnotation
static MyKey createMyKey(String name, Class<?> implementingClass, int[] thresholds) {
return new AutoAnnotation_MyComponentTest_createMyKey(name, implementingClass, thresholds);
}
When converted to Kotlin, I use below
companion object {
#AutoAnnotation
#JvmStatic
fun createMyKey(name: String, implementingClass: Class<*>, thresholds: IntArray): MyKey {
return AutoAnnotation_MainActivity_createMyKey(name, implementingClass, thresholds)
}
}
It still complaints
error: #AutoAnnotation method must be static
public final com.elyeproj.daggermultibinding.MyKey createMyKey(#org.jetbrains.annotations.NotNull()
^
I tried both with and without #JvmStatic still not working. How to resolve this?
The following works for me. Have the create key method as global function.
class HelloAutoAnnotations {
fun execute() {
println("HelloAutoAnnotations...")
DaggerMyComponent.create().myMap().forEach(::println)
}
}
#MapKey(unwrapValue = false)
private annotation class MyKey(val username: String, val password: String)
#Module
private class MyModule {
#Provides
#IntoMap
#MyKey(username = "user1", password = "T0gether")
fun providesUser(): String = "Rooney"
#Provides
#IntoMap
#MyKey(username = "user2", password = "T0gether")
fun provideUser(): String = "Doo"
}
#Component(modules = arrayOf(MyModule::class))
private interface MyComponent {
fun myMap(): Map<MyKey, String>
}
#AutoAnnotation
private fun createMyKey(username: String, password: String): MyKey {
return MyKeyCreator.createMyKey(username, password)
}
According to the docs:
Maps whose keys are not known at compile time
Map multibindings work only if your map’s keys are known at compile
time and can be expressed in an annotation. If your map’s keys don’t
fit in those constraints, then you cannot create a multibound map, but
you can work around that by using set multibindings to bind a set of
objects that you can then transform into a non-multibound map.
#Module
class MyModule {
#Provides #IntoSet
static Map.Entry<Foo, Bar> entryOne(...) {
Foo key = ...;
Bar value = ...;
return new SimpleImmutableEntry(key, value);
}
#Provides #IntoSet
static Map.Entry<Foo, Bar> entryTwo(...) {
Foo key = ...;
Bar value = ...;
return new SimpleImmutableEntry(key, value);
}
}
#Module
class MyMapModule {
#Provides
static Map<Foo, Bar> fooBarMap(Set<Map.Entry<Foo, Bar>> entries) {
Map<Foo, Bar> fooBarMap = new LinkedHashMap<>(entries.size());
for (Map.Entry<Foo, Bar> entry : entries) {
fooBarMap.put(entry.getKey(), entry.getValue());
}
return fooBarMap;
}
}
So you should try this approach perhaps.

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