简体   繁体   中英

Scala - how to make generic decoder in circe?

I have two similar functions which have different return types:

override def getUsers(uri: Uri): F[Either[CodecException, List[User]]] =
    for {
      response <- retrieveDataFromClient(uri)
      result <- Sync[F].delay(response)
    } yield result

  override def getAnimals(uri: Uri): F[Either[CodecException, List[Animal]]] =
    for {
      response <- retrieveDataFromClient(uri)
      result <- Sync[F].delay(response)
    } yield result

And I have implicit circe decoders for them:

 implicit def decodeUser(response: HttpResponse): Either[CodecException, List[User]] = Decoder[List[User]].decode(response.entity)

 implicit def decodeAnimal(response: HttpResponse): Either[CodecException, List[Animal]] = Decoder[List[Animal]].decode(response.entity)

Now I have refactored first two methods into generic one:

 override def getData[A](uri: Uri): F[Either[CodecException, List[A]]] =
    for {
      response <- retrieveDataFromClient(uri)
      result <- Sync[F].delay(response)
    } yield result

And created generic circe decoder:

 implicit def decodeGeneric[A](response: HttpResponse): Either[CodecException, List[A]] = Decoder[List[A]].decode(response.entity)

But I got compilation error:

Could not find an instance of Decoder for List[A]
implicit def decodeGeneric[A](response: HttpResponse): Either[CodecException, List[A]] = Decoder[List[A]].decode(response.entity)


not enough arguments for method apply: (implicit instance: hammock.Decoder[List[A]])hammock.Decoder[List[A]] in object Decoder.
Unspecified value parameter instance.
implicit def decodeGeneric[A](response: HttpResponse): Either[CodecException, List[A]] = Decoder[List[A]].decode(response.entity)

Method retrieveDataFromClient return F[HttpResponse] from http client Hammock and response is implicit parsed into type User and Animal (via above decoders and works fine), but now I want to have it generic to remove boilerplate. Is it possible to refactor this code in this way and create generic decoder?

You can't make a generic decoder for every A , constrain your A in your decodeGeneric method to those that can be decoded. Circe auto should give you a decoder for your User and Animal classes.

import io.circe.generic.auto._

implicit def decodeGeneric[A](response: HttpResponse)(implicit decoder: Decoder[A]): Either[CodecException, List[A]] = 
    Decoder[List[A]].decode(response.entity)

Change the method signature by introducing a context bound

 implicit def decodeGeneric[A: Decoder](response: HttpResponse): Either[CodecException, List[A]] = Decoder[List[A]].decode(response.entity)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM