Scala:正确将参数传递给MethodMirror

时间:2019-04-20 18:04:00

标签: scala

我一直试图在Scala中使用反射创建一个简单的依赖项注入容器。我遇到的问题是如何正确地将参数传递给MethodMirror。我目前遇到异常:

  

java.lang.IllegalArgumentException:参数类型在不匹配   java.base / jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native   方法)

容器类:

import scala.reflect.runtime.{universe => ru}
import ru._
import extensions.MapExtension._

class RegisterConfig[TSource: TypeTag](container: Container){
  def as[TTrait >: TSource : TypeTag] = {
    container.typeTable += typeOf[TTrait] -> typeOf[TSource]
    container
  }
}

class InstanceConfig[TSource: TypeTag](container: Container, instance: TSource){
  def as[TTrait >: TSource : TypeTag] = {
    container.typeTable += typeOf[TTrait] -> typeOf[TSource]
    container.instances += typeOf[TTrait] -> instance
    container
  }
}

class ContainerConfig(container: Container) {
  def register[TSource: TypeTag] = new RegisterConfig(container)

  def instance[TSource: TypeTag](instance: TSource) = new InstanceConfig(container, instance)
}

class Container {
  var typeTable = Map[Type, Type]()
  var instances = Map[Type, Any]()

  def config() = new ContainerConfig(this)

  def resolve[TSource: TypeTag] = resolveDynamic(typeOf[TSource]).asInstanceOf[TSource]

  private def resolveDynamic(requestedType: Type) = {
    val resultType = typeTable.getOrElseWithCompare(requestedType, requestedType, (x, y) => x =:= y)

    val instance = instances.getOrElseWithCompare(resultType, createInstance(resultType), (x, y) => x =:= y)

    instances += resultType -> instance

    instance
  }

  private def createInstance(tpe: Type): Any = {
    val mirror: ru.Mirror = ru.runtimeMirror(getClass.getClassLoader)
    val clsSym: ru.ClassSymbol = tpe.typeSymbol.asClass
    val clsMirror: ru.ClassMirror = mirror.reflectClass(clsSym)
    val constructorSym: ru.MethodSymbol = tpe.decl(ru.termNames.CONSTRUCTOR).asMethod
    val constructorParameterTypes = constructorSym.paramLists.head.map(x => x.typeSignature)
    // Recursive step
    val params = constructorParameterTypes.map(x => resolveDynamic(x)).toArray
    // Passing `params` does not work! I get an exception here ...
    val constructorMirror: ru.MethodMirror = clsMirror.reflectConstructor(constructorSym)
    val instance = constructorMirror(params)
    instance
  }
}

单元测试:

import org.scalatest.FlatSpec

trait TestTrait
class TestClass extends TestTrait
class TestRecClass(x : TestTrait)

class ContainerTest extends FlatSpec {

  "Given Trait" should "return instance (with recursion)" in {
    val container = new Container()
      .config()
      .register[TestClass]
      .as[TestTrait]

    val instance = container.resolve[TestRecClass]

    assert(instance match {
      case _: TestRecClass => true
      case null => false
    })
  }
}

1 个答案:

答案 0 :(得分:1)

我应该使用“ splat" operator来正确地将参数数组传递给采用可变参数的方法

val instance = constructorMirror(params : _*)