web-dev-qa-db-ja.com

変換Scala Any to Java Object

Java Scalaからのリフレクションの使用に問題があります。私のコード:

_case class MyClass(id: String, value: Double)     

def create(values: Map[String, Any]): MyClass = {
   val constructor = classOf[MyClass].getConstructors.head
   val arguments = classOf[MyClass].getDeclaredFields().map( f => values(f.getName) )
   constructor.newInstance(arguments: _*).asInstanceOf[MyClass]
} 

create(Map("id" -> "CE0D23A", "value" -> 828.32))
_

私の問題は、Map [String、Any]を渡す必要があることです。値の1つがDoubleですが、newInstanceにはAnyではなくObjectが必要です。

私はスカラ宇宙で同じことを試しました:

_case class MyClass(id: String, value: Double)     

def create(values: Map[String, Any]): MyClass = {
   val m = universe.runtimeMirror(getClass.getClassLoader)
   val myClass = universe.typeOf[MyClass].typeSymbol.asClass
   val cm = m.reflectClass(myClass)
   val ctro = universe.typeOf[MyClass].declaration(universe.nme.CONSTRUCTOR).asMethod
   val ctorm = cm.reflectConstructor(ctro)
   ctorm(values: _*).asInstanceOf[MyClass]
} 

create(Map("id" -> "CE0D23A", "value" -> 828.32))
_

ここでの問題は、例としてMyClassのみを紹介したことです。後でそれはdef create(values: Map[String, Any]): Tのような汎用関数になるはずです。しかし、次の例外が発生しました:「Tで使用できるTypeTagはありません」

これらの値を変換する方法はありますか?

ありがとうございました

18
Torben

Java.lang.Objectは、AnyRefではなく、ScalaのAnyと同等です。 Scala Double(Java doubleとほぼ同等)はAnyですが、AnyRefではありません。Java.lang.DoubleAnyRefであるため、Anyでもあります。

AnyAnyRefにキャストするだけで、Scala DoubleJava.lang.Doubleに変換するために必要な変換が実行されます。

scala> val x = 3.5
x: Double = 3.5

scala> x.getClass
res0: Class[Double] = double

scala> val y = x.asInstanceOf[AnyRef]
y: AnyRef = 3.5

scala> y.getClass
res1: Class[_ <: AnyRef] = class Java.lang.Double
33
Dan Getz

わかりました。少し遅れましたが、次のとおりです。

次の作品:

constructor.newInstance(arguments.asInstanceOf[Array[AnyRef]]: _*).asInstanceOf[MyClass]

参照: Transforming Scala varargs into Java Object ... varargs

アドバイス:リフレクションの使用には非常に注意が必要です。 Scalaこれは悪いスタイルです。これを制限/カプセル化する1つの方法は次のとおりです。

case class MyClass(id: String, value: Double)     

object MyClass {

    import scala.util.Try
    def apply(map: Map[String, Any] /* this is asking for trouble */) : Option[MyClass]  =  for {
            id <- maybeT[String](map.get("id"))
            value <- maybeT[Double](map.get("value"))
        } yield MyClass(id, value)

    // a truly global utility?
    @inline def maybeT[T] ( a: Any /*Option[T]*/ ) : Option[T]= Try(a.asInstanceOf[Option[T]]).toOption.flatten //yep ugly as hell

}


MyClass(Map("id" -> "CE0D23A", "value" -> 828.32))
1
user3680494