Reflection을 이용하여 private method를 클래스 밖에서 사용하기

Seokchan Yoon·2024년 9월 24일
class MyClass {
    private fun secretMethod(message: String): String {
        return "Secret message: $message"
    }
}

fun main() {
    val myClassInstance = MyClass()
    
    // Cannot access 'secretMethod': it is private in 'MyClass'kotlin(INVISIBLE_MEMBER)
    val result = myClassInstance.secretMethod("I am hungry.") 
}

Kotlin에서 private 메서드는 기본적으로 클래스 외부에서 접근할 수 없다. 하지만 reflection을 사용하면 런타임에 클래스의 메타데이터에 접근하여 이러한 제한을 우회할 수 있다.

Reflection은 클래스, 메서드, 필드 등의 정보를 런타임에 동적으로 가져오거나 조작할 수 있다.

Java Reflection API 사용

Kotlin 클래스에서 Java의 리플렉션 API를 사용하려면 먼저 KClass를 Java의 Class 객체로 변환해야 한다.

val clazz = MyClass::class.java

객체에서 getDeclaredMethod()를 이용해 호출하려는 private method를 찾는다. 이 method는 클래스의 public method, private method 모두를 반환한다.

val method = clazz.getDeclaredMethod("secretMethod", String::class.java)

isAccessible 설정을 사용하여 접근 제어를 변경할 수 있다.

method.isAccessible = true

invoke() 메서드를 사용하여 인스턴스를 넘겨주고, 필요한 매개변수를 전달한다.

val result = method.invoke(myClassInstance, "I am hungry.")

전체 예시

class MyClass {
    private fun secretMethod(message: String): String {
        return "Secret message: $message"
    }
}

fun main() {
    val myClassInstance = MyClass()
    val clazz = MyClass::class.java
    val method = clazz.getDeclaredMethod("secretMethod", String::class.java)
    method.isAccessible = true

    val result = method.invoke(myClassInstance, "I am hungry.")
    println(result)
}

Kotlin Reflection API 사용

Kotlin 자체 reflection API를 사용하여 메타데이터에 접근할 수도 있다. Java reflection을 사용하는 것과 원리는 같다.

import kotlin.reflect.full.declaredFunctions
import kotlin.reflect.jvm.isAccessible

class MyClass {
    private fun secretMethod(message: String): String {
        return "Secret message: $message"
    }
}

fun main() {
    val myClassInstance = MyClass()
    val secretMethod = MyClass::class.declaredFunctions.find { it.name == "secretMethod" }
    secretMethod?.isAccessible = true

    val result = secretMethod?.call(myClassInstance, "I am hungry.")
    println(result)
}

참고

method를 호출할 때 instance를 같이 넘겨줘야한다. 이는 secretMethod 가 static method가 아니라 instance method이기 때문이다. 따라서 객체의 상태에 따라서 method 결과가 달라질 수 있기 때문에 instance가 요구되는 것이다.

0개의 댓글