繁体   English   中英

将值映射到json4s中的case类

[英]Mapping values to case class in json4s

说我有以下几点:

[ {
    "job_id": "1",
    "status": "running"
  },
  {
    "job_id": "0",
    "status": "finished"
  }]

我可以以某种方式对json4s执行以下操作:

case class Job(job_id: Int, status: JobStatus)

abstract class JobStatus

case class JobFinished extends JobStatus

case class JobRunning extends JobStatus

... some  magic is probably needed here

这样,提取第一个代码段将导致:

[ Job(1, JobRunning()), Job(0, JobFinished())]

我认为基于JSON创建scala case类的最佳方法是使用此站点,这增加了魔力,我通常使用此站点,您甚至可以更改分类的名称,因此在您的情况下,可以使用网站,然后管理班级之间的关系:

JSON至Scala

JSON粘贴

结果

您可以使用一个枚举,然后通过json4s-ext将EnumSerializer添加到您的formats 但是,您的枚举将被序列化为int(在您的情况下为0或1)。

除了我自己的答案外,您还可以使用EnumNameSerializer,它将序列化为您指定的枚举值(例如“运行”或“完成”)。

这是可能的,但是需要一些编码。 我将尝试以一些较小的步骤对其进行分解。

类型/型号的定义

// Types
case class Job(jobId: Int, status: JobStatus)
// Sealed trait to make match exhaustive in helper functions
sealed trait JobStatus
// use case object to not create uneeded instances, also case class without () no longer allowed
case object JobFinished extends JobStatus
case object JobRunning extends JobStatus

魔术”

所需进口

import org.json4s._
import org.json4s.native.Serialization
import org.json4s.native.Serialization.{read, write}

辅助功能

// helper functions, could be improved by having a mapping
implicit def stringToJobStatus(in: String) : JobStatus = in match {
  case "running" => JobRunning
  case "finished" => JobFinished
}
implicit def jobStatusToString(jobStatus: JobStatus) : String = jobStatus match {
  case  JobRunning => "running"
  case  JobFinished => "finished"
}

自定义序列化器

// here is the "magic" a custom serializer
class JobSerializer extends CustomSerializer[Job](format => (
         // unmarshal Function
         {
           case JObject( JField("job_id", JString(jobId)) :: JField("status", JString(status)) :: Nil ) => {
             new Job(jobId.toInt, status)
           }
         },
         // masrshal Function
         {
           case Job(jobId, status) => JObject(
         JField("job_id", JString(jobId.toString)) :: 
         JField("status", JString(status)) :: Nil)
         }
))

使序列化器成为可能

// Implicit formats for serialization and deserialization
implicit val formats = Serialization.formats(NoTypeHints) + new JobSerializer

REPL中的示例

val data = """
[
 {
   "job_id": "1",
   "status": "running"
 },
 {
   "job_id": "0",
   "status": "finished"
 }
]
"""

read[List[Job]](data)

res3: List[Job] = List(Job(1,JobRunning), Job(0,JobFinished))

尽管@Andres Neumann的回答相当不错,但它确实需要重新实现整个Job类的序列化(可能比示例中笨拙的Job类大很多),而实际上唯一需要序列化的是状态。 根据@Andreas的回答,所需的实际代码会短一些,并且不需要手动序列化Job中的每个字段。

// here is the "magic" a custom serializer
class JobStatusSerializer extends CustomSerializer[JobStatus](format => (
  // unmarshal Function
  {
    case JString(status) => {
      // helper functions, could be improved by having a mapping
      def stringToJobStatus(in: String): JobStatus = in match {
        case "running" => JobRunning
        case "finished" => JobFinished
      }

      stringToJobStatus(status)
    }
  },
  // marshal Function
  {

    case status: JobStatus => {
      def jobStatusToString(jobStatus: JobStatus): String = jobStatus match {
        case JobRunning => "running"
        case JobFinished => "finished"

      }

      JString(jobStatusToString(status))
    }
  }
  )
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM