2013-06-24 15 views
3

我正在嘗試爲可以處理Java枚舉的Json4s編寫一個通用自定義序列化程序,該枚舉類型爲T <:Enum [T]。要做到這一點,我想使用Enum.valueOf方法,它也採用類型爲T <的類令牌:Enum [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有正確的類型。

回答

3

enumerationClassdeserialize方法陰影它之外定義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成爲一個穩定的標識符,即在這裏使其成爲大寫。請參閱this questionanswer瞭解更多信息。

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") 
     } 
    } 
    } 

    ... 
} 
+0

謝謝,我甚至沒有意識到大寫字母的變量名稱意味着什麼在斯卡拉。我在原始代碼(基於別人寫的不太通用的東西)中確實擁有它,但認爲它只是奇怪的風格,所以我在添加通用部分之前對其進行了更改,然後想知道爲什麼它不起作用。 – Ryan

0

嘗試宣告enumerationClass爲:

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

你已經知道Manifest的的runtimeClass是T型的,所以我不知道你爲什麼被聲明爲val enumerationClass: Class[_ <: Enum[T]]Enum.valueOf無法使用通配類型,所以這就是您看到該錯誤的原因。