0

I am attempting to create a unmarshaller for akka http, going from avro to a custom case class. But it gives me a very vague error: "could not find implicit value". How can I debug this or make scala give me hint where the problem is?

I set up the route as such:

class MetricsRoute(implicit val system: ActorSystem, implicit val materializer: ActorMaterializer) {
import system.dispatcher

  def getRoute() = {
    path("metrics") {
      put {
        decodeRequest {
          entity(as[Metrics]) { metrics: Metrics =>
            println(metrics.time)
            complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>hi!</h1>"))
          }
        }
      }
    }
  }

In the same class I also created the unmarshaller like this:

  implicit def avroUnmarshaller(): FromRequestUnmarshaller[Metrics] =
    Unmarshaller.withMaterializer {
      implicit ex: ExecutionContext =>
      implicit mat: Materializer =>
        request: HttpRequest => {
          val inputStream = request.entity.dataBytes.runWith(
            StreamConverters.asInputStream(FiniteDuration(3, TimeUnit.SECONDS))
          )

          val reader = new SpecificDatumReader[AvroMetrics](classOf[AvroMetrics])
          val decoder:BinaryDecoder = DecoderFactory.get().binaryDecoder(inputStream, null)

          //AvroMetrics is a case class generated from the avro schema
          val avroMetrics:AvroMetrics = AvroMetrics(0, 0, List())
          reader.read(avroMetrics, decoder)

          Future {
            //converts the avro case class to the case class specific for my application
            convertMetrics(avroMetrics)
          }
        }
  }

But this gives me the very vague 'could not find implicit value' error:

[error] /mypath/MetricsRoute.scala:34: could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[my.package.types.Metrics]
[error]           entity(as[Metrics]) { metrics: Metrics =>
[error]                    ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed

How do I go about debugging what is missing or what I did wrong?

Edit:

Worth noting is when I specify the unmarshaller myself it does work, so changing

entity(as[Metrics]) { metrics: Metrics =>

to

entity(avroUnmarshaller) { metrics: Metrics =>

Which seems to indicate the marshaller code itself isn't wrong, but I've done something wrong with the types?

Richard Deurwaarder
  • 2,023
  • 1
  • 26
  • 40

1 Answers1

1

The compiler is looking for a FromRequestUnmarshaller[Metrics], what you defined is of type () => FromRequestUnmarshaller[Metrics].

Try defining your implicit with no empty braces, e.g.

implicit def avroUnmarshaller: FromRequestUnmarshaller[Metrics] = ???

instead of

implicit def avroUnmarshaller(): FromRequestUnmarshaller[Metrics] = ???

(also, it could be made a val, but that's not relevant to this issue)

Stefano Bonetti
  • 8,973
  • 1
  • 25
  • 44
  • Ahh, that makes a lot of sense. Too bad it doesn't show this explicitly in the type. Is there any advantage of using val over def? – Richard Deurwaarder May 24 '17 at 14:02
  • 1
    `def` gets evaluated anew every time it's called, `val` gets evaluated only once (https://stackoverflow.com/questions/4437373/use-of-def-val-and-var-in-scala) – Stefano Bonetti May 24 '17 at 14:26