【问题标题】:ScalaJson: Parsing optional values (with default) without Option [duplicate]ScalaJson:解析可选值(默认)没有选项[重复]
【发布时间】:2018-02-26 12:49:13
【问题描述】:

我想解析Json 文件以读取可能可选提供的值。如果未提供它们,我有默认值可供选择。

显然在这种情况下,最终结果是我肯定会有一个值:要么是从Json 读取的值,要么是默认值。但是根据我目前对ScalaJson 的了解(如果我错了请纠正我),我仍然必须使用Option[T] 来保存它(因为它可能无法直接在Json 文件中使用) .换句话说,我相信虽然我可以提供一个默认值,但它仍然必须包含在Option[T]

有没有一种方法可以读取 可选 值(使用 default)而无需将其 包装Option[T] 中?我想提前通知一下,我不需要(在可预见的将来)将我的数据写入(serialize)到Json,我只需要读取它(deserializeJson.


进一步阐述我的问题:-

我正在使用automatic-conversion using case classes,因此不必将这个case class 与给定的reads 一起使用converter

case class MyCaseClass(optString: Option[String] = Some("None"))
implicit val reads = Json.reads[MyCaseClass]

我想用这个case class

case class MyCaseClass(optStringWithDefault: String = "None")

如果给定相同的Json 源,是否可以为此case class 编写read converter?或者,是否有更好的设计选择可以完全克服这个问题?


我来了

  • Scala 2.11.11
  • PlayFramework 2.6

【问题讨论】:

标签: scala playframework play-json


【解决方案1】:

如果你使用 SBT,你可以在你的项目中包含 spray-json

libraryDependencies += "io.spray" %%  "spray-json" % "1.3.3"

定义案例类

case class MyCaseClass(optString: String = "None")

定义 json 转换的协议。

import spray.json._
object MyProtocol extends DefaultJsonProtocol {
    implicit object MyCaseClassFormat extends RootJsonFormat[MyCaseClass] {
      def write(obj: MyCaseClass): JsValue = JsObject(
        "optString" -> JsString(obj.optString)
      )
      def read(json: JsValue): MyCaseClass = {
        json.asJsObject.getFields("optString") match {
          case Seq(JsString(optString)) => MyCaseClass(optString.asInstanceOf[String])
          case _ => MyCaseClass()
        }
      }
    }
  }

导入协议

import MyProtocol._

场景一#

import spray.json._
val jsonStringOne: String = """{"optString": "testData"}"""
val resultOne = jsonStringOne.parseJson.convertTo[MyCaseClass]
Output: MyCaseClass(testData)

场景2#

import spray.json._
val jsonStringTwo: String = """{"otherString": "tempData"}"""
val resultTwo = jsonStringTwo.parseJson.convertTo[MyCaseClass]
Output: MyCaseClass(None)

参考链接:https://github.com/spray/spray-json

【讨论】:

    【解决方案2】:

    使用jsoniter-scala,它内置支持案例类字段的默认值。

    添加库依赖:

    libraryDependencies ++= Seq(
      "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "0.29.2" % Compile, 
      "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "0.29.2" % Provided // required only in compile-time
    )
    

    为您的根类型生成编解码器,并使用它来解析具有默认值的案例类:

    import com.github.plokhotnyuk.jsoniter_scala.macros._
    import com.github.plokhotnyuk.jsoniter_scala.core._
    
    case class Device(id: Int = 1, model: String = "iPhone X")
    
    case class User(name: String = "Joe", devices: Seq[Device] = Seq(Device()))
    
    implicit val codec: JsonValueCodec[User] = JsonCodecMaker.make[User](CodecMakerConfig())
    
    val user = readFromArray("{}".getBytes)
    
    require(user == User())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-05
      • 1970-01-01
      • 2018-05-06
      • 2014-07-26
      • 2021-02-20
      • 2011-04-22
      • 2018-05-06
      • 1970-01-01
      相关资源
      最近更新 更多