使用Scala中的隐式和类型创建通用可重用函数

时间:2015-06-11 18:56:55

标签: json scala playframework generic-programming playframework-2.4

我有一块代码块可以在整个地方进行复制。这段代码(大约10行)处理入站操作,验证它们,处理JSON序列化,并调用内部函数,准备结果。

我知道可以将其减少为对普通辅助函数的单行调用,但由于隐含,类型以及我对Scala语法的了解不多,我一直遇到问题。

代码(两个单独的示例,用于演示它们的不同之处):

val authenticate = GPAuthenticatedAction(parse.json) { implicit request =>
    request.body.validate[AuthenticationRequest] match {
        case JsSuccess(request, _) => {
            val (status, response) = performAuthentication(request)
            status(Json.toJson(response.asInstanceOf[AuthenticationResponse]))
        }

        case e: JsError => NotAcceptable(Json.toJson(GPError.MalformedJSON.value(e.toString + " REQUEST: " + request.body.toString)))
    }
}

val register = GPAuthenticatedAction(parse.json) { implicit request =>
    request.body.validate[RegistrationRequest] match {
        case JsSuccess(request, _) => {
            val (status, response) = performRegistration(request)
            status(Json.toJson(response.asInstanceOf[RegistrationResponse]))
        }

        case e: JsError => NotAcceptable(Json.toJson(GPError.MalformedJSON.value(e.toString + " REQUEST: " + request.body.toString)))
    }
}

正如您所见 - 非常非常相似,但请求类型(AuthenticationRequestRegistrationRequest)和响应类型(AuthenticationResponse与{{1}除外})。否则它是样板。

应该有办法将其提炼为类似的东西:

RegistrationResponse

我在定义val register = GPAuthenticatedAction(parse.son) from(RegistrationRequest, RegistrationResponse) 时花了很多钱,但这导致了一系列问题(没有关于JSON反序列化的信息等)。所以,我尝试通过创建一些特征from[I,O](request: I, response: O)GPRequest来抽象出来:

GPResult

然后尝试定义一个函数,如:

trait GPRequest[T] {
    implicit val format = Json.format[T]
}

trait GPResponse[T] {
    implicit val format: Format[T] = Json.format[T]
    def from(error: GPError): GPResponse
}

但这会导致各种形式的问题。我在下面粘贴了编译器错误,但一般的要点是:

  1. JSON无法弄清楚如何处理隐式序列化(格式化/读取/写入)。找不到实际类型的def from[I: GPRequest, O: GPResponse](request: Request) { implicit request => request.body.validate[I] match { case JsSuccess(request, _) => { val (status, response) = performAuthentication(request) status(Json.toJson(response.asInstanceOf[O])) } case e: JsError => NotAcceptable(Json.toJson(GPError.MalformedJSON.value(e.toString + " REQUEST: " + request.body.toString))) } } apply
  2. 在GPRequest,GPResponse上输入参数错误。
  3. 无法将请求声明为unapply(我的Scala语法可能已经搞砸了)。
  4. 情况变得更糟。

    底线问题:有没有人有一个干净的设计模式来实现我在这里寻找的东西?(或者,知道Play和Scala的人可以提供一些指导从这里开始)。这看起来应该是可能的,但我很难搞清楚下一步。

    对于勇敢者,以下是错误:

    implicit

1 个答案:

答案 0 :(得分:1)

您可以编写父案例类而不是特征,并扩展现有类型:

AuthenticationRequest, RegistrationRequest, AuthenticationResponse, RegistrationResponse

是新的父案例类的子类。

有了这个,您可以更改签名以扩展您的泛型类型:

def from[I <: GPRequest, O <: GPResponse]