我一直试图在scala中使用反射来创建一个简单的依赖注入容器。我面临的问题是如何正确地将参数传递给
MethodMirror
. 我现在有个例外:
java.lang.IllegalargumentException:参数类型不匹配
Java.Base/jdk.Neal.Eng.NATVEngRealToSoReRoopIMP.NeWistStase0(母语)
方法在
容器类别:
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
})
}
}