簡體   English   中英

如何在Scala的隱式Json`reads'中使用特定的apply方法

[英]How to use specific apply method in implicit Json `reads` from Scala

我有一個在其構造函數中采用一些可選Enumeration類型的類:

case class GPMedia(id: Option[GPID], created: Option[DateTime], active: Option[Boolean], data: Array[Byte], mimeType: Option[GPMediaType.Type], encoding: Option[GPEncoder.Codec], compression: Option[GPCompressor.Type])

我一直在努力創建一個有效的implicit Json reads方法。 我一直以諸如以下的錯誤結束:

[error] /Users/zbeckman/Projects/Glimpulse/Server/project/glimpulse-server/app/utility/GPMedia.scala:57: overloaded method value apply with alternatives:
etc...

我想做的是轉換入站Json字符串,將它們轉換為正確的Option實例(例如,Json中的MIME類型“ image / png”將轉換為Option(GPMediaType(v)) 。 GPMediaType構造函數將映射該字符串,並返回正確的值(其中一個是GPMediaType.Unknown )。

這是我到目前為止處理的implicit reads ,是在GPMedia類的伴隨對象上實現的...

case object GPMedia extends GPRequestLogging {
    implicit val reads: Reads[GPMedia] = (
        (__ \ "id").readNullable[GPID] and
            (__ \ "created").readNullable[DateTime] and
            (__ \ "active").readNullable[Boolean] and
            (__ \ "data").read[Array[Byte]] and
            (__ \ "mimeType").readNullable[String].map(v => Option(GPMediaType(v))) and
            (__ \ "encoding").readNullable[String].map(v => Option(GPEncoder(v.get))) and
            (__ \ "compression").readNullable[String].map(v => Option(GPCompressor(v.get)))
        )(GPMedia.apply _)
}

這可行,但是當我嘗試添加其他apply()方法時,一切都變得很麻煩。 如何在Json reads實現中應用特定的 apply方法? 例如,當我添加以下apply方法時:

def apply(data: Array[Byte]) = new GPMedia(None, None, None, data, None, None, None)

我最終得到:

[error] /Users/zbeckman/Projects/Glimpulse/Server/project/glimpulse-server/app/utility/GPMedia.scala:60: ambiguous reference to overloaded definition,
[error] both method apply in object GPMedia of type (id: Option[models.GPID], created: Option[org.joda.time.DateTime], active: Option[Boolean], data: Array[Byte], mimeType: Option[utility.GPMediaType.Type], encoding: Option[utility.GPEncoder.Codec], compression: Option[utility.GPCompressor.Type])utility.GPMedia
[error] and  method apply in object GPMedia of type (data: Array[Byte])utility.GPMedia
[error] match expected type ?
[error]         )(GPMedia.apply _)

我嘗試了幾種不同的方法,例如(GPMedia.apply(...))但似乎無法正確獲取參數。

我是整個Json隱式讀取器/寫入器和Json解碼語法的新手。 顯然我在這里缺少什么...

編輯

關於我嘗試調用特定apply方法的另一個示例:

implicit val reads: Reads[GPMedia] = (
    (__ \ "id").readNullable[GPID] and
        (__ \ "created").readNullable[DateTime] and
        (__ \ "active").readNullable[Boolean] and
        (__ \ "data").read[Array[Byte]] and
        (__ \ "mimeType").readNullable[String].map(v => Option(GPMediaType(v))) and
        (__ \ "encoding").readNullable[String].map(v => Option(GPEncoder(v.get))) and
        (__ \ "compression").readNullable[String].map(v => Option(GPCompressor(v.get)))
    )(v => GPMedia.apply(v.id, v.created, v.active, v.data, v.mimeType, v.encoding, v.compression))

結果是:

[error] /Users/zbeckman/Projects/Glimpulse/Server/project/glimpulse-server/app/utility/GPMedia.scala:60: type mismatch;
[error]  found   : utility.GPMedia
[error]  required: (Option[models.GPID], Option[org.joda.time.DateTime], Option[Boolean], Array[Byte], Option[utility.GPMediaType.Value], Option[utility.GPEncoder.Value], Option[utility.GPCompressor.Type])
[error]     (which expands to)  (Option[models.GPID], Option[org.joda.time.DateTime], Option[Boolean], Array[Byte], Option[utility.GPMediaType.Value], Option[utility.GPEncoder.Value], Option[utility.GPCompressor.Value])
[error]         )(v => GPMedia.apply(v.id, v.created, v.active, v.data, v.mimeType, v.encoding, v.compression))
[error]                             ^

有可能的。

但是您需要using _: ParameterType來指定重載apply方法所需的所有using _: ParameterType就像我在下面所做的那樣,它將起作用。

implicit val reads: Reads[GPMedia] = (
    (__ \ "id").readNullable[GPID] and
      (__ \ "created").readNullable[DateTime] and
      (__ \ "active").readNullable[Boolean] and
      (__ \ "data").read[Array[Byte]] and
      (__ \ "mimeType").readNullable[String].map(v => Option(GPMediaType(v))) and
      (__ \ "encoding").readNullable[String].map(v => Option(GPEncoder(v.get))) and
      (__ \ "compression").readNullable[String].map(v => Option(GPCompressor(v.get)))
    ) (
    v => GPMedia.apply(
      _: GPID,
      _: DateTime, 
      _: Boolean,
      _: Array[Byte],
      _: Option[GPMediaType],
      _: Option[GPEncoder],
      _: Option[GPCompressor]
    )
  )

這是不可能的。 編譯器不知道使用哪種apply方法。 這只是使用重載方法的警告之一。 像“ nice”這樣的唯一方法是重命名方法,或使用不同的名稱對重載的apply方法進行別名並使用它們。


您的第二次嘗試不起作用,因為編譯器期望函數的簽名類似於apply ,例如:

(Option[GPID], Option[DateTime], Option[Boolean], Array[Byte], Option[String], Option[String], Option[String]) => GPMedia

但是您正在嘗試使用:

GPMedia => GPMedia

這行不通,因為我們還沒有GPMedia對象,只有元組字段。 它看起來更像:

implicit val reads: Reads[GPMedia] = (
    (__ \ "id").readNullable[GPID] and
    (__ \ "created").readNullable[DateTime] and
    (__ \ "active").readNullable[Boolean] and
    (__ \ "data").read[Array[Byte]] and
    (__ \ "mimeType").readNullable[String].map(v => Option(GPMediaType(v))) and
    (__ \ "encoding").readNullable[String].map(v => Option(GPEncoder(v.get))) and
    (__ \ "compression").readNullable[String].map(v => Option(GPCompressor(v.get)))
).tupled.map(v => GPMedia.apply(v._1, v._2, v._3, v._4, v._5, v._6, v._7))

哪個不好看。 通常,我們可以使它看起來像這樣更好:

implicit val reads: Reads[GPMedia] = (
    (__ \ "id").readNullable[GPID] and
    (__ \ "created").readNullable[DateTime] and
    (__ \ "active").readNullable[Boolean] and
    (__ \ "data").read[Array[Byte]] and
    (__ \ "mimeType").readNullable[String].map(v => Option(GPMediaType(v))) and
    (__ \ "encoding").readNullable[String].map(v => Option(GPEncoder(v.get))) and
    (__ \ "compression").readNullable[String].map(v => Option(GPCompressor(v.get)))
).tupled.map(v => GPMedia.apply _ tupled v)

除了最終會遇到與開始時相同的問題外,因為編譯器將無法選擇正確的apply方法。 因此,您實際上別無選擇,只能重命名或使其變得丑陋。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM