`Future.failed` внутри` transformWith [Array [Byte]] `выдает ошибку компилятора - PullRequest
0 голосов
/ 13 февраля 2019

Я пытаюсь проанализировать HttpResponse от Акки.Идеальное поведение состоит в том, что если ответ возвращается успешно, передайте Array[Byte] представление HttpEntity вместе для обработки.Однако, если состояние возвращается как сбой, передайте Future.failed с исключением, содержащим код состояния и представление дерева JSON HttpEntity.Причина передачи дерева JSON состоит в том, что этот абстрактный метод запроса использует разные серверы, и они по-разному форматируют свои ответы, поэтому я хочу обработать синтаксический анализ ответа в этих других классах.

Я пытался различные манипуляции с этим рабочим процессом.Выдача исключения напрямую вместо возврата Future.failed возвращает значение None вместо дерева JSON в исключении.Другие методы дают похожие результаты.Когда я println(MAPPER.readTree(byteArray)) выводит ответ, как я ожидал, но затем возвращается None в поле response поля BadRequestException.

import akka.http.scaladsl.model._
import akka.http.scaladsl.model.headers.Authorization
import akka.stream.Materializer
import com.fasterxml.jackson.databind.{DeserializationFeature, JsonNode, ObjectMapper}
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper

val MAPPER = new ObjectMapper with ScalaObjectMapper
  MAPPER.registerModule(DefaultScalaModule)
  MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

def performQueryRaw(method: HttpMethod, uri: Uri, entity: Option[RequestEntity] = None, authorization: Option[Authorization] = None): Future[Array[Byte]] = {

  val request: HttpRequest = HttpRequest(
    method = method,
    uri = uri,
    entity = entity.getOrElse(HttpEntity.Empty),
    headers = authorization.toList)

  http.singleRequest(request).transformWith[Array[Byte]] {
    case Success(response: HttpResponse) =>
      convertEntityToBytes(response.entity).map { byteArray =>
        if (response.status.isFailure()) Future.failed(BadRequestException(response.status, MAPPER.readTree(byteArray)))
        else byteArray
      }
      case Failure(throwable) => Future.failed(RequestFailedException(throwable.getMessage + " -- " + uri.toString, throwable))
    }
  }

def convertEntityToBytes(entity: HttpEntity): Future[Array[Byte]] = {
  entity.dataBytes.runFold[Seq[Array[Byte]]] (Nil) {
    case (acc, next) => acc :+ next.toArray
  }.map(_.flatten.toArray)
}

case class BadRequestException(status: StatusCode, response: JsonNode = None.orNull, t: Throwable = None.orNull) extends Exception(t)

case class RequestFailedException(message: String, t: Throwable = None.orNull) extends Exception(message, t)

Я ожидаю BadRequestException со значением non-none для JsonNode.Вместо этого я получаю сообщение об ошибке компилятора Future.failed, которое гласит:

Expression of type Future[Nothing] doesn't conform to expected type Array[Byte].

Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 13 февраля 2019

Используйте flatMap вместо map при запуске следующего шага после convertEntityToBytes:

def performQueryRaw(
    method: HttpMethod,
    uri: Uri,
    entity: Option[RequestEntity] = None,
    authorization: Option[Authorization] = None
  ): Future[Array[Byte]] = {

    val request: HttpRequest = HttpRequest(
      method = method,
      uri = uri,
      entity = entity.getOrElse(HttpEntity.Empty),
      headers = authorization.toList
    )

    Http().singleRequest(request).transformWith[Array[Byte]] {
      case Success(response: HttpResponse) =>
        convertEntityToBytes(response.entity).flatMap { byteArray =>
          if (response.status.isFailure()) Future.failed(new Exception("change this exception to one you had"))
          else Future.successful(byteArray)
        }
      case Failure(throwable) => Future.failed(new Exception("also here"))
    }
  }

Поскольку вы хотите провалить вычисления Future, вам необходимо вернуть новое Future.В случае неудачи вы уже делали Future.failed.Недостающий кусок также должен был обернуть byteArray в Future.successful.Конечно, это один из способов решения ошибки компиляции типов в этом коде.

...