我正在构建一个Scala Play应用程序,其中事件和数据以Json格式保存,并且我正在尝试对用户及其分配的角色进行建模。我的想法是将角色建模为案例对象,因为每个标准角色只需要为应用程序中的所有用户定义一次,并且我想根据分配的特定用户的角色类型进行模式匹配。到目前为止,我有这个;
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]
的隐式值,我会收到"未找到应用函数"或"未找到取消应用函数"错误 - 所以我添加了它们,以尝试摆脱此错误。
如果不向Role
应用方法添加.asInstanceOf[Role]
,我就无法编译它。它现在可以编译,但是当我尝试使用以下命令设置新RegisteredUser
实例的role: Role
参数时,
val role: Role = RegisteredUserRole
创建一个新的RegisteredUser
实例,其中角色属性被序列化为 Json AS;
"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 方面还不够熟练和知识渊博,无法知道我是否在建模用户和角色方面走在正确的轨道上。
正如@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)
}