Scala:通过字段名称反射设置字段值

18

我正在学习Scala,但无法找到如何实现以下内容:

我正在编写一个在Scala对象和Google App Engine实体之间进行映射的mapper。如果我有一个像这样的类:

class Student {
    var id:Long
    var name:String
}

我需要创建该类的一个实例,在Java中,我可以通过名称获取Field,然后执行field.set(object, value),但是我找不到在Scala中如何执行此操作。

由于Student的字段被视为私有字段,并且因此field.set会抛出错误,因此我无法使用Java反射。

谢谢

1个回答

42

Scala将"var"转换为一个私有字段、一个getter和一个setter。因此,为了通过使用字符串来识别它来获取/设置var,您需要使用Java反射来查找getter/setter方法。以下是执行此操作的代码片段。请注意,此代码在Scala 2.8.0下运行,并且不存在重复方法名称和错误处理。

class Student {
  var id: Long = _
  var name: String = _
}

implicit def reflector(ref: AnyRef) = new {
  def getV(name: String): Any = ref.getClass.getMethods.find(_.getName == name).get.invoke(ref)
  def setV(name: String, value: Any): Unit = ref.getClass.getMethods.find(_.getName == name + "_$eq").get.invoke(ref, value.asInstanceOf[AnyRef])
}

val s = new Student
s.setV("name", "Walter")
println(s.getV("name"))  // prints "Walter"
s.setV("id", 1234)
println(s.getV("id"))    // prints "1234"

谢谢!那真的很有帮助,我用了你的一部分代码,在Scala 2.7.6中运行得很好。 - Damian
如果您事先知道方法参数类型,您也可以通过名称直接获取方法,使用getClass.getDeclaredMethod。 - Vincenzo Maggio
为什么它比设置field.setAccessible(true)更好? - Yael
你可以通过更改find方法的定义,使用javabeans来实现这个功能。例如,对于getV方法:find(_.getName == s"get${lowerCamelToUpperCamel(name)}",对于setter:find(_.getName == s"set${lowerCamelToUpperCamel(name)}"。当然,你还需要定义一个lowerCamelToUpperCamel函数,例如使用Guava:def lowerCamelToUpperCamel(str : String) { CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, str)} - RyanQuey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接