Skip to content

Instantly share code, notes, and snippets.

@jorgeortiz85
Created April 7, 2011 15:41
Show Gist options
  • Star 36 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save jorgeortiz85/908035 to your computer and use it in GitHub Desktop.
Save jorgeortiz85/908035 to your computer and use it in GitHub Desktop.
Calling private methods in Scala
// Usage:
// p(instance)('privateMethod)(arg1, arg2, arg3)
class PrivateMethodCaller(x: AnyRef, methodName: String) {
def apply(_args: Any*): Any = {
val args = _args.map(_.asInstanceOf[AnyRef])
def _parents: Stream[Class[_]] = Stream(x.getClass) #::: _parents.map(_.getSuperclass)
val parents = _parents.takeWhile(_ != null).toList
val methods = parents.flatMap(_.getDeclaredMethods)
val method = methods.find(_.getName == methodName).getOrElse(throw new IllegalArgumentException("Method " + methodName + " not found"))
method.setAccessible(true)
method.invoke(x, args : _*)
}
}
class PrivateMethodExposer(x: AnyRef) {
def apply(method: scala.Symbol): PrivateMethodCaller = new PrivateMethodCaller(x, method.name)
}
def p(x: AnyRef): PrivateMethodExposer = new PrivateMethodExposer(x)
@Kylin1027
Copy link

Kylin1027 commented Aug 8, 2019

@leobenkel demo like this?

class PrivateMethodCallerDemo {
  private def saySomething(name: String, content: String): String = {
   s"${name} says ${content} to you"
  }
}

object DriverMain {
  def p(x: AnyRef): PrivateMethodExposer = new PrivateMethodExposer(x)
  def main(args: Array[String]): Unit = {
    val demoInstance = new PrivateMethodCallerDemo

    val name = "Aimer"
    val content = "Hello"
    val expectedRet = "Aimer says Hello to you"

    // Usage: p(instance)('privateMethod)(arg1, arg2, arg3)
    val retValue = p(demoInstance)('saySomething)(name, content)
    assert(retValue == expectedRet)
  }
}

@zbstof
Copy link

zbstof commented Dec 31, 2019

some method names are of the form: org$apache$spark$sql$execution$command$ShowCreateTableCommand$$escapeSingleQuotedString

p(instance)('escapeSingleQuotedString)("aaa")
java.lang.IllegalArgumentException: Method escapeSingleQuotedString not found

Workaround like so:

val method = methods.find(_.getName.split("\\$\\$") contains methodName).getOrElse(
  throw new IllegalArgumentException("Method " + methodName + s" not found, available: ${methods.map(_.getName).mkString(", ")}"))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment