How to access a field's value via reflection (Scala 2.8)
Asked Answered
S

5

13

Consider the following code:

class Foo(var name: String = "bar")

Now i try to get the value and the correct type of it via reflection:

val foo = new Foo
val field = foo.getClass.getDeclaredField("name")
field.setAccessible(true)
//This is where it doesn't work
val value = field.get(????)

I tried things like field.get(foo), but that just returns an java.lang.Object but no String. Basically I need the correct type, because I want to invoke a method on it (e. g. toCharArray).

What is the suggested way to do that?

Sanborne answered 17/4, 2010 at 10:39 Comment(0)
S
7

As others have mentioned, the reflection methods return Object so you have to cast. You may be better using the method that the Scala compiler creates for field access rather than having to change the visibility of the private field. (I'm not even sure if the name private field is guaranteed to be the same as that of the accessor methods.)

val foo = new Foo
val method = foo.getClass.getDeclaredMethod("name")
val value = method.get(foo).asInstanceOf[String]
Shotten answered 17/4, 2010 at 14:40 Comment(1)
working well with foo.getClass.getDeclaredField("name") because foo.getClass.getDeclaredMethod does not have a member called getSesquiplane
P
5

getDeclaredField is a method of java.lang.Class.

You have to change foo.getDeclaredField("name") to foo.getClass.getDeclaredField("name") (or classOf[Foo].getDeclaredField("name")) to get the field.

You can get the type with getType method in class Field but it won't help you because it returns Class[_]. Given than you know that the type is a String you can always cast the value returned using field.get(foo).asInstanceOf[String]

Pandit answered 17/4, 2010 at 12:59 Comment(2)
I fixed the missing getClass, this was only an oversight. I wonder how to do the cast without knowing what it is beforehand. If I knew everything about the class I have to handle i wouldn't need reflection... Thanks for the suggestions!Sanborne
You can pattern match the object with something like value match { case s: String => /* do something with a string */ case _ => /* do something else */ }. Don't know if I understand what you want to do.Pandit
O
1

AFAIK, reflection always work with Object, and you have to cast the results yourself.

Opium answered 17/4, 2010 at 13:9 Comment(1)
Yes, I had misunderstood the question, now I have changed mi answer.Pandit
D
1

This is how one can get list of fieldnames and its value of a case class:
First, using reflection, get fields info as follows -

val TUPLE2_OF_FIELDNAME_TO_GETTERS = typeOf[<CLASS>].members
.filter(!_.isMethod)
.map(x => (x.name.toString, classOf[<CLASS>].getDeclaredMethod(x.name.toString.trim)))

How to use it?

getFieldNameAndValue(obj: <CLASS>): Seq[(String, String)] {
  var output = Seq[(String, String)]()
 for(fieldToGetter <- TUPLE2_OF_FIELDNAME_TO_GETTERS) {
      val fieldNameAsString = fieldToGetter._1
      val getter = fieldToGetter._2
      val fieldValue = getter.invoke(obj).toString
      output += (fieldName, fieldValue)
    }
}
Directional answered 22/9, 2017 at 6:56 Comment(0)
B
0
foo.getClass.getDeclaredField("name").getString(foo)

should work if you want to avoid asInstanceOf. get* is available for various types

Briarwood answered 25/8, 2020 at 12:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.