How to call private functions of a class from outside the class in Kotlin
Asked Answered
G

4

8

I want to call a private functions of class SomeClass from outside of this class:

class SomeClass {
    private fun somePrivateFunction() {
        //...
    }

    private fun somePrivateFunctionWithParams(text: String) {
        //...
    }
}

Somewhere in the code I have a reference to SomeClass object:

val someClass = SomeClass()
// how can I call the private function `somePrivateFunction()` from here?
// how can I call the private function `somePrivateFunctionWithParams("some text")` from? here

How to call private functions with params and without params in Kotlin from outside a class?

Gaucherie answered 17/12, 2019 at 9:12 Comment(0)
G
8

I came across two useful extension functions, which are using reflection:

inline fun <reified T> T.callPrivateFunc(name: String, vararg args: Any?): Any? =
    T::class
        .declaredMemberFunctions
        .firstOrNull { it.name == name }
        ?.apply { isAccessible = true }
        ?.call(this, *args)

inline fun <reified T : Any, R> T.getPrivateProperty(name: String): R? =
    T::class
        .memberProperties
        .firstOrNull { it.name == name }
        ?.apply { isAccessible = true }
        ?.get(this) as? R

To use reflection in Kotlin add dependency:

implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

Those functions can be used as the following:

class SomeClass {

    private val world: World = World()

    private fun somePrivateFunction() {
        println("somePrivateFunction")
    }

    private fun somePrivateFunctionWithParams(text: String) {
        println("somePrivateFunctionWithParams()  text=$text")
    }
}

class World {
    fun foo(): String = "Test func"
}

// calling private functions:

val someClass = SomeClass()
someClass.callPrivateFunc("somePrivateFunction")
someClass.callPrivateFunc("somePrivateFunctionWithParams", "test arg")

// getting private member and calling public function on it:

val world = someClass.getPrivateProperty<SomeClass, World>("world")
println(world?.foo())
Gaucherie answered 4/5, 2022 at 11:7 Comment(5)
When using the parameter version, I'm getting: "IllegalArgumentException: Callable expects 4 arguments, but 2 were provided." Which is weird because the function actually needs 3 parameters. Could you explain using the parameter version in a little more detail?Brass
what function do you call which has parameter version?Gaucherie
I figured it out. Each parameter needs to be its own separate parameter after the name of the function. I thought the parameters were all part of the String (which was the second parameter).Brass
I'd like to add that setting the variable should be: inline fun <reified T : Any, R> T.setPrivateProperty(name: String, value: R) = T::class .memberProperties .firstOrNull { it.name == name } ?.apply { isAccessible = true } ?.let { (it as? KMutableProperty1<T, R>)?.setter?.call(this, value) }Tatterdemalion
@Gaucherie callPrivateFunc is not working in case of polymorphism. When creating 2 methods with same name with different number of arguments.Ibnsina
C
5

The idea of "private" is that only you can call it inside your class. If you want to "break in" to that class, you need to make use of reflection: https://mcmap.net/q/354672/-java-android-kotlin-reflection-on-private-field-and-call-public-methods-on-it

From the docs:

private means visible inside this class only (including all its members)

Here's an example:

class WithPrivate {
    private fun privFun() = "you got me"
}

fun main() {
    WithPrivate::class.declaredMemberFunctions.find { it.name == "privFun" }?.let {
        it.isAccessible = true
        println(it.call(WithPrivate()))
    }

}
Cabral answered 17/12, 2019 at 9:19 Comment(3)
I think OP wants to know how to do it using reflection, but the only hint to that in the question is the reflection tag...Courthouse
By the link you provided, I see how to access to private fields of an object, but there is no information on how to call private functions of an object.Gaucherie
Added an example for a function, it's very similar thoughCabral
S
0
val managerClass = Class.forName("com.api.Manager").kotlin
val managerInstance = managerClass.createInstance()
val startMethod = managerClass
    .declaredMemberFunctions
    .first { it.name == "start" }
    .also { it.isAccessible = true }
val param = 1234
startMethod.call(managerInstance, param)
Scirrhus answered 16/10, 2022 at 18:49 Comment(0)
A
0

You can call any private function by suppressing the compilation warning

@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")

@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
fun callPrivateFunction() {
  com.foo.bar.privateFunction()
}
Ascension answered 28/8 at 5:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.