我有以下课程
package myapp.model
case class Person(
name: String,
age: Option[Int]
)
我想实现以下功能:
def getFieldClass(className: String, fieldName:String): java.lang.Class[_] = {
// case normal field return its class
// case Option field return generic type of Option
}
以便进行以下输入:
该函数将返回类对象:scala.Int
使用Java Reflection API的解决方案不能很好地工作,它返回选项[Int]的java.lang.Object:
def getFieldClass(className: String, fieldName:String): java.lang.Class[_] = {
val cls = java.lang.Class.forName(className)
val pt = cls.getDeclaredField(fieldName).getGenericType.asInstanceOf[java.lang.reflect.ParameterizedType]
val tpe = pt.getActualTypeArguments()(0);
java.lang.Class.forName(tpe.getTypeName)
}
我正在编写反序列化功能的一部分而我没有对象来检查它的类型,我只有一个类名。
答案 0 :(得分:2)
您可以使用Scala的反射库来完成此任务。
虽然不是特别漂亮:
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)
}
}
然后:
ReflectionHelper.getFieldClass("myapp.model.Person", "age") // int
ReflectionHelper.getFieldClass("myapp.model.Person", "name") // class java.lang.String
我建议将getFieldClass
的返回类型更改为可选,以防字段值有意义!
答案 1 :(得分:0)
也许这可以帮到你。 TypeTags and manifests.
例如,我们可以编写一个方法来获取一些任意对象,并使用TypeTag打印有关该对象的类型参数的信息:
import scala.reflect.runtime.universe._ def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = { val targs = tag.tpe match { case TypeRef(_, _, args) => args } println(s"type of $x has type arguments $targs") }
在这里,我们编写一个在T上参数化的通用方法paramInfo,我们 提供隐式参数(隐式标签:TypeTag [T])。我们可以 直接访问标记表示使用的类型(类型为Type) TypeTag的方法tpe。
然后我们可以使用我们的方法paramInfo,如下所示:
scala> paramInfo(42) type of 42 has type arguments List() scala> paramInfo(List(1, 2)) type of List(1, 2) has type arguments List(Int)