2017-12-13 1 views
0
private def responseValidationFlow[T](responsePair: ResponsePair)(implicit evidence: FromByteStringUnmarshaller[T]) = responsePair match { 
    case (Success(response), _) => { 
     response.entity.dataBytes 
     .via(Framing.delimiter(ByteString("\n"), maximumFrameLength = 8192)) 
     .mapAsyncUnordered(Runtime.getRuntime.availableProcessors()) { body => 
      if (response.status == OK) { 
      val obj: Future[T] = Unmarshal(body).to[T] 
      obj.foreach(x => log.debug("Received {}: {}.", x.getClass.getSimpleName, x)) 
      obj.map(Right(_)) 
      } else { 
      val reason = body.utf8String 
      log.error("Non 200 response status: {}, body: {}.", response.status.intValue(), reason) 
      Future.successful(reason) 
       .map(Left(_)) 
      } 
     } 
    } 
    case (Failure(t), _) => { 
     Source.single(Left(t.getMessage)) 
    } 
    } 

Was ich tun möchte, ist beide Seiten der Either zu parametrisieren. Das ist nicht schwer zu tun, aber was ich habe Probleme mit der Erstellung einer Left oder Right, die keinen Wert hat. In diesem Fall sollte der Körper vollständig verzehrt und entsorgt werden. Ich versuchte mit ClassTag s, aber der Compiler denkt, dass der Typ Any ist, nicht S oder T. Eine Probe Aufruf dieses Verfahren würde wie responseValidationFlow[String, Unit] aussieht eine Herstellung Source[Either[String, Unit]]Wie erstellt man entweder [S, T] wo S oder T Einheit sein könnte?

+4

Ist das nicht eine 'Option [String]' –

+0

@RamonJRomeroyVigil Nur wenn einer der Typen 'Unit' ist. Ein anderes Mal könnte es sein: Entweder [String, Was auch immer] ' –

Antwort

0

Ich glaube, können Sie nur einen impliziten Unmarshaller zu Unit in Umfang definieren:

implicit val unitUnmarshaller: FromByteStringUnmarshaller[Unit] = 
    Unmarshaller.strict(_ =>()) 
+0

Sie sagen also, dass ich nicht speziell nach dem Typ suchen sollte, sondern von Impliziten und dem Compiler abhängig bin, um die Konvertierung durchzuführen? Ich werde das versuchen und danach kommentieren. –

+0

@AbhijitSarkar Sie würden nicht wirklich auf die implizite abhängen. In der Frage, die Sie gesagt haben, geben Sie explizit 'Unit' an, wenn Sie' responceValidationFlow [Unit] 'aufrufen. Wenn Sie also angeben, dass Sie "Unit" möchten, verwendet der Compiler diesen implizit und verwirft den Antworttext. – Kolmar

+0

Es funktioniert nicht ohne die impliziten Beweise. Ich habe eine Antwort mit dem Arbeitscode gepostet (es ist zu groß für einen Kommentar). Ich werde deine Antwort akzeptieren, als du mich zur Lösung geführt hast. –

0

Nach dem, was @Kolmar vorgeschlagen, hier sind die Arbeitscode.

private def responseValidationFlow[L, R](responsePair: ResponsePair)(
    implicit ev1: FromByteStringUnmarshaller[L], ev2: FromByteStringUnmarshaller[R] 
): Source[Either[L, R], Any] = { 
    responsePair match { 
    case (Success(response), _) => { 
     response.entity.dataBytes 
     .via(Framing.delimiter(ByteString("\n"), maximumFrameLength = 8192)) 
     .mapAsyncUnordered(Runtime.getRuntime.availableProcessors()) { body => 
      if (response.status == OK) { 
      val obj: Future[R] = Unmarshal(body).to[R] 
      obj.foreach(x => log.debug("Received {}.", x.getClass.getSimpleName)) 
      obj.map(Right(_)) 
      } else { 
      log.error("Non 200 response status: {}.", response.status.intValue()) 
      Unmarshal(body).to[L] 
       .map(Left(_)) 
      } 
     } 
    } 
    case (Failure(t), _) => { 
     log.error(t, "Request failed.") 
     Source.empty 
    } 
    } 
} 

Wenn die Methode wie diese responseValidationFlow[Status, Unit] aufgerufen wird, dann wird ein FromByteStringUnmarshaller[Unit] bei Aufrufort zur Verfügung gestellt. Der Compiler verwendet die implicit Beweise, um die erforderliche Unmarshaller zu finden.

Verwandte Themen