java scala reflection scala-java-interop

Convertir Scala Any a objeto Java



reflection scala-java-interop (2)

Tengo un problema al utilizar Java Reflection desde Scala. Mi código:

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

Mi problema es que necesito pasar un Mapa [String, Any], porque uno de los valores es Double, pero newInstance necesita Object, no Any.

Intenté lo mismo con el universo scalas:

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

El problema aquí es que solo presenté MyClass para el ejemplo. Más adelante debería ser una función genérica como def create(values: Map[String, Any]): T Pero luego obtuve la siguiente excepción: "No TypeTag disponible para T"

¿Hay alguna forma de transformar estos valores?

Gracias


Ok, llegué un poco tarde pero aquí va:

Los siguientes trabajos:

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

Ver también: Transformar Scala varargs en Java Object ... varargs

Consejo: Sería muy cauto con la reflexión. En Scala eso es mal estilo. Una forma de limitarlo / encapsularlo podría ser:

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


java.lang.Object es equivalente a AnyRef en Scala, no a Any . La idea es que Scala Double (aproximadamente equivalente a Java double ) es un Any , pero no un AnyRef . java.lang.Double es un AnyRef , por lo tanto también un Any .

Simplemente puedes lanzar un Any a AnyRef , que realizará la conversión necesaria para convertir un Double Scala en un 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