В spray для scala получить FromRequestUnmarshaller от обычного Unmarshaller

#scala #spray

#scala #спрей

Вопрос:

В scala spray есть ли способ преобразовать из a Unmarshaller[T] в a FromRequestUnmarshaller[T] . Я застрял, пытаясь заставить entity директиву работать без использования implicits. Например:

 ...
} ~ post {
  path("myPath") {
    entity(sprayJsonUnmarshaller[MyCaseClass](myCaseClassRootJsonFormat)) { myCaseClass =>
      complete { handle(myCaseClass) }
    }
  } ~ ...
 

Ошибка компилятора:

 Multiple markers at this line
    - type mismatch; found : spray.httpx.unmarshalling.Unmarshaller[MyCaseClass] (which 
     expands to) spray.httpx.unmarshalling.Deserializer[spray.http.HttpEntity,MyCaseClass] 
     required: spray.httpx.unmarshalling.FromRequestUnmarshaller[?] (which expands to) 
     spray.httpx.unmarshalling.Deserializer[spray.http.HttpRequest,?]
    - type mismatch; found : spray.httpx.unmarshalling.Unmarshaller[MyCaseClass] (which 
     expands to) spray.httpx.unmarshalling.Deserializer[spray.http.HttpEntity,MyCaseClass] 
     required: spray.httpx.unmarshalling.FromRequestUnmarshaller[?] (which expands to) 
     spray.httpx.unmarshalling.Deserializer[spray.http.HttpRequest,?]
 

Ответ №1:

В этой части Spray сильно зависит от неявного разрешения. Возможно, я ошибаюсь, но, насколько я знаю, теперь есть простой и элегантный способ сделать это. Как и было задумано, вы должны выполнить следующую директиву: entity(as[MyCaseClass]) . Затем, если вы посмотрите на as[_] директиву, нет короткого способа сделать простой unmarshaller (который принимает сущность и создает ваш класс case) в fromRequestUnmarshaller (из HttpRequest -> case class ), все неявные расширители можно найти [здесь] (https://github.com/spray/spray/blob/master/spray-httpx/src/main/scala/spray/httpx/unmarshalling/UnmarshallerLifting.scala#L21). Поэтому, когда вы вызываете entity(as[MyCaseClass]) , он расширяется до этого:

 entity {
  as[MyCaseClass] {
    fromRequestUnmarshaller[MyCaseClass] {
      fromMessageUnmarshaller[MyCaseClass] {
        sprayJsonUnmarshaller[MyCaseClass](myCaseClassRootJsonFormat)
      }
    }
  }
}
 

Если вы хотите сделать его явным, вам следует записать его в верхней форме. Таким образом, вы можете удалить as[MyCaseClass]

С другой стороны, вы можете выбрать другой явный способ — извлечь объект и преобразовать его в json:

 requestInstance { req =>
  val json = req.entity.asString.parseJson
  json.convertTo(myCaseClassRootJsonFormat)
}
 

Комментарии:

1. Я также сделал FromRequestUnmarshaller следующее: def unmarshaller[T](fmt: JsonFormat[T]): FromRequestUnmarshaller[T] = { val f: HttpRequest => T = hr => fmt.read(hr.entity.asString) Deserializer.fromFunction2Converter[HttpRequest, T](f) }