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))

这意味着可以做一些事情:

  1. Foo.bar不应该评价
  2. 相反,Foo.bar 应该分解为一个目标对象 Foo 和一个字段 "bar"
  3. Foo.bar 的类型应与 newValue
  4. 的类型相同

奖励问题:如果这是可能的,如何使其适用于 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)"
  }
}