将Scala Any转换为Java对象

时间:2014-05-27 14:30:34

标签: java scala reflection scala-java-interop

我在使用Scala的Java Reflection时遇到了问题。我的代码:

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],因为其中一个值是Double,但newInstance需要Object,而不是Any。

我尝试使用scalas universe:

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这样的通用函数。但后来我得到了以下例外:"没有TypeTag可用于T"

有没有办法改变这些价值?

谢谢

2 个答案:

答案 0 :(得分:32)

java.lang.Object相当于Scala中的AnyRef,而不是Any。我的想法是,Scala Double(大致相当于Java double)是Any,而不是AnyRefjava.lang.DoubleAnyRef,因此也是Any

您可以简单地将Any投射到AnyRef,这将执行所需的转化,将Scala Double变为java.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

答案 1 :(得分:1)

好的,我有点迟了但是这里有:

以下作品:

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

另请参阅:Transforming Scala varargs into Java Object... varargs

建议:使用反射我会非常谨慎。在Scala中,这是一种糟糕的风格。限制/封装它的一种方法可能是:

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