Java reflection returning base type for Scala classes

29 Views Asked by At

In the following code, the type of the get method of the Scala class as seen by Java reflection is SSuperClass (both in Scala 2.13 and Scala 3). Yet when doing the same with Java classes, the type is SubClass. Why is this? Can I get the more precise type using Java reflection?

public class SuperClass {
    public SuperClass get() {return  this;}
}

public class SubClass extends SuperClass{
    @Override
    public SubClass get() {return  this;}
}
class SSuperClass {
  def get = this
}

class SSubClass extends SSuperClass {
  override def get: SSubClass = this
}

object Main {
  def main(args: Array[String]): Unit = {
    val getMethod = classOf[SubClass].getDeclaredMethods.find(_.getName == "get").get
    val returnType = getMethod.getReturnType
    println(returnType)

    val getMethodS = classOf[SSubClass].getDeclaredMethods.find(_.getName == "get").get
    val returnTypeS = getMethodS.getReturnType
    println(returnTypeS)
  }
}

I know this could be solved using Scala reflection, but that opens a new can of worms (e.g. needing separate solutions for Scala 2 and Scala 3).

2

There are 2 best solutions below

0
Dmytro Mitin On BEST ANSWER

If you print classOf[SSubClass].getDeclaredMethods you'll see that there are two methods

public App$SSuperClass App$SSubClass.get()
public App$SSubClass App$SSubClass.get()

Just .find finds the first one.

You can add filter(!_.isBridge) in

classOf[SSubClass].getDeclaredMethods.filter(!_.isBridge).find(_.getName == "get").get

How bridge method works?

What Method.isBridge used for?

0
Suma On

You can get the primary version of the method by using getMethod. If you do not know the parameter types, you can get them from the version you have found:

    val preciseMethod = classOf[SSubClass].getMethod(getMethodS.getName, getMethodS.getParameterTypes.toSeq:_*)
    val returnTypeP = preciseMethod.getReturnType
    println(returnTypeP)