2014-12-19 22 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

相关问题