2014-12-19 21 views
3

我正在構建一個Scala Play應用程序,其中的事件和數據是以Json格式持久化的,我試圖爲用戶和他們分配的角色建模。我的想法是模擬作爲案例對象的角色,因爲每個標準角色只需要爲應用程序中的所有用戶定義一次,並且我想對特定用戶已分配的角色類型進行模式匹配。到目前爲止,我有這個;在Scala Play應用程序中避免此java.lang.ClassCastException錯誤的正確apply和unapply方法是什麼?

package models 

abstract class User { 
    def displayName: String 
    def role: Role 
} 

case class GuestUser(displayName: String, role: Role) extends User { 
} 

case class RegisteredUser(displayName: String, role: Role) extends User { 
} 

trait Role { // have tried abstract class too - but like idea of developing stackable traits for role permissions 
} 
object Role { 
    implicit val RoleTypeFormat: Format[Role] = Json.format[Role] 
    def apply(className: String): Role = Class.forName(className: String).asInstanceOf[Role] 
    def unapply(role: Role): Option[String] = Option(this.getClass.getName) // have also tried .getSimpleName 
} 

case object GuestUserRole extends Role { 
} 

case object RegisteredUserRole extends Role { 
} 

如果我不定義適用,不應用方法object Role,只依靠使用Json.format[Role]隱含的價值,我得到或「否取消應用功能發現」錯誤「沒有發現應用功能」 - 所以我加了他們,試圖擺脫這個錯誤。

我無法在沒有將.asInstanceOf[Role]添加到Role應用方法的情況下編譯它。現在編譯,但是當我嘗試設置role: Role參數使用新RegisteredUser實例,

val role: Role = RegisteredUserRole 

RegisteredUser實例被創建,其中的角色屬性,都會序列化JSON作爲;

"role":{"className":"models.Role$」}

但是當我嘗試反序列化,我得到Exception in thread "pool-4868-thread-1" java.lang.ClassCastException: java.lang.Class cannot be cast to models.Role

我的目標是用相同的RegisteredUser實例(或GuestUser實例)結束了,這樣我就可以在視圖中進行模式匹配控制器,沿着;

def isAuthorized: Boolean = { 
    role match { 
     case RegisteredUserRole => true 
     case GuestUserRole => false 
     // etc 
    } 
} 

任何幫助和建議,將非常感激。我在Scala和Play方面還不夠熟練和知識淵博,不知道我是否正在建模用戶和角色的正確軌道。

+0

我建議定義自定義JSON格式(即不使用'Json.format'快捷方式),而不是嘗試添加'apply'和'unapply'方法,使糖的工作。但要回答你的實際問題,你不能將'Class'強制轉換爲對象實例,你需要使用反射API來獲得它的靜態成員(它的名字就像'MODULE $'),實際的情況。 – lmm 2014-12-19 11:50:19

+0

感謝您的推薦並回答@lmm - 我將探索兩種方法。 – functup 2014-12-19 14:33:45

回答

3

正如@lmm所建議的那樣,最好提供一個自定義的Format[Role],而不是試圖以奇怪的方式創建實例。

事情是這樣的:

implicit val fmt = new Format[Role] { 

    def reads(js: JsValue): JsResult[Role] = { 
     js.validate[String] fold (
      error => JsError(error), 
      role => role match { 
       case "GuestUserRole" => JsSuccess(GuestUserRole) 
       case "RegisteredUserRole" => JsSuccess(RegisteredUserRole) 
       case _ => JsError(Nil) // Should probably contain some sort of `ValidationError` 
      } 
     ) 
    } 

    def writes(r: Role): JsValue = JsString(r.toString) 
} 
+0

非常感謝這個解決方案。它工作完美:)(並感謝@lmm推薦此路線)。我喜歡直接清晰地引用案例對象的事實。如果有的話,從我現在的知識狀態中得到這個解決方案本來會花費我很多時間,所以再次感謝。我將更深入地學習play.api.libs.json,以更好地理解自定義格式。 – functup 2014-12-19 17:29:25

相關問題