Scala/Java 反射数组类型

问题描述 投票:0回答:1

我正在尝试使用反射实例化案例类。 我正在使用这个参考代码:https://gist.github.com/ConnorDoyle/7002426


import scala.reflect.runtime.universe._

object ReflectionHelpers extends ReflectionHelpers

trait ReflectionHelpers {

  protected val classLoaderMirror = runtimeMirror(getClass.getClassLoader)

  /**
    * Encapsulates functionality to reflectively invoke the constructor
    * for a given case class type `T`.
    *
    * @tparam T the type of the case class this factory builds
    */
  class CaseClassFactory[T: TypeTag] {

    val tpe = typeOf[T]
    val classSymbol = tpe.typeSymbol.asClass

    if (!(tpe <:< typeOf[Product] && classSymbol.isCaseClass))
      throw new IllegalArgumentException(
        "CaseClassFactory only applies to case classes!"
      )

    val classMirror = classLoaderMirror reflectClass classSymbol

    val constructorSymbol = tpe.declaration(nme.CONSTRUCTOR)

    val defaultConstructor =
      if (constructorSymbol.isMethod) constructorSymbol.asMethod
      else {
        val ctors = constructorSymbol.asTerm.alternatives
        ctors.map { _.asMethod }.find { _.isPrimaryConstructor }.get
      }

    val constructorMethod = classMirror reflectConstructor defaultConstructor

    /**
      * Attempts to create a new instance of the specified type by calling the
      * constructor method with the supplied arguments.
      *
      * @param args the arguments to supply to the constructor method
      */
    def buildWith(args: Seq[_]): T = constructorMethod(args: _*).asInstanceOf[T]

  }
}

对于案例类中的大多数类型的字段来说,一切都非常有效。 我唯一的问题是尝试填充数组字段时。

基本上可以归结为这个问题:

case class MyClass(arr: Array[String])

object Main {
  def main(args: Array[String]): Unit = {
    val f = new CaseClassFactory[MyClass]
    f.buildWith(Seq(Array[String]("1","2","3"))) //This works
    f.buildWith(Seq(Array[Object]("1","2","3"))) //This does not work
  }
}

Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaVanillaMethodMirror1.jinvokeraw(JavaMirrors.scala:415)
    at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaMethodMirror.jinvoke(JavaMirrors.scala:380)
    at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaVanillaMethodMirror.apply(JavaMirrors.scala:396)

在我的用例中,数组是使用反射以及数组[对象]创建的。 我有案例类的数组字段的 scala.reflect.api.Types#Type 。我需要以某种方式将现有数组转换为具有正确类型的数组 我了解数组的内部实现导致了这个问题。 如何在运行时将数组转换为所需的类型。 我尝试使用 Arrays.copyOf 但没有让它工作

reflection
1个回答
0
投票

我能够通过将数组复制到另一个正确类型的数组中来解决问题:

val arr: Array[Any] = ...
val correctTypeArray = java.lang.reflect.Array.newInstance(theClass, arr.size).asInstanceOf[Array[Any]]
arr.indices.foreach(i => correctTypeArray(i) = arr(i))
© www.soinside.com 2019 - 2024. All rights reserved.