Scala,spray-json:通用枚举 json 格式

     2023-02-16     108

关键词:

【中文标题】Scala,spray-json:通用枚举 json 格式【英文标题】:Scala, spray-json: universal enumeration json formatting 【发布时间】:2018-03-18 15:22:36 【问题描述】:

我有这样的模型:两个枚举和一个案例类,其中包含这些枚举类型的两个字段:

// see later, why objects are implicit
implicit object Fruits extends Enumeration 
  val Apple = Value("apple")
  val Orange = Value("orange")


implicit object Vegetables extends Enumeration 
  val Potato = Value("potato")
  val Cucumber = Value("cucumber")
  val Tomato = Value("tomato")


type Fruit = Fruits.Value
type Vegetable = Vegetables.Value

case class Pair(fruit: Fruit, vegetable: Vegetable)

我想使用 spray-json 向/从 Pairs 解析/生成 JSON。我不想为水果和蔬菜单独声明JsonFormats。所以,我想做这样的事情:

import spray.json._
import spray.json.DefaultJsonProtocol._

// enum is implicit here, that's why we needed implicit objects
implicit def enumFormat[A <: Enumeration](implicit enum: A): RootJsonFormat[enum.Value] =
  new RootJsonFormat[enum.Value] 
    def read(value: JsValue): enum.Value = value match 
      case JsString(s) =>
        enum.withName(s)
      case x =>
        deserializationError("Expected JsString, but got " + x)
    

    def write(obj: enum.Value) = JsString(obj.toString)
  

// compilation error: couldn't find implicits for JF[Fruit] and JF[Vegetable]
implicit val pairFormat = jsonFormat2(Pair)

// expected value:
// spray.json.JsValue = "fruit":"apple","vegetable":"potato"
// but actually doesn't even compile
Pair(Fruits.Apple, Vegetables.Potato).toJson

遗憾的是,enumFormat 不会为 jsonFormat2 生成隐式值。如果我在 pairFormat 之前手动为水果和蔬菜格式编写两个隐式声明,那么 json marshalling 就可以了:

implicit val fruitFormat: RootJsonFormat[Fruit] = enumFormat(Fruits)
implicit val vegetableFormat: RootJsonFormat[Vegetable] = enumFormat(Vegetables)

implicit val pairFormat = jsonFormat2(Pair)

// "fruit":"apple","vegetable":"potato", as expected
Pair(Fruits.Apple, Vegetables.Potato).toJson

那么,两个问题:

    如何摆脱这些fruitFormatvegetableFormat 声明?

    理想情况下,最好不要将枚举对象设为隐式,同时保持enumFormat 函数的通用性。有没有办法做到这一点?也许,使用scala.reflect 包或类似的东西。

【问题讨论】:

【参考方案1】:

您只需将enum.Value 替换为A#Value

查看spray-json #200,您可以找到定义明确的隐式enumFormat 的示例,稍作修改以利用隐式enu 检索:

