how to get value class fields with scala reflection

2,276 views
Skip to first unread message

Jeff Olson

unread,
Apr 3, 2013, 3:14:09 PM4/3/13
to scala...@googlegroups.com
I have some class with a value class field. I would like to use scala reflection to get at that field, but so far I can seem to do no better than I can do with java reflection. Here's an example:

mport scala.reflect.runtime._

case class Foo(x: Int) extends AnyVal
case class Bar(foo: Foo)

object Test {
  def main(args: Array[String]) {
    val bar = Bar(Foo(3))
    println(bar.foo) // Foo(3)

    val mirror = currentMirror
    val im = mirror.reflect(bar)
    val fooTerm = universe.typeOf[Bar].declaration(universe.newTermName("foo")).asMethod

    val obj1 = im.reflectField(fooTerm).get // returns java.lang.Integer(3) not Foo(3)
    println(obj1) // 3

    val obj2 = im.reflectMethod(fooTerm)() // returns java.lang.Integer(3) not Foo(3)
    println(obj2) // 3
  }
}

So how do I get Foo(3) from my InstanceMirror `im` and my MethodSymbol `fooTerm`? Obviously I would like a solution with works with arbitrary value class fields, not just this silly example.

-Jeff

Flavio W. Brasil

unread,
Apr 3, 2013, 3:43:45 PM4/3/13
to Jeff Olson, Eugene Burmako, scala...@googlegroups.com
Jeff,

It looks like that when using runtime reflection, foo becomes the int value (3) because it extends AnyVal.

Eugene,

This behavior is expected or are we using the reflection API in a wrong way? I get the same result using SMirror:

scala>  implicit val mirror = scala.reflect.runtime.currentMirror
mirror: reflect.runtime.universe.Mirror = JavaMirror with scala.t...

scala> import net.fwbrasil.smirror._
import net.fwbrasil.smirror._

scala> case class Foo(x: Int) extends AnyVal
defined class Foo

scala> case class Bar(foo: Foo)
defined class Bar

scala> val bar = Bar(Foo(3))
bar: Bar = Bar(Foo(3))

scala> println(bar.foo)
Foo(3)

scala> bar.reflect.vals
res3: List[net.fwbrasil.smirror.SInstanceVal[Bar]] = List(val foo: Foo (bound to Bar(Foo(3))))

scala> bar.reflect.vals.head.get
res4: Any = 3

-- 
Flávio W. Brasil
{persistence as it should be}

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Jeff Olson

unread,
Apr 3, 2013, 3:52:26 PM4/3/13
to scala...@googlegroups.com, Jeff Olson, Eugene Burmako
Yes, but it knows that the field is of type Foo, so, in theory, it should be capable of doing the right thing:

scala> println(fooTerm.returnType)
res10: Foo

-Jeff

Eugene Burmako

unread,
Apr 3, 2013, 4:52:46 PM4/3/13
to Jeff Olson, scala-user
Could you please submit an issue for this one? If that's a blocker for you, I could fix it soonish.

Jeff Olson

unread,
Apr 4, 2013, 1:00:15 AM4/4/13
to scala...@googlegroups.com, Jeff Olson
Here you go: https://issues.scala-lang.org/browse/SI-7328

It is a blocker, but I can't wait for a fix, so I'll have to cook up a workaround.

-Jeff

Jeff Olson

unread,
Apr 4, 2013, 12:33:51 PM4/4/13
to scala...@googlegroups.com, Jeff Olson
so here's my cooked up workaround if anyone else runs into this before Eugene can fix it:

  def getFieldValue(im: InstanceMirror, term: MethodSymbol): Any = {
    val rawValue = im.reflectMethod(term)()
    val tpe = term.returnType
    val symbol = tpe.typeSymbol.asClass
    if (symbol.isDerivedValueClass) {
      val ctor = tpe.declaration(nme.CONSTRUCTOR).asMethod
      val ctorMirror = mirror.reflectClass(symbol).reflectConstructor(ctor)
      ctorMirror(rawValue)
    }
    else rawValue
  }

-Jeff
Reply all
Reply to author
Forward
0 new messages