java - 实例化参数类型的空对象

标签 java scala reflection scala-reflect

我正在尝试制作一个 CSV 阅读器,将带有标题的 CSV 文件解析为“行对象”列表。这些“线对象”的类型由函数的调用者给出。

这个想法是能够像这样使用 CSV 阅读器:

case class PlayerData(btag: String, team: String, status: String, role: String)
//...
val p = CSV.from_filename("all-team.test.csv").extract[PlayerData]
for(PlayerData(b, t, _, r) <- p) {
  println(s"btag: $b, team: $t, role: $r")
}

我在 extract 函数中实例化对象时遇到一些问题。目前,该功能如下:

class CSV(data: List[List[String]]) {

  def make_instance[T: ClassTag]: Option[T] = classTag[T].runtimeClass.newInstance match {
    case v: T => Some(v)
    case _ => None
  }

  def get_term[T: TypeTag](term: String) = ru.typeOf[T].decl(ru.TermName(term)).asTerm

  def get_mirror[T: ClassTag] = ru.runtimeMirror(classTag[T].runtimeClass.getClassLoader)

  def extract[T:ClassTag:TypeTag](): List[T] = {
    val header = data.head
    val datas = data.tail
    data.map(row => {
               val res: T = make_instance[T].get
               for(i <- 0 to row.length) {
                 val data_symb = get_term[T](header(i))
                 val m = get_mirror[T]
                 val im = m.reflect(res)
                 val data_mirror = im.reflectField(data_symb)
                 data_mirror.set(datas(i))
               }
               res
             })
  }
}

代码可以编译,但在执行过程中出现以下异常:

[error] (run-main-0) java.lang.InstantiationException: CLI$PlayerData
[error] java.lang.InstantiationException: CLI$PlayerData
[error]         at java.base/java.lang.Class.newInstance(Class.java:547)
[error]         at CSV.make_instance(csv.scala:63)
[error] eam-statat CSV.$anonfun$extract$1(csv.scala:79)
[error]     at scala.collection.immutable.List.map(List.scala:286)
[error]     at CSV.extract(csv.scala:78)
[error]     at CLI$.main(test.scala:61)
[error]     at CLI.main(test.scala)
[error]     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error]     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error]     at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error]     at java.base/java.lang.reflect.Method.invoke(Method.java:564)
[error] Caused by: java.lang.NoSuchMethodException: CLI$PlayerData.<init>()
[error]     at java.base/java.lang.Class.getConstructor0(Class.java:3302)
[error]     at java.base/java.lang.Class.newInstance(Class.java:532)
[error]     at CSV.make_instance(csv.scala:63)
[error]     at CSV.$anonfun$extract$1(csv.scala:79)
[error]     at scala.collection.immutable.List.map(List.scala:286)
[error]     at CSV.extract(csv.scala:78)
[error]     at CLI$.main(test.scala:61)
[error]     at CLI.main(test.scala)
[error]     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error]     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error]     at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error]     at java.base/java.lang.reflect.Method.invoke(Method.java:564)

如何创建我尝试使用 CSV 行填充的对象?

最佳答案

错误出现在 make_instance 中。 classTag[T].runtimeClass.newInstance 尝试调用 T(即 PlayerData)的零参数构造函数。而 PlayerData 没有这样的构造函数。因此,要么将这样的构造函数添加到 PlayerData

case class PlayerData(btag: String, team: String, status: String, role: String) {
  def this() = {
    this("", "", "", "")
  }
}

或修复 make_instance 调用正确的构造函数

def make_instance[T: ClassTag]: Option[T] = classTag[T].runtimeClass.getConstructor(classOf[String],classOf[String],classOf[String],classOf[String]).newInstance("", "", "", "") match {
  case v: T => Some(v)
  case _ => None
}

(这当然是针对 PlayerData 的,而不是针对任意 T)

<小时/>

对于任意T,您应该修改make_instance

class CSV(data: List[List[String]]) {

//def make_instance[T: ClassTag]: Option[T] =
  def make_instance[T: ClassTag](args: Seq[String]): Option[T] =
//  classTag[T].runtimeClass.newInstance match {
    classTag[T].runtimeClass.getConstructor(Seq.fill(args.length)(classOf[String]): _*).newInstance(args: _*) match {
      case v: T => Some(v)
      case _ => None
    }

  def get_term[T: TypeTag](term: String) = ru.typeOf[T].decl(ru.TermName(term)).asTerm

  def get_mirror[T: ClassTag] = ru.runtimeMirror(classTag[T].runtimeClass.getClassLoader)

  def extract[T:ClassTag:TypeTag](): List[T] = {
    val header = data.head
    val datas = data.tail
    /*data*/datas.map(row => {
      val res: T = /*make_instance[T].get*/make_instance[T](row).get
      for(i <- 0 /*to*/until row.length) {
        val data_symb = get_term[T](header(i))
        val m = get_mirror[T]
        val im = m.reflect(res)
        val data_mirror = im.reflectField(data_symb)
        data_mirror.set(/*datas*/row(i))
      }
      res
    })
  }
}

case class PlayerData(btag: String, team: String, status: String, role: String)

val p = new CSV(List(
  List("btag", "team", "status", "role"), 
  List("a", "b", "c", "d"), 
  List("a1", "b1", "c1", "d1")
)).extract[PlayerData]

for(PlayerData(b, t, _, r) <- p) {
  println(s"btag: $b, team: $t, role: $r")
}
//btag: a, team: b, role: d
//btag: a1, team: b1, role: d1

关于java - 实例化参数类型的空对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58920221/

相关文章:

scala - 使用单片眼镜/scala 镜片时的权益成本

c# - 无法从动态生成的程序集访问 CodeBase

java - 使用反射与 java.math.BigInteger 交互时,我会遇到哪些问题?

java - 如何在异常处理程序中访问访问请求主体

java - JAXRS + JerseyTest 测试 REST 服务

scala - 如何在 IntelliJ 13 中调试 Scala SBT 项目?

java - jarInputStream.getManifest() 为空

java - 如何在 BDD 中创建良好的可重复日期测试?

java - 安装Spring STS后无法打开Eclipse

algorithm - 将多个 .OBJ 索引缓冲区映射/折叠到 OpenGL 的第一个索引缓冲区