2013-10-24 111 views
2

型號:淘金,自定義JSON格式映射

case class DateValue(year: Option[Int] = None, month: Option[Int] = None) 

基於淘金者解碼器:

implicit val dateValueDecode = casecodec2(DateValue.apply, DateValue.unapply)("year", "month") 

這使得解析這樣的格式:

{ 
    "year": "2013", 
    "month": "10" 
} 

現在我想簡化JSON格式和使用

"2013/10" 

取而代之,但保留我的模型不變。如何用Argonaut完成這件事?

回答

2

以下是袖口,但它應該工作。請注意,我假設你只是想在當值是空分隔兩側空字符串,而我沒有驗證該月值是1到12之間

import argonaut._, Argonaut._ 
import scalaz._, Scalaz._ 

case class DateValue(year: Option[Int] = None, month: Option[Int] = None) 

object YearMonth { 
    def unapplySeq(s: String) = 
    """((?:\d\d\d\d)?)/((?:\d?\d)?)""".r.unapplySeq(s).map { 
     case List("", "") => List(None, None) 
     case List(y, "") => List(Some(y.toInt), None) 
     case List("", m) => List(None, Some(m.toInt)) 
     case List(y, m) => List(Some(y.toInt), Some(m.toInt)) 
    } 
} 

implicit val DateValueCodecJson: CodecJson[DateValue] = CodecJson(
    { case DateValue(year, month) => jString(~year + "/" + ~month) }, 
    c => c.as[String].flatMap { 
    case YearMonth(y, m) => DecodeResult.ok(DateValue(y, m)) 
    case _ => DecodeResult.fail("Not a valid date value!", c.history) 
    } 
) 

然後:

val there = Parse.decodeValidation[DateValue](""""2013/12"""") 
val back = there.map(DateValueCodecJson.encode) 

這給了我們:

scala> println(there) 
Success(DateValue(Some(2013),Some(12))) 

scala> println(back) 
Success("2013/12") 

正如預期的那樣。

訣竅是提供您自己的編碼和解碼功能CodecJson.apply。編碼函數非常簡單 - 它只需要一些編碼類型並返回Json值。解碼方法稍微複雜一點,因爲它需要一個HCursor並返回一個DecodeResult,但這些也很容易處理。

+0

正是我在找的東西。謝謝你,特拉維斯。 '〜'操作符對我來說也是一個很棒的發現。 – Tvaroh