Private method name mangling in scala

scala

name mangling

Name mangling is a technique adopted by compiler to ensure the uniqueness of names. In the context of jvm, name is compiled to a different name in byte code compared to the original one in source code.

I am aware of this technique when I unit test of a private method in scala. I tried to invoke the method by reflect, but it reports NoSuchMethodException.

Below is a simplified example for demonstration. Private method foo is defined and is called in the InnerClass. After compilation, foo will be mangled to another name as PrivateMethod$$foo.

import java.lang.reflect.Method

class PrivateMethod {
  private def foo(a: Int): Int = a

  class Inner {
    def f(): Unit = {
      foo(1)
    }
  }
}

object PrivateMethod {
  def main(args: Array[String]): Unit = {
		// NoSuchMethodException
    val foo: Method = classOf[PrivateMethod].getDeclaredMethod("foo", classOf[Int])
    foo.setAccessible(true)
    val obj = new PrivateMethod
    val ret = foo.invoke(obj, Integer.valueOf(1))
    println(ret)
  }
}

823a3f0f-e072-40f4-b218-f2d6a4bb262d

Let’s check the javap output. The private method turns into a public method with new name. That’s why the private method cannot be found by reflect.

9b328b75-4dbe-449d-9ce3-a165f4c3c57e

So how to test private method?

Use the PrivateMethodTester trait in scalatest. The method will be resolved not only by its original name but also the name prefixed with $$. See below:

e24bcf71-4f7c-4f62-bc1c-65143f252cf6

Note that if the private method is not called within an inner class, its name will not be mangled.