Получить тип примитивного поля из объекта, используя отражение Scala - PullRequest
0 голосов
/ 27 февраля 2019

Поэтому я пытаюсь получить типы каждого поля в классе объектов Scala:

package myapp.model

object MyObject {
  val theInt: Option[Int]
}

Использование ReflectionHelper, любезно предоставленного Брайаном в этой публикации .Я использую getFieldType, но он возвращает Option[Object] вместо того, что есть, то есть Option[Int].Пример кода в этом ответе работает для класса дел, например:

package myapp.model

case class Person(
 name: String,
 age: Option[Int]
)

scala> ReflectionHelper.getFieldType("myapp.model.Person", "age")  // int
res12: Option[reflect.runtime.universe.Type] = Some(Option[Int])

Однако, если я запускаю getFieldType в поле объекта Scala, мы получим следующее:

scala> ReflectionHelper.getFieldType("myapp.model.MyObject$", "theInt")
res10: Option[reflect.runtime.universe.Type] = Some(Option[Object])

Чем отличается объект Scala от такого поведения, и как я могу получить getFieldType для возврата Option[Int] вместо Option[Object], как это происходит для класса case?

Вот ReflectionHelper от другоговопрос для удобства:

import scala.reflect.runtime.{ universe => u }
import scala.reflect.runtime.universe._

object ReflectionHelper {

  val classLoader = Thread.currentThread().getContextClassLoader

  val mirror = u.runtimeMirror(classLoader)

  def getFieldType(className: String, fieldName: String): Option[Type] = {

    val classSymbol = mirror.staticClass(className)

    for {
      fieldSymbol <- classSymbol.selfType.members.collectFirst({
        case s: Symbol if s.isPublic && s.name.decodedName.toString() == fieldName => s
      })
    } yield {

      fieldSymbol.info.resultType
    }
  }

  def maybeUnwrapFieldType[A](fieldType: Type)(implicit tag: TypeTag[A]): Option[Type] = {
    if (fieldType.typeConstructor == tag.tpe.typeConstructor) {
      fieldType.typeArgs.headOption
    } else {
      Option(fieldType)
    }
  }

  def getFieldClass(className: String, fieldName: String): java.lang.Class[_] = {

    // case normal field return its class
    // case Option field return generic type of Option

    val result = for {
      fieldType <- getFieldType(className, fieldName)
      unwrappedFieldType <- maybeUnwrapFieldType[Option[_]](fieldType)
    } yield {
      mirror.runtimeClass(unwrappedFieldType)
    }

    // Consider changing return type to: Option[Class[_]]
    result.getOrElse(null)
  }
}

1 Ответ

0 голосов
/ 28 февраля 2019

Попробуйте

// import scala.reflect.runtime.universe._  
mirror.staticClass("myapp.model.Person").typeSignature.member(TermName("age")).typeSignature // => Option[Int]    
mirror.staticModule("myapp.model.MyObject").typeSignature.member(TermName("theInt")).typeSignature // => Option[Int]
...