-
Notifications
You must be signed in to change notification settings - Fork 532
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 DecoderAndEncorder Example / Issue, Generic[T] Decoder[T], Generic[T] Encoder[T] #1442
Comments
@aukgit I'm not sure I understand the exact issue, but here are some examples that I hope might help. First, if you have import io.circe.{Decoder, Encoder}, io.circe.generic.semiauto._
implicit val encodeCampaignRow: Encoder[CampaignRow] = deriveEncoder
implicit val decodeCampaignRow: Decoder[CampaignRow] = deriveDecoder And then: scala> import io.circe.syntax._
import io.circe.syntax._
scala> CampaignRow(1, "abc", "def", demandsideplatformid = 0, expectedusergender = None, publisherid = None).asJson
res3: io.circe.Json =
{
"campaignid" : 1,
"campaignname" : "abc",
"contentcategoryid" : "def",
"totalbudgetcpm" : 0.0,
"spendalready" : 0.0,
"remainingamount" : 0.0,
"startdate" : 0.0,
"enddate" : 0.0,
"impressioncount" : 0,
"demandsideplatformid" : 0,
"isrunning" : 0,
"priority" : 999,
"isretricttousergender" : 0,
"expectedusergender" : null,
"publisherid" : null
} Once you have that, you should never explicitly need to define a So you should just make sure you have an encoder in scope for If you're working with a generic type instead of a concrete class like abstract class AbstractRestWebApi[TTable, TRow: Encoder, TKey]
(components : ControllerComponents)
extends
AbstractController(components) with
RestWebApiContracts[TTable, TRow, TKey] {
val service : AbstractBasicPersistentService[TTable, TRow, TKey]
def getAll : Action[AnyContent] = Action { implicit request =>
val records : List[TRow] = service.getAll
val json = records.asJson.space2
Ok(json)
}
} Which is syntactic sugar for the following: abstract class AbstractRestWebApi[TTable, TRow, TKey]
(components : ControllerComponents)
(implicit encodeTRow: Encoder[TRow])
extends
AbstractController(components) with
RestWebApiContracts[TTable, TRow, TKey] {
val service : AbstractBasicPersistentService[TTable, TRow, TKey]
def getAll : Action[AnyContent] = Action { implicit request =>
val records : List[TRow] = service.getAll
val json = records.asJson(encodeTRow).space2
Ok(json)
}
} You'd have to include this constraint on any methods or other classes that instantiate this class with a generic type, all the way up to the point where there's a concrete type. Hope that helps! |
Thank you @travisbrown for the quick help. For now, I have found a workaround using def, instead of val. As I mentioned before, these below ones failed: Failed Example// abstract 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
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] Success Example// abstract class
def listEncoder : Encoder[List[TRow]]
def encoder : Encoder[TRow]
def decoder : Decoder[TRow]
def listDecoder : Decoder[List[TRow]]
// Concreate class
override def listEncoder : Encoder[List[CampaignRow]] = Encoder[List[CampaignRow]]
override def encoder : Encoder[CampaignRow] = Encoder[CampaignRow]
override def decoder : Decoder[CampaignRow] = Decoder[CampaignRow]
override def listDecoder : Decoder[List[CampaignRow]] = Decoder[List[CampaignRow]] Probably I will use an Encoder encapsulate class to solve this issue. class GenericCodec[TRow : Encoder] {
def listEncoder : Encoder[List[TRow]] = Encoder[List[TRow]]
def encoder : Encoder[TRow] = Encoder[TRow]
def decoder : Decoder[TRow] = Decoder[TRow]
def listDecoder : Decoder[List[TRow]] = Decoder[List[TRow]]
} val genericCodec = new GenericCodec[CampaignRow] |
Hello @travisbrown , I have one more question, probably a silly one, however, I couldn't find a good answer yet. For generics what is the difference amount these below categories category1: class Generic[+A] vs class Generic[A] category2: class Generic[-A] vs class Generic[A]) |
In the future can we make dynamic decoders and encoders which may fail in runtime if not successful Proposal,
May fail on run time if cannot parse to T |
@aukgit There's no reason you couldn't have a decoder that relied on runtime reflection to decode an arbitrary type (although you'd probably need an implicit |
Will you please kindly point me to that? |
Sorry, as I said I can't find it at the moment. IIRC it was something I posted in a Gist or Stack Overflow or somewhere like that, but searching for variations of "manifest classtag circe scala" doesn't turn it up. There's a similar example in this old blog post of mine. In any case I definitely don't recommend it, and especially if you're just getting started with Scala I'd recommend steering clear of runtime reflection for as long as you can. |
Hi @travisbrown Thank you for taking your valuable time and replying. Here is what I tried and having some issues. package shared.io.traits.jsonParse
import io.circe.generic.codec.DerivedAsObjectCodec
import io.circe.generic.decoding.DerivedDecoder
import shapeless.{Lazy, tag}
class JsonDecoders[T]
(implicit decode : Lazy[DerivedDecoder[T]], decodeCodec : DerivedAsObjectCodec[T])
{
import io.circe._
import io.circe.generic.semiauto._
def defaultDecoder() : Decoder[T] = deriveDecoder[T]
def codec : Codec.AsObject[T] = deriveCodec[T](decodeCodec)
}
object WApp extends App {
import shared.com.ortb.persistent.schema.Tables._
val re = new JsonDecoders[AuctionRow] // Works fine, gets compiled.
val re2 = new JsonDecoders[List[AuctionRow]] // fails to compiled
/**
Error:(30, 13) could not find Lazy implicit value of type io.circe.generic.decoding.DerivedDecoder[List[shared.com.ortb.persistent.schema.Tables.AuctionRow]]
val re2 = new JsonDecoders[List[AuctionRow]]
**/
} My question of how to create the Or, Probably using reflection.?? |
Things gets fixed if I import all these import io.circe.generic.semiauto._
import io.circe._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.generic.auto._
import io.circe.generic.encoding.DerivedAsObjectEncoder
import io.circe.generic.encoding._
import io.circe.{ Decoder, Encoder }, io.circe.generic.semiauto._
import io.circe.{Decoder, Encoder}
import io.circe.generic.semiauto._
import io.circe.syntax._
import io.circe.Decoder.AccumulatingResult
import io.circe.generic.JsonCodec
import io.circe.{Decoder, _}
import io.circe.generic.codec.DerivedAsObjectCodec
import io.circe.generic.decoding.DerivedDecoder
import io.circe.generic.semiauto.{deriveDecoder, _}
import shapeless.Lazy
import shared.com.ortb.implicits.implementations.CirceJsonSupport Which one to keep as organize import also fails to build again. |
|
For anyone who is going to use the generic version of decoders, codecs for T and List[T] Example Code : https://bit.ly/2RXr7gT package shared.io.traits.jsonParse
import io.circe.generic.auto._ // must to import.
import io.circe.generic.codec.DerivedAsObjectCodec
import io.circe.generic.decoding.DerivedDecoder
import io.circe.generic.encoding.DerivedAsObjectEncoder
import io.circe.generic.semiauto.{deriveDecoder, _}
import io.circe.{Decoder, Encoder, _}
import shapeless.Lazy
import shared.com.ortb.implicits.implementations.CirceJsonSupport
class JsonCirceEncoder[T]
(
implicit val decodeCodec : DerivedAsObjectCodec[T],
implicit val decoder : Lazy[DerivedDecoder[T]],
val encoder : Lazy[DerivedAsObjectEncoder[T]],
val decodeListCodec : DerivedAsObjectCodec[List[T]]){
implicit def defaultCodec : Codec.AsObject[T] = deriveCodec[T](decodeCodec)
implicit def defaultListCodec : Codec.AsObject[List[T]] =
deriveCodec[List[T]](decodeListCodec)
implicit def defaultDecoder : Decoder[T] = deriveDecoder[T]
implicit def defaultListDecoder : Decoder[List[T]] = deriveDecoder[List[T]]
implicit def defaultEncoder : Encoder[T] = deriveEncoder[T]
implicit def defaultListEncoder : Encoder[List[T]] = deriveEncoder[List[T]]
}
object ExampleApp extends App with CirceJsonSupport {
import shared.com.ortb.persistent.schema.Tables._
val re = new JsonCirceEncoder[AuctionRow]
} |
Hello @travisbrown,
How are you? Greetings for the day.
I have things set up correctly. Data comes properly. However, I am having issues with generic types. As I am completely new to scala, probably I am missing something. However, I have read in the StackOverflow articles that circle doesn't support conversion of Any, Object (which makes sense). However, 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) that can be a help.
Main Goal
Make circle JSON encode/decode on the abstract class level. Just like NewtonJson (https://www.newtonsoft.com/json)
Versions (Scala 2.13.1, Circle: 0.12.3)
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
Examples
Abstract API Sample, CircleJsonSupport integrated
Build fails
Build Success and works fine if the same code is written in the actual class
Build Success and works fine if casting happens properly
Implicts failed
Base Class
Concreate class Class
Also doesn't help
Case Class for CampaignRow (Slick Class)
Build errors faced during
The text was updated successfully, but these errors were encountered: