首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scala Circe推论类

Scala Circe推论类
EN

Stack Overflow用户
提问于 2020-09-06 13:57:51
回答 2查看 171关注 0票数 1

我在消耗来自websocket的信息。它们有两种形式之一:

{"typ": "subscription", "channel": "BTC-USD"}

{"typ": "ticker", "price": 10213.42}

所以我有三个案例类和Circe的解码器一起使用:

代码语言:javascript
复制
case class GenericMessage(typ: String)

case class SubscriptionMessage(channel: String)

case class TickerMessage(price: Double) 

我怎样才能让Circe知道消息的类型,而不嵌套大量的解码尝试?

代码语言:javascript
复制
val message: String = ??? // From websocket
decode[GenericMessage](message) match {
    case Left(e) => ??? // Handle error
    case Right(decoded) => decoded.typ match {
        case "subscription" => decode[SubscriptionMessage](message) match {
            case Left(e) => ??? // Handle error
            case Right(subscriptionMessage) => ??? // Handle subscription message
         }
        case "ticker" =>  decode[TickerMessage](message) match {
            case Left(e) => ??? // Handle error
            case Right(tickerMessage) => ??? // Handle ticker message
         }
        case other => ??? // Handle unrecognized message
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-09-06 16:48:53

多亏了@LuisMiguelMejiaSuarez

我使用做了以下解决方案

代码语言:javascript
复制
sealed trait WebSocketMessage
final case class Subscriptions(typ: String, channel: String) extends WebSocketMessage
final case class Ticker(typ: String, price: Double) extends WebSocketMessage

implicit val config: Configuration = Configuration.default
  .withDiscriminator("type") // Tell circe that the 'type' attribute specifies which case class to decode to
  .copy(transformConstructorNames = _.toLowerCase) // Map 'ticker' string to 'Ticker' class name. Could also pass a more complex mapping function here to use arbitrary class names
  .copy(transformMemberNames = {
      case "typ" => "type" // The word 'type' is a reserved Scala, so class members are renamed to'typ' instead
      case other => Configuration.snakeCaseTransformation(other) // Tell circe to map product_ids field to productIds class member, for example.
  })
票数 1
EN

Stack Overflow用户

发布于 2020-09-06 15:02:57

您可以尝试一下我的Circe ADT扩展:https://github.com/abdolence/circe-tagged-adt-codec

因此,就你的情况而言,应该是:

代码语言:javascript
复制
sealed trait Message

object Message {

  @JsonAdt("ticker")
  case class Ticker(price : BigDecimal) extends Message

  @JsonAdt("subscription")
  case class Subscription(channel: Channel) extends Message


implicit val encoder : Encoder[Message] = JsonTaggedAdtCodec.createEncoder[Message]("typ")

implicit val decoder : Decoder[Message] = JsonTaggedAdtCodec.createDecoder[Message]("typ")
}

PS。由于浮点舍入问题,我不建议在货币/价格类型中使用Double

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63764935

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档