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

Я пытаюсь вызвать функцию, используя переменную как тип String, динамически, т.е. переменная будет содержать имя функции как String. Итак, мне нужно вызвать функцию с использованием этой переменной.

Итак, я использую Scala Reflection. Работает, если функция принимает тип данных как Sting, но выдает ошибку List[Map[String, Double]]

Я использовал ссылку ниже, чтобы ссылаться на код

Есть ли какая-либо функция Scala, которая позволяет вам вызывать метод, имя которого хранится в строке?

и ниже тестовая программа, которую я пытаюсь проверить

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

Моя версия Scala 2.11.6, и я использую IntelliJ. Я также проверил версию SDK. И снял флажок "Запустить рабочий лист в процессе компиляции" в Scala

Но все равно не повезло! Любая идея будет полезна. Спасибо!

2 ответа

Решение

Как описано здесь, классы времени выполнения в Java и типы времени выполнения в Scala

использование отражения Java на классах Scala может привести к неожиданным или неверным результатам

Кажется, для вашего случая, поскольку данные имеют тип scala.collection.immutable.List, вам нужно использовать отражение Scala, чтобы получить тип данных val во время выполнения. Вот пример

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]
}

Ниже я приведу работоспособное решение, которое использует отражение scala против гибридного java/scala @ValentinCarnu.

Я не гуру рефлексии, и поэтому я не знаю, является ли нижеследующее идиоматическим.

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)
  }
}
Другие вопросы по тегам