Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic Codec[T] for Circle JSON parser #2

Open
aukgit opened this issue Apr 19, 2020 · 0 comments
Open

Generic Codec[T] for Circle JSON parser #2

aukgit opened this issue Apr 19, 2020 · 0 comments

Comments

@aukgit
Copy link
Owner

aukgit commented Apr 19, 2020

Main Goal

Make circle JSON encode/decode on the abstract class level. Just like NewtonJson (https://www.newtonsoft.com/json)

I want to make a generic one where I have a [T] and that [T] transforms into something that can be convertible to JSON. Probably there is a boundary (I am unaware of).

Versions (Scala 2.13.1, Circle: 0.12.3)

lazy val scalaVersionF = "2.13.1"
lazy val circeVersion = "0.12.3"

  "io.circe" %% "circe-core" % circeVersion,
  "io.circe" %% "circe-generic" % circeVersion,
  "io.circe" %% "circe-parser" % circeVersion,
  "de.heikoseeberger" %% "akka-http-circe" % "1.31.0",

Issue Summary

Things work fine when the actual type is given, however, it doesn't work when generics are used.

AnyVal JSON Add

Reference: https://www.programcreek.com/scala/io.circe.Decoder

import io.circe.{Decoder, Encoder}
import shapeless.Unwrapped

trait AnyValCirceEncoding {
  implicit def anyValEncoder[V, U](implicit ev: V <:< AnyVal,
    V: Unwrapped.Aux[V, U],
    encoder: Encoder[U]): Encoder[V] = {
    val _ = ev
    encoder.contramap(V.unwrap)
  }

  implicit def anyValDecoder[V, U](implicit ev: V <:< AnyVal,
    V: Unwrapped.Aux[V, U],
    decoder: Decoder[U]): Decoder[V] = {
    val _ = ev
    decoder.map(V.wrap)
  }
}

object AnyValCirceEncoding extends AnyValCirceEncoding
trait CircleJsonSupport extends de.heikoseeberger.akkahttpcirce.FailFastCirceSupport
  with AnyValCirceEncoding

Examples

Abstract API Sample, CircleJsonSupport integrated

trait RestWebApiContracts[TTable, TRow, TKey]
  extends
    RestWebApi[TTable, TRow, TKey] with
    RestWebApiBodyProcessor[TTable, TRow, TKey] with
    RestWebApiMessages[TTable, TRow, TKey] with
    RestWebApiJson[TTable, TRow, TKey] with
    RestWebApiEntityJsonAdapter[TTable, TRow, TKey] with
    CircleJsonSupport // has the support for the Circle any value type

Build fails

abstract class AbstractRestWebApi[TTable, TRow, TKey]
(components : ControllerComponents)
  extends
    AbstractController(components) with
    RestWebApiContracts[TTable, TRow, TKey] {
  val service : AbstractBasicPersistentService[TTable, TRow, TKey]

  def getAll : Action[AnyContent] = Action { implicit request =>
      // cannot create for List[TRow]
      implicit val listEncoder: Encoder.AsObject[List[TRow]] = deriveEncoder[List[TRow]]
      val records : List[TRow] = service.getAll
      val json = records.asJson(listEncoder).space2
      Ok(json)
    }
}

Build Success and works fine if the same code is written in the actual class

class CampaignsApiController @Inject()(
  campaignService : CampaignService,
  components      : ControllerComponents)
  extends AbstractRestWebApi[Campaign, CampaignRow, Int](components) {
    override def getAll : Action[AnyContent] = Action { implicit request : Request[AnyContent] =>
      val campaigns: List[CampaignRow] = campaignService.getAll
      val json = campaigns.asJson.spaces2
      Ok(json) // works perfect and returns json array
    }
}

Build Success and works fine if casting happens properly

abstract class AbstractRestWebApi[TTable, TRow, TKey]
(components : ControllerComponents)
  extends
    AbstractController(components) with
    RestWebApiContracts[TTable, TRow, TKey] {
  val service : AbstractBasicPersistentService[TTable, TRow, TKey]

  def getAll : Action[AnyContent] = Action { implicit request =>
      // cannot create for List[TRow]
      implicitvallistEncoder:Encoder[List[CampaignRow]]=deriveEncoder[List[CampaignRow]]
      val campaigns=service.getAll
      val json =campaigns.asInstanceOf[List[CampaignRow]].asJson(listEncoder).spaces2
      Ok(json) // perfectly
    }
}

Implicts failed

Base Class

  lazy implicit val listEncoder : Encoder[List[TRow]] = Encoder[List[TRow]]
  lazy implicit val encoder : Encoder[TRow] = Encoder[TRow]
  lazy implicit val decoder : Decoder[TRow] = Decoder[TRow]
  lazy implicit val listDecoder : Decoder[List[TRow]] = Decoder[List[TRow]]

Concreate class Class

  override implicit val listEncoder : Encoder[List[CampaignRow]] = Encoder[List[CampaignRow]]
  override implicit val encoder : Encoder[CampaignRow] = Encoder[CampaignRow]
  override implicit val decoder : Decoder[CampaignRow] = Decoder[CampaignRow]
  override implicit val listDecoder : Decoder[List[CampaignRow]] = Decoder[List[CampaignRow]]

Also doesn't help

Case Class for CampaignRow (Slick Class)

case class CampaignRow(campaignid: Int, campaignname: String, contentcategoryid: String, totalbudgetcpm: Double = 0.0, spendalready: Double = 0.0, remainingamount: Double = 0.0, startdate: Option[Double] = Some(0.0), enddate: Option[Double] = Some(0.0), impressioncount: Int = 0, demandsideplatformid: Int, isrunning: Int = 0, priority: Int = 999, isretricttousergender: Int = 0, expectedusergender: Option[String], publisherid: Option[Int])

Build errors faced during

- could not find implicit value for parameter encoder: io.circe.Encoder[List[TRow]]
- could not find Lazy implicit value of type io.circe.generic.encoding.DerivedAsObjectEncoder[List[TRow]]
      implicit val listEncoder: Encoder.AsObject[List[TRow]] = deriveEncoder[List[TRow]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant