反射を使用して実行時にSCALAオプション宣言のタイプにアクセスする方法はありますか?
-
27-09-2019 - |
質問
だから、私はこのように見えるScalaクラスを持っています:
class TestClass {
var value: Option[Int] = None
}
そして、私は文字列値を持っている問題に取り組んでおり、反射を使用して実行時にそのオプション[int]にそれを強制したいと思います。したがって、別のコード(TestClassについては何も知らない)では、次のようなコードがあります。
def setField[A <: Object](target: A, fieldName: String, value: String) {
val field = target.getClass.getDeclaredField(fieldName)
val coercedValue = ???; // How do I figure out that this needs to be Option[Int] ?
field.set(target, coercedValue)
}
これを行うには、フィールドがオプションであり、オプションのタイプパラメーターがintであることを知る必要があります。
「値」のタイプが実行時に[int]であることを理解するための私のオプションは何ですか(つまり、反射を使用する)?
@optionType(int.class)など、フィールドに注釈を付けることで、同様の問題が解決されました。可能であれば、反射ターゲットに注釈を必要としないソリューションを好みます。
解決
Java 1.5 Reflection APIを使用して、非常に奇妙なものです:
def isIntOption(clasz: Class[_], propertyName: String) = {
var result =
for {
method <- cls.getMethods
if method.getName==propertyName+"_$eq"
param <- method.getGenericParameterTypes.toList.asInstanceOf[List[ParameterizedType]]
} yield
param.getActualTypeArguments.toList == List(classOf[Integer])
&& param.getRawType == classOf[Option[_]]
if (result.length != 1)
throw new Exception();
else
result(0)
}
他のヒント
バイトコードレベルでは、Javaにはジェネリックがありません。ジェネリックは多型で実装されているため、ソースコード(この場合はScala)がコンパイルされると、ジェネリックタイプが消えます(これは呼ばれます タイプ消去 )。これにより、リフレクションを介して一般的なランタイムタイプ情報を収集することはできません。
可能な - 少し汚れたものですが、回避策は、一般的なパラメーターと同じタイプを持っていることがわかっているプロパティのランタイムタイプを取得することです。オプションインスタンスの場合、使用できます get
メンバー
object Test {
def main(args : Array[String]) : Unit = {
var option: Option[_]= None
println(getType(option).getName)
option = Some(1)
println(getType(option).getName)
}
def getType[_](option:Option[_]):Class[_]= {
if (option.isEmpty) classOf[Nothing] else (option.get.asInstanceOf[AnyRef]).getClass
}
}
class TestClass {
var value: Option[Int] = None
// ...
def doSomething {
value match {
case Some(i) => // i is an Int here
case None =>
// No other possibilities
}
}
}
問題は、JVMが型消去を通じてジェネリックを実装することです。したがって、反省を通して発見することは不可能です value
は Option[Int]
実行時には実際にはそうではないからです:それはただ Option
!
2.8では、使用できるはずです Manifests
このような:
var value: Option[Int] = None
val valueManifest = implicitly[scala.reflect.Manifest[Option[Int]]]
valueManifest.typeArguments // returns Some(List(Int))