Java 反射在 Scala 中的类型安全用法
Type-safe usage of Java reflection in Scala
我正在尝试使用 Java 反射在运行时以类型安全的方式替换对象字段的值。
假设我们有以下对象。
import cats.Eval
object Foo {
val bar: Eval[Int] = Eval.later(throw new Exception)
}
我们想在运行时更改 Foo.bar
的值。我们可以使用普通 Java 反射轻松定义以下方法:
import java.lang.reflect.Field
def usingJavaReflection[T](targetObject: AnyRef, fieldName: String)(newValue: T): Unit = {
val field = targetObject.getClass.getDeclaredField(fieldName)
field.setAccessible(true)
field.set(targetObject, newValue)
}
// usage
usingJavaReflection(Foo, "bar")(Eval.now(42))
现在问题变成了:如何以更安全的方式做到这一点?
def usingJavaReflectionButTypesafe[T](field: T)(newValue: T): Unit = ???
// intended usage
usingJavaReflectionButTypesafe(Foo.bar)(Eval.now(42))
这意味着可以做一些事情:
Foo.bar
不应该评价
- 相反,
Foo.bar
应该分解为一个目标对象 Foo
和一个字段 "bar"
Foo.bar
的类型应与 newValue
的类型相同
奖励问题:如果这是可能的,如何使其适用于 Scala 2.11、2.12 和 2.13。我只是想不通哪些 Scala 宏技术可以安全地用于哪些版本的 Scala,以及如何使用。
尝试
def usingJavaReflectionButTypesafe[T](field: => T)(newValue: T): Unit = macro impl[T]
def impl[T: c.WeakTypeTag](c: blackbox.Context)(field: c.Tree)(newValue: c.Tree): c.Tree = {
import c.universe._
field match {
case q"$expr.$tname" =>
q"usingJavaReflection($expr, ${tname.toString})($newValue)"
}
}
我正在尝试使用 Java 反射在运行时以类型安全的方式替换对象字段的值。
假设我们有以下对象。
import cats.Eval
object Foo {
val bar: Eval[Int] = Eval.later(throw new Exception)
}
我们想在运行时更改 Foo.bar
的值。我们可以使用普通 Java 反射轻松定义以下方法:
import java.lang.reflect.Field
def usingJavaReflection[T](targetObject: AnyRef, fieldName: String)(newValue: T): Unit = {
val field = targetObject.getClass.getDeclaredField(fieldName)
field.setAccessible(true)
field.set(targetObject, newValue)
}
// usage
usingJavaReflection(Foo, "bar")(Eval.now(42))
现在问题变成了:如何以更安全的方式做到这一点?
def usingJavaReflectionButTypesafe[T](field: T)(newValue: T): Unit = ???
// intended usage
usingJavaReflectionButTypesafe(Foo.bar)(Eval.now(42))
这意味着可以做一些事情:
Foo.bar
不应该评价- 相反,
Foo.bar
应该分解为一个目标对象Foo
和一个字段"bar"
Foo.bar
的类型应与newValue
的类型相同
奖励问题:如果这是可能的,如何使其适用于 Scala 2.11、2.12 和 2.13。我只是想不通哪些 Scala 宏技术可以安全地用于哪些版本的 Scala,以及如何使用。
尝试
def usingJavaReflectionButTypesafe[T](field: => T)(newValue: T): Unit = macro impl[T]
def impl[T: c.WeakTypeTag](c: blackbox.Context)(field: c.Tree)(newValue: c.Tree): c.Tree = {
import c.universe._
field match {
case q"$expr.$tname" =>
q"usingJavaReflection($expr, ${tname.toString})($newValue)"
}
}