用反射创建对象 - 来自字符串

时间:2013-06-26 07:20:16

标签: scala type-conversion

我有以下Scala代码,虽然调试它,并检查方法 createObject 是什么,证明一切正常,但我得到一个例外:

java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)

constructor.newInstance(convertedArguments).asInstanceOf [T]

object ObjectFactory {
  def runTest() = {
    val container = createContainer("n1 | 1 | true")
    container.created
  }

  def createContainer(s: String): Container = {
    createObject(classOf[Container], s)
  }

  def createObject[T](cls: Class[T], line: String): T = {
    // we assume the classes first non-zero
    // argument constructor is the one we need :)
    val constructor = cls.getConstructors.filter(_.getParameterTypes.length > 0)(0)
    var ptypes = constructor.getParameterTypes

    val tokens: Array[String] = line.split("\\|", -1)
    val convertedArguments = tokens.zip(ptypes).collect {
      case Tuple2(value: String, propType: Class[_]) => convert(value.trim, propType)
    }.collect {
      case Some(o) => o
      case None    => null
    }

    constructor.newInstance(convertedArguments).asInstanceOf[T]
  }

  private def convert[T](input: String, outputClass: Class[T]): Option[T] = {
    if (outputClass == classOf[Date]) {
      Some(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.S").parse(input).asInstanceOf[T])
    } else if (outputClass == classOf[BigDecimal]) {
      Some(BigDecimal.apply(input).asInstanceOf[T])
    }
    else {
        if (input == null || ("" == input) || ("null" == input))
          None
        else
          Some(outputClass.getConstructor(classOf[String]).newInstance(input))
    }
  }
}

class Container(val name: String, val score: Integer, val created: String)

这里发生了什么?如何将代码更正为scala-like - 尤其是类型转换部分。

1 个答案:

答案 0 :(得分:2)

方法newInstance需要varargs(AnyRef*),而不是Array[Any]。您正尝试使用1个参数调用构造函数 - Array

您应该将Array[Any]转换为Array[AnyRef],而不是使用特殊语法: _*调用方法:

constructor.newInstance(convertedArguments.map{_.asInstanceOf[AnyRef]}: _*)