如何从有界泛型类型中获取类



我正试图为Json4s编写一个通用的自定义序列化程序,它可以处理类型为T<的Java枚举:枚举[T]。要做到这一点,我想使用Enum.valueOf方法,它接受一个类型也为T<的类令牌:枚举[T]。这就是我目前所拥有的:

class EnumSerializer[T <: Enum[T]](implicit m: Manifest[T]) extends Serializer[T] {
  val enumerationClass: Class[_ <: Enum[T]] = m.runtimeClass.asInstanceOf[Class[T]]
  def deserialize(implicit format: Formats) :  PartialFunction[(TypeInfo, JValue), T] = {
    case (t @ TypeInfo(enumerationClass, _), json) => {
      json match {
        case JString(value) => Enum.valueOf(enumerationClass, value.toUpperCase()).asInstanceOf[T]
        case value => throw new MappingException(s"Can't convert $value to $enumerationClass")
      }
    }
  }
  def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
    case i : Enum[T] => JString(i.name())
  }
}

但我得到以下编译错误:

inferred type arguments [_0] do not conform to method valueOf's type parameter bounds [T <: Enum[T]]
case JString(value) => Enum.valueOf(enumerationClass, value.toUpperCase()).asInstanceOf[T]

我不知道如何使enumerationClass具有正确的类型。

deserialize方法中的enumerationClass对其外部定义的val enumerationClass进行阴影处理。您的代码等效于:

case (t @ TypeInfo(a, _), json) => {
  json match {
    case JString(value) => Enum.valueOf(a, value.toUpperCase()).asInstanceOf[T]
    case value => throw new MappingException(s"Can't convert $value to $enumerationClass")
  }
}

这不是你想要的:这将始终匹配,因为你没有限制类。您需要使enumerationClass成为一个稳定的标识符,即在这里使其大写。请参阅此问答,了解更多关于此的阅读内容。

class EnumSerializer[T <: Enum[T]](implicit m: Manifest[T]) extends Serializer[T] {
  val EnumerationClass = m.runtimeClass.asInstanceOf[Class[T]]
  def deserialize(implicit format: Formats) :  PartialFunction[(TypeInfo, JValue), T] = {
    case (t @ TypeInfo(EnumerationClass, _), json) => {
      json match {
        case JString(value) => Enum.valueOf(EnumerationClass, value.toUpperCase()).asInstanceOf[T]
        case value => throw new MappingException(s"Can't convert $value to $enumerationClass")
      }
    }
  }
  ...
}

尝试将enumerationClass声明为:

val enumerationClass: Class[T] = m.runtimeClass.asInstanceOf[Class[T]]

您已经知道Manifest的runtimeClass的类型是T,所以我不知道为什么要将其声明为val enumerationClass: Class[_ <: Enum[T]]Enum.valueOf不能与通配符类型一起工作,所以这就是您看到该错误的原因。

最新更新