mercredi 14 août 2019

Type-safe usage of Java reflection in Scala

I am trying to use Java reflection to replace the value for an object's field at runtime, but in a type-safe way.

Let's assume we have the following object.

import cats.Eval

object Foo {
  val bar: Eval[Int] = Eval.later(throw new Exception)
}

We want to change the value for Foo.bar at runtime. We can easily define the following method using normal Java reflection:

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

// intended usage
usingJavaReflection(Foo, "bar")(Eval.now(42))

Now the question becomes: how to do that in a more type-safe way?

def usingJavaReflectionButTypesafe[T](field: T)(newValue: T): Unit = ???

// usage
usingJavaReflectionButTypesafe(Foo.bar)(Eval.now(42))

This means being able to do a few things:

  1. Foo.bar should not be evaluated
  2. Instead, Foo.bar should be broken down into a target object Foo and a field "bar"
  3. The type for Foo.bar should be the same as for newValue

Bonus question: If this is possible, how to make it work for Scala 2.11 and 2.12 and 2.13. I just cannot wrap my head around which Scala macros techniques are safe to use in which versions of Scala, and how.





Aucun commentaire:

Enregistrer un commentaire