implicit def enumFormat[T <: Enumeration](implicit enu: T): RootJsonFormat[T#Value] =
  new RootJsonFormat[T#Value] 
    def write(obj: T#Value): JsValue = JsString(obj.toString)
    def read(json: JsValue): T#Value = 
      json match 
        case JsString(txt) => enu.withName(txt)
        case somethingElse => throw DeserializationException(s"Expected a value from enum $enu instead of $somethingElse")
      
    

【讨论】:

【参考方案2】:

你不能,Scala 不允许隐式链接,因为它会导致组合爆炸,使编译器太慢。

见https://docs.scala-lang.org/tutorials/FAQ/chaining-implicits.html

Scala 不允许发生两次这样的隐式转换,因此不能使用隐式 A 到 B 和另一个隐式 B 到 C 从 A 到 C。

您必须为要使用的每个 T 显式生成一个 JsonFormat[T]

【讨论】:

如何使用 AKKA-HTTP、spray-json、oauth2 和 slick 优化 scala REST api?

】如何使用AKKA-HTTP、spray-json、oauth2和slick优化scalaRESTapi?【英文标题】:HowtooptimizescalaRESTapiusingAKKA-HTTP,spray-json,oauth2andslick?【发布时间】:2017-01-3111:11:31【问题描述】:我使用AKKA-HTTP、spray-json和Slick在scala中创建了一个RESTapi。对... 查看详情

如何在 Scala 3 枚举上进行模式匹配

...如:objmatchcasee:Enumeration=>...caseother=>...在Scala3中没有通用接口,如 查看详情

Scala 类型类模式和泛型方法

...述】:我正在尝试编写一个通用提取器,用于使用spray和spray-json解析jsonPOST正文。但是,我很难让它与多个模型一起使用。这是服务对象中的case语句:importMyJsonProtocol._...defreceive=casePost(R 查看详情

spray-json

spray-json是一个轻量级的,简介的和高效的使用Scala实现的json它拥有以下特征:一个简单不可变的模型的json语言元素一个高效的json解析器可选择既紧凑又漂亮的json到string的打印(格式化输出)基于类的自定义对象的(反)序列化(没... 查看详情

scala枚举:enumeration概述

SparkScala枚举*Java中的那套枚举并不能直接使用到Scala中*Scala中的枚举使用轻量级Enumeration进行实现*Scala中的枚举其实是一个伴随对象*Scala中的枚举没有方法重写功能*Scala中的枚举其实都是Enumeration.Value这个对象和Java和C++不同,Scala... 查看详情

Scala 3枚举方法覆盖

】Scala3枚举方法覆盖【英文标题】:Scala3enummethodoverride【发布时间】:2021-07-1815:48:22【问题描述】:有没有办法像在Java中一样覆盖Scala3枚举中的方法?publicenumTestONE@Overridepublicintcalc()return1;,TWO@Overridepublicintcalc()return2;;publicabstracti... 查看详情

scala.的enumeration枚举示例(转)

简介 在scala中没有枚举类型,但在标准类库中提供了Enumeration类来产出枚举。扩展Enumeration类后,调用value方法类初始化枚举中的可能值。 内部类value实际上是一个抽象类,真正创建的是val。因为实际上是Val,所以可以为Va... 查看详情

在scala 3中获取枚举的名称?

】在scala3中获取枚举的名称?【英文标题】:Getnameoftheenuminscala3?【发布时间】:2022-01-1216:27:51【问题描述】:Java枚举有name()方法,但scala3没有。如何在scala3中获取枚举的名称?enumColor:caseRed,Green,Blue【问题讨论】:【参考方案1... 查看详情

spark的枚举类型实例!scala的枚举。

Spark的枚举类型实例!scala的枚举。Enumeration定义:[deploy] SparkSubmitAction  {  = Value  = Value}Enumeration使用:appArgs. {  SparkSubmitAction.=> ( 查看详情

scala自定义实现枚举

参考技术Ajava使用枚举类型,所以不用scala但是没有枚举类型,如果项目中需要用到枚举或者类似枚举。scala就需要使用其他方式来实现。基本来说有三种第一种,就是在项目中单独写一个java文件,在文件中声明枚举类型,然后... 查看详情

如何在 SORM 中添加 Scala 枚举?

】如何在SORM中添加Scala枚举?【英文标题】:HowtoaddScalaEnumerationinSORM?【发布时间】:2014-08-2813:38:55【问题描述】:如何在SORM中添加枚举?我有这个枚举:objectRoutineTypeextendsEnumerationvalTimeRoutine,SetRoutine=Value并在DB对象中添加实体... 查看详情

Scala:继承的枚举对象不满足父特征

】Scala:继承的枚举对象不满足父特征【英文标题】:Scala:Inheritedenumobjectdoesn\'tsatisfyparenttrait【发布时间】:2021-04-2017:25:30【问题描述】:我正在尝试在方法中使用Enumeration对象。枚举对象从特征扩展而来,该方法将特征作为参... 查看详情

python枚举是不是有等效的Scala?

】python枚举是不是有等效的Scala?【英文标题】:IsthereaScalaequivalentforthepythonenumerate?python枚举是否有等效的Scala?【发布时间】:2011-09-2302:36:24【问题描述】:我想要方便fori,lineinenumerate(open(sys.argv[1])):printi,line在Scala中执行以下操... 查看详情

Scala模式匹配Java枚举值

】Scala模式匹配Java枚举值【英文标题】:ScalapatternmatchingJavaenumvalue【发布时间】:2014-04-1011:30:27【问题描述】:我有我的java枚举,例如:FOO("foo")、BAR("bar")...我有一个getValue()方法来返回枚举的值"foo"和"... 查看详情

scala定义复杂枚举(代码片段)

通常我们需要枚举参数不止两个,Scala提供的枚举类最多定义两个参数:id:Int与name:String。不能满足我们通常要求。1objectBaseEntryEnumextendsEnumeration2typeBaseEntryEnum=Value3//item_base类别4valITEM_TYPE_PURCHASE_CENTER=Value(31,"采购中心")5valITEM_TYP 查看详情

java示例代码_从Java传递Scala枚举

java示例代码_从Java传递Scala枚举 查看详情

scala反射获取枚举值的类

】scala反射获取枚举值的类【英文标题】:scalareflectiongetclassofenumarationvalue【发布时间】:2017-11-0712:22:40【问题描述】:假设我们有classUser(valname:String,valrole:UserRole.Value)classUserRoleextendsEnumerationvalAdmin,User=Valuevalu=newUser("root",Us 查看详情

Circe 和 Scala 的枚举类型

】Circe和Scala的枚举类型【英文标题】:CirceandScala\'sEnumerationtype【发布时间】:2017-06-2310:44:36【问题描述】:我正试图将我的头包裹在Circe周围。所以,这是我得到的模型:objectGenderextendsEnumerationtypeGender=ValuevalMale,Female,Unisex,Unknow... 查看详情