简体   繁体   English

播放/ Scala JSON格式

[英]Play / Scala JSON Format for Either

I have a value class that accepts an Either , which I would like to generate a Play for Scala v2.5.6 JSON Format for: 我有一个接受Either的值类,我想生成一个Play for Scala v2.5.6 JSON Format

import org.joda.time.{DateTime, Duration}

case class When(when: Either[DateTime, Duration]) extends AnyVal

I think I have the writes method figured out; 我觉得我有writes方法想通了; the problems I am having are with the reads method. 我遇到的问题是reads方法。 I've attempted two approaches, both failed for different reasons. 我试过两种方法,都因为不同的原因而失败了。

Attempt #1, showing both the reads and writes methods: 尝试#1,示出了两个readswrites的方法:

import play.api.libs.json._
import play.api.libs.json.Json.obj

object When {    
  def apply(dateTime: DateTime): When = When(Left(dateTime))

  def apply(duration: Duration): When = When(Right(duration))

  implicit val whenFormat = new Format[When] {
    def reads(json: JsValue): JsResult[When] = {
      val reads = (__ \ "dateTime").read[Long] { (millis: Long) =>
        When(Left(new DateTime(millis)))
      } | (__ \ "duration").read[Long] { (millis: Long) =>
        When(Right(new Duration(millis)))
      }
      reads.reads(json)
    }

    def writes(o: When): JsValue = obj(
      o.when.fold(
        duration => "duration" -> duration.getMillis,
        dateTime => "dateTime" -> dateTime.getMillis
      )
    )
  }
}

The error messages are: 错误消息是:

overloaded method value read with alternatives:
[error]   (t: Long)play.api.libs.json.Reads[Long] <and>
[error]   (implicit r: play.api.libs.json.Reads[Long])play.api.libs.json.Reads[Long]
[error]  cannot be applied to (Long => When)
[error]       val reads = (__ \ "dateTime").read[Long] { (millis: Long) =>

[error] overloaded method value read with alternatives:
[error]   (t: Long)play.api.libs.json.Reads[Long] <and>
[error]   (implicit r: play.api.libs.json.Reads[Long])play.api.libs.json.Reads[Long]
[error]  cannot be applied to (Long => When)
[error]       } | (__ \ "duration").read[Long] { (millis: Long) =>

Attempt #2, just showing the reads method: 尝试#2,只显示reads方法:

def reads(json: JsValue): JsResult[When] =
  JsSuccess(
    When(Left(new DateTime((__ \ "dateTime").read[Long]))) ||
    When(Right(new Duration((__ \ "duration").read[Long])))
  )

The error message is: 错误消息是:

value || is not a member of When
[error]  Note: implicit value whenFormat is not applicable here because it comes after the application point and it lacks an explicit result type
[error] Error occurred in an application involving default arguments.

I'd just like something that works, and I don't care what approach is used (even one I did not show), so long as it is maintainable and efficient. 我只是喜欢有用的东西,我不关心使用什么方法(即使是我没有展示的方法),只要它是可维护和有效的。 It would also be helpful to know what was wrong with each of these approaches. 了解每种方法的错误也会有所帮助。

Here is working example of how to do this: 以下是如何执行此操作的工作示例:

import org.joda.time.{DateTime, Duration}
import play.api.libs.functional.syntax._
import play.api.libs.json.Reads._
import play.api.libs.json._

object When {
  def apply(dateTime: DateTime): When = When(Left(dateTime))

  def apply(duration: Duration): When = When(Right(duration))

  val reads: Reads[When] = 
    (__ \ "dateTime").read[Long].map(millis => When(Left(new DateTime(millis)))) |
    (__ \ "duration").read[Long].map(millis => When(Right(new Duration(millis))))

  val writes: Writes[When] = new Writes[When] {
    override def writes(o: When): JsValue = Json.obj(
      o.when.fold(
        duration => "duration" -> duration.getMillis,
        dateTime => "dateTime" -> dateTime.getMillis
      )
    )
  }

  implicit val format = Format(reads, writes)
}

basically you should map the reads 基本上你应该映射读数

(__ \ "dateTime").read[Long]

gives you Reads[Long] , then you can map result to When . 给你Reads[Long] ,然后你可以把结果映射到When You were just passing parameter. 你只是传递参数。 This parameter could be a Long , to just ignore what is read and return that value, or implicit reads for long that you probably don't want to change and should let it stay implicit. 这个参数可以是Long ,只是忽略读取的内容并返回该值,或者长时间implicit读取,你可能不想改变它应该让它保持隐含。

So then in similar way you can create another reads for duration and combine them with alternative ( | ) and done, you have reads. 那么以类似的方式你可以创建另一个读取持续时间并将它们与替代( | )组合完成,你有读取。

Your second approach makes no sense. 你的第二种方法毫无意义。 Either use reads and compose them or just manually check if something is there and if not return a different result, but it is not worth doing this, just go with default approach. 要么使用读取和组合它们,要么只是手动检查是否有东西,如果没有返回不同的结果,但不值得这样做,只需采用默认方法。

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

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