Tarun Khaneja
Tarun Khaneja

Reputation: 451

java.lang.NoSuchMethodException: scala.collection.immutable.$colon$colon

I am trying to call a function using a variable as String type dynamically i.e. variable will contain a function name as String. So, I need to call a function using that variable.

So, I am using Scala Reflection. It is working if the function is accepting datatype as Sting, But it is throwing error List[Map[String, Double]]

I used below link to refer a code

Is there any Scala feature that allows you to call a method whose name is stored in a string?

and below is a test program which I am trying to test

package test

import scala.collection.immutable.Map

class DynamicaVariable {
 def cat(s1: List[Map[String, Double]]) = {
  println(s1)
 }
}

object DynamicaVariable{
 def main(args: Array[String]): Unit = {

 val obj = new DynamicaVariable
 val data = List(
  Map("a" -> 1.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0), Map("a" -> 1.0, "b" -> 2678.0, "c" -> 40.0, "d" -> 2.0), Map("a" -> 4.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0), Map("a" -> 1.0, "b" -> 2678.0, "c" -> 90.0, "d" -> 17.0)
)
 val functionName = "cat"
 val method = obj.getClass.getMethod(functionName,data.getClass)
 method.invoke(obj,data)
}
}

My scala version is 2.11.6 and I am using IntelliJ. I have checked the SDK version also. And unchecked the "Run worksheet in the compile process" under scala

But still no luck! Any idea will be helpful. Thanks!

Upvotes: 2

Views: 2168

Answers (2)

user10386912
user10386912

Reputation:

As described here Runtime Classes in Java vs. Runtime Types in Scala

using Java reflection on Scala classes might return surprising or incorrect results

It seems for your case, as data is of type scala.collection.immutable.List, you need to use Scala reflection to get the type of the data val at runtime. Here is an example

import scala.reflect.ClassTag
import scala.reflect.classTag

class DynamicaVariable {
    def cat(s1: List[Map[String, Double]]) = {
        println(s1)
    }
}

object DynamicaVariable{
    def main(args: Array[String]): Unit = {
        val obj = new DynamicaVariable
        val data = List(Map("a" -> 1.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0)
                        , Map("a" -> 1.0, "b" -> 2678.0, "c" -> 40.0, "d" -> 2.0)
                        , Map("a" -> 4.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0)
                        , Map("a" -> 1.0, "b" -> 2678.0, "c" -> 90.0, "d" -> 17.0))
        val functionName = "cat"
        val method = obj.getClass.getMethod(functionName, getClassOf(data).runtimeClass)

        method.invoke(obj,data)
    }

    def getClassOf[T: ClassTag](obj: T) = classTag[T]
}

Upvotes: 2

Yaneeve
Yaneeve

Reputation: 4779

I give a workable solution below that employs scala reflection vs the java/scala hybrid of @ValentinCarnu.

I am not a reflection guru, and so I do not know if the below is idiomatic.

import scala.collection.immutable.Map
import scala.reflect.runtime.{universe => ru}

class DynamicaVariable {
  def cat(s1: List[Map[String, Double]]) = {
    println(s1)
  }
}

object DynamicaVariable {
  def main(args: Array[String]): Unit = {

    val obj = new DynamicaVariable
    val data = List(
      Map("a" -> 1.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0),
      Map("a" -> 1.0, "b" -> 2678.0, "c" -> 40.0, "d" -> 2.0),
      Map("a" -> 4.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0),
      Map("a" -> 1.0, "b" -> 2678.0, "c" -> 90.0, "d" -> 17.0)
    )
    val functionName = "cat"
    val mirror = ru.runtimeMirror(getClass.getClassLoader)
    val instanceMirror: ru.InstanceMirror = mirror.reflect(obj)
    val classSymbol = mirror.classSymbol(obj.getClass)
    val termName: ru.MethodSymbol = classSymbol.info.decl(ru.TermName(functionName)).asMethod


    val methodMirror: ru.MethodMirror = instanceMirror.reflectMethod(termName)
    methodMirror.apply(data)
  }
}

Upvotes: 1

Related Questions