我正在尝试使用spray在Scala中创建通用HTTP客户端。这是类定义:
object HttpClient extends HttpClient
class HttpClient {
implicit val system = ActorSystem("api-spray-client")
import system.dispatcher
val log = Logging(system, getClass)
def httpSaveGeneric[T1:Marshaller,T2:Unmarshaller](uri: String, model: T1, username: String, password: String): Future[T2] = {
val pipeline: HttpRequest => Future[T2] = logRequest(log) ~> sendReceive ~> logResponse(log) ~> unmarshal[T2]
pipeline(Post(uri, model))
}
val genericResult = httpSaveGeneric[Space,Either[Failure,Success]](
"http://", Space("123", IdName("456", "parent"), "my name", "short_name", Updated("", 0)), "user", "password")
}
对象utils.AllJsonFormats
具有以下声明。它包含所有模型格式。在“另一端”使用相同的类,即我也编写了API并在那里使用了与spray-can和spray-json相同的格式化程序。
object AllJsonFormats
extends DefaultJsonProtocol with SprayJsonSupport with MetaMarshallers with MetaToResponseMarshallers with NullOptions {
当然,该对象具有模型序列化的定义.api.Space,models.api.Failure和models.api.Success。
Space
类似乎很好,即当我告诉泛型方法它将接收并返回Space
时,没有错误。但是一旦我将Either带入方法调用,我就会得到以下编译器错误:
无法找到类型的证据参数的隐含值 spray.httpx.unmarshalling.Unmarshaller [要么[models.api.Failure,models.api.Success]。
我的期望是,在spray.json.DefaultJsonProtocol中隐含的,即在spray.json.StandardFormts中,会让我受到覆盖。
以下是我的HttpClient类,它最好是通用的: 更新:更清晰/可重复的代码示例
object TestHttpFormats
extends DefaultJsonProtocol {
// space formats
implicit val idNameFormat = jsonFormat2(IdName)
implicit val updatedByFormat = jsonFormat2(Updated)
implicit val spaceFormat = jsonFormat17(Space)
// either formats
implicit val successFormat = jsonFormat1(Success)
implicit val failureFormat = jsonFormat2(Failure)
}
object TestHttpClient
extends SprayJsonSupport {
import TestHttpFormats._
import DefaultJsonProtocol.{eitherFormat => _, _ }
val genericResult = HttpClient.httpSaveGeneric[Space,Either[Failure,Success]](
"https://api.com/space", Space("123", IdName("456", "parent"), "my name", "short_name", Updated("", 0)), "user", "password")
}
有了上述内容,仍然会出现unmarshaller未解决的问题。非常感谢帮助..
感谢。
答案 0 :(得分:3)
如果Either[A,B]
和Marshaller[A]
位于Marshaller[B]
特征内的定义范围内,则MetaMarshallers
的默认编组器。但是,走另一个方向需要Unmarshaller
。您需要为Unmarshaller
定义范围Either[Failure, Success]
。如果没有预期响应的具体知识,以及选择是否将响应解组为Left
或Right
的策略,则无法对此进行编码。例如,让我们假设您想要从非200响应中返回失败,并从200 json响应主体返回成功:
type ResultT = Either[Failure,Success]
implicit val resultUnmarshaller: FromResponseUnmarshaller[ResultT] =
new FromResponseUnmarshaller[ResultT] {
def apply(response: HttpResponse): Deserialized[ResultT] = response.status match {
case StatusCodes.Success(200) =>
Unmarshaller.unmarshal[Success](response.entity).right.map(Right(_))
case _ => Right(Left(Failure(...)))
}
}
<强>更新强>
仔细研究一下,问题似乎是eitherFormat
中的默认spray.json.StandardFormats
不是RootJsonFormat
,这是spray.httpx.SprayJsonSupport
中定义的默认JSON unmarshaller所必需的}。定义以下隐式方法应该可以解决问题:
implicit def rootEitherFormat[A : RootJsonFormat, B : RootJsonFormat] = new RootJsonFormat[Either[A, B]] {
val format = DefaultJsonProtocol.eitherFormat[A, B]
def write(either: Either[A, B]) = format.write(either)
def read(value: JsValue) = format.read(value)
}
我有一个工作示例要点,希望能解释如何使用它。 https://gist.github.com/mikemckibben/fad4328de85a79a06bf3