2

I'm diving into reflection and I've met the following issue with this object class:

object Dict {

     fun getAll(): Map<String, List<String>> {
        return mapOf(
            "Mark" to listOf("Banana"),
            "John" to listOf("Strawbery", "Pie"),
            "Lily" to listOf("Apple", "Banana", "Pie"),
        )
    }
}

knowing the package canonical name of this class I can get this method:

val dictClass = Class.forName("com.example.util.Dict")
val getAllRelationsMethod = relationsClass.getMethod("getAll")
val peopleWithMeals = getAllRelationsMethod.invoke(null) // this line gives error

I got the following exception: java.lang.NullPointerException: null receiver

I'm passing the null into the invoke() method because it doesn't need a class instance to call (like static in java). Does the method call differs from Java here somehow? Didn't find a tip around the Internet so that's why I'm asking here. Thanks in advance! :)

2 Answers 2

4

If I remember correctly you have to change it like that ..

@JvmStatic
fun getAll(): Map<String, List<String>> {
    return mapOf(
        "Mark" to listOf("Banana"),
        "John" to listOf("Strawbery", "Pie"),
        "Lily" to listOf("Apple", "Banana", "Pie"),
    )
}

JVMStatic

Sign up to request clarification or add additional context in comments.

2 Comments

Wow, that works. I thought I need to use this annotation only if my code is supposed to work with some other java code... Thanks!
If I am correct, the part or reflection is java, so you want the method to be static in java that is why you need the annotation :)
1

As you can access (and have control over) both, the caller, as also the target, you probably shouldn't use reflection. @JvmStatic is a solution to this, but only if you can alter the target class.

If you can't and still need reflection, the following may help you:

val dictClass = Class.forName("com.example.util.Dict")
val getAllRelationsMethod = relationsClass.getMethod("getAll")
val objectInstance = dictClass.getField("INSTANCE").get(null) // get value of static field INSTANCE (which every object has)
val peopleWithMeals = getAllRelationsMethod.invoke(objectInstance)

It first extracts the object's instance with which you can call the object functions.

If you know that the object is always Dict and you imported it appropriately, you can also just use the following to call a function of/on it:

val dictClass = Class.forName("com.example.util.Dict")
val getAllRelationsMethod = relationsClass.getMethod("getAll")
val peopleWithMeals = getAllRelationsMethod.invoke(Dict) // Dict is an object and here the actual instance is used...

If it isn't very generic what you want to do, then omit reflection. Maybe having appropriate interfaces may help you accomplish something similar instead of using reflection?

8 Comments

It is very generic indeed. But thanks for all the tips :)
if it is very generic, then @JvmStatic is probably no solution to it... and if it is, it is probably not that generic ;-)
How can you know that without knowing the context of the project? :D
experience (if you can set @JvmStatic everywhere, then you can also introduce an appropriate other structure) ... but as I do not know for sure I used "probably" ;-)
I assure you that the reflection is exactly what I need in my strict example. I just want to point that the question wasn't about if I should use the reflection or not but how to get the object function from it ;-)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.