Convert Scala Any to Java Object

20,160

Solution 1

java.lang.Object is equivalent to AnyRef in Scala, not Any. The idea is, Scala Double (roughly equivalent to Java double) is an Any, but not an AnyRef. java.lang.Double is an AnyRef, thus also an Any.

You can simply cast an Any to AnyRef, which will perform the needed conversion to turn a Scala Double into a 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

Solution 2

Ok, I was a bit late but here goes:

The following works:

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

See also: Transforming Scala varargs into Java Object... varargs

Advice: I'd be very cautious using reflection. In Scala that is bad style. One way to limit/encapsulate it could be:

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))
Share:
20,160

Related videos on Youtube

Torben
Author by

Torben

Updated on July 09, 2022

Comments

  • Torben
    Torben almost 2 years

    I've a problem using Java Reflection from Scala. My Code:

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

    My problem is, that I need to pass a Map[String, Any], because one of the values is a Double, but newInstance needs Object, not Any.

    I tried the same with 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))
    

    Problem here is, that I only introduced MyClass for the example. Later it should be a generic function like def create(values: Map[String, Any]): T. But then I got the following exception: "No TypeTag available for T"

    Is there any way to transform these values?

    Thank you

  • Torben
    Torben almost 10 years
    I added a second exampled based on scalas universe. Maybe you know a solution for this problem too? Or is there no way to use scalas universe runtime reflection with generics?
  • Dan Getz
    Dan Getz almost 10 years
    I don't know how to do that, sorry. Maybe you should post it as a new, separate question.