Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can reflection extract initial values used in a trait?

I am playing with reflection to achieve a deep analysis on a trait. One of the things I would like to get is the initial value set to a member field. For example, in the trait:

trait A {
  val x: Int = 3
  val y: String = "y"
}

it would be nice to know 3 and "y". I have not found anything related to this task in the API, and due to the following output (generated by scalac -Xprint):

abstract trait A extends Object {
  <accessor> def com$hablapps$A$_setter_$x_=(x$1: Int): Unit;
  <accessor> def com$hablapps$A$_setter_$y_=(x$1: String): Unit;
  <stable> <accessor> def x(): Int;
  <stable> <accessor> def y(): String
};
abstract trait A$class extends  {
  def /*A$class*/$init$($this: com.hablapps.A): Unit = {
    $this.com$hablapps$A$_setter_$x_=(3);
    $this.com$hablapps$A$_setter_$y_=("y");
    ()
  }
}

I am afraid it is going to be quite hard to access them, since they are kept in the $init$ method's body. Is there any (easy) way to get those values with reflection?

like image 250
jeslg Avatar asked Oct 07 '22 04:10

jeslg


2 Answers

You have to disassemble the bytecode:

trait A { val x: Int = 3 }

public abstract class A$class extends java.lang.Object{
public static void $init$(A);
  Code:
   0:    aload_0
   1:    iconst_3
   2:    invokeinterface #12,  2; //InterfaceMethod A.A$_setter_$x_$eq:(I)V
   7:    return

See line 1--the only place the value exists is in the bytecode for the init method!

You cannot get to this any other way, since if you have

trait A { val x: Int = 3 }
trait B extends A { override val x = 7 }
class C extends B {}

you find that C extends A$_setter_$x_$eq to do nothing at all--making the A$class.$init$ call a no-op and rendering the value unretrievable.

Proof:

public class C extends java.lang.Object implements B,scala.ScalaObject{
public void A$_setter_$x_$eq(int);
  Code:
   0:    return

public void B$_setter_$x_$eq(int);
  Code:
   0:    aload_0
   1:    iload_1
   2:    putfield #11; //Field x:I
   5:    return
like image 200
Rex Kerr Avatar answered Oct 13 '22 11:10

Rex Kerr


I doubt you can introspect to this point. That's not information about the type, but code. If you have the tree for the trait, you can find it out, but, otherwise, I doubt it.

You can use, however, class file parsers to investigate this further. I assume these would appear as constants for the class, which can be read. I'm not sure you could associate them with the variable, but...

I'm not much familiar with class file parsers, but I think a tool called "asm" does that.

like image 22
Daniel C. Sobral Avatar answered Oct 13 '22 10:10

Daniel C. Sobral