玩 - 通用Crud自定义Json [英] Play - Custom Json with Generic Crud

查看:244
本文介绍了玩 - 通用Crud自定义Json的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中有一个Crud控制器,它可以与JsonInception完美配合使用,但是会失败,只能使用自定义的json转换器。

请遵循给定的案例类:

  case类型有效性(id:Option [UUID],objectType:String,因为:DateTime,直到:DateTime,objectId:UUID,validityTargetId:UUID ,validityTargetType:String)

我有一个对象伴侣如下:

  object有效性扩展了CrudObject [有效性] {
隐式val读取= Json.reads [有效期]
隐式val写入= Json.writes [有效性]
}

其中我的CrudObject是具有给定代码的特征:

  trait CrudObject [T] {
val读取:读取[T]
val写入:写入[T]
}

因为我在Generic Crud中工作,所以这是必需的。如果没有这个,Play无法找到任何隐式转换器。



所以我的通用Crud控制器就是这样的:

  trait CrudController [T]扩展控制器{

def service:ServiceModule [T]
def companion:CrudObject [T]

def search ...
def insert ...

implicit def reads:Reads [T] = companion.reads
implicit def writes:Writes [T] = companion.writes

对于每个控制器,我有以下内容:

 对象ValidityController extends CrudController [有效性] {
覆盖def service:GenericServiceModule [有效期] = ServiceModule
覆盖def伴随:CrudObject [有效期] =有效性
}

好吧,正如我所说的,完美的是,我需要设计一个定制的json转换器。是的,我知道,这很简单,但有些事情正在发生,我不知道如何摆脱它。



现在我正在尝试执行以下操作:

 隐式val读取:读取[Validity] =(
(JsPath \id)。read [ (JsPath \objectType)。read [String]和
(JsPath \since)。read [Long] and
(JsPath \until ).read [Long] and
(JsPath \objectId)。read [String] and
(JsPath \validityTargetId)。read [String] and
(JsPath \\ \\validityTargetType)。read [String]
)(unlift(Validity.apply _))



 类型不匹配,预期:(​​NotInferedA)=>选项[NotInferedB],实际:(CrudObject [Nothing])=> CrudObject [Nothing] 

我相信这是发生的事情cuz CrudObject是一个特征,并且不适用和不适用。

无论如何,删除CrudObject给了我一个类似的错误:

 类型不匹配,预期:(​​NotInferedA)=> Option [NotInferedB],actual:(Option [UUID],String,DateTime,DateTime,UUID,UUID,String)=>有效性

但即使我能解决这个问题,我也无法想象没有CrudObject因为我的GenericCrud而生活。



任何想法?



PS:感谢@mz,他通过stackoverflow =给我一些帮助)



更新

我几乎用这种方法:

 隐式对象validityFormat extends格式[有效性] {
覆写高清写入(o:有效性):JsValue = {
Json.obj(
id - > JsString(o.id.getOrElse(null).toString),
objectType - > JsString(o.objectType),
因为 - > JsString(o.since.toString),
until - > JsString(o.since.toString),
objectId - > JsString(o.objectId.toString ),
validityTargetId - > JsString(o.validityTargetId.toString),
validityTargetType - > JsString(o.validityTargetType))
}

overrid (json:JsValue):JsResult [Validity] = {
JsSuccess(有效性(
(json \id)。as [Option [UUID]],
(json \objectType)。as [String],
(json \since)。as [DateTime],
(json \until)。as [DateTime],
(json \objectId)。as [UUID],
(json \validityTargetId)。as [UUID],
(json \validityTargetType)。as [String ])

}
}

使用这种方式,这与文档 Scala Combinators 不同,我没有得到以前的错误,这是好的,没有类型不匹配=)

现在我正在研究如何转换为UUID和DateTime。



UPDATE

我做了一个可行的例子,但我接受了@ mz答案,吃了比我的,但都工作得很好。最大的区别是,在我的方法中,我需要为DateTime和UUID提供一些自定义转换器,而@mz方法不适用于您!

 隐式对象UUIDFormatter extends Format [UUID] {
override def reads(json:JsValue):JsResult [UUID] = {
val uuid = json.validate [String]
JsSuccess (uUID.fromString(uuid.get))
}

覆写def write(o:UUID):JsValue = {
JsString(o.toString)
}
}

隐式对象DateTimeFormatter extends Format [DateTime] {
覆盖def reads(json:JsValue):JsResult [DateTime] = {
datetime = json。验证[Long]
JsSuccess(new DateTime(datetime.get))
}

覆盖def write(o:DateTime):JsValue = {
JsNumber(o .getMillis)
}
}

隐式对象validityFormat extends格式[有效性] {
覆盖高清写入(o:有效性):JsValue = {
JSON .obj(
id - > JsString(o.id.getOrElse(null).toString),
objectType - > JsString(o.objectType),
since - > JsNumber(o.since.getMillis),
until - > JsNumber(o.since.getMillis),
objectId - > JsString(o.objectId.toString),
validityTargetId - > JsString(o.validityTargetId.toString),
validityTargetType - > JsString(o.validityTargetType))
}

覆盖def reads(json:JsValue):JsResult [Validity] = {
JsSuccess(Validity(
(json \\ (id))。as [Option [UUID]],
(json \objectType)。as [String],
(json \since)。as [DateTime],
(json \until)。as [DateTime],
(json \objectId)。as [UUID],
(json \validityTargetId)。as [UUID],
(json \validityTargetType)。as [String])

}


解决方案

这里有几个问题,但它们都与泛型没有关系,因为您正在处理具体类型<$ c $首先,使用 Reads 组合子的最后一个参数应该是。

code>(Validity.apply _)。您只能使用 unlift 写入



第二,组合器中的类型必须映射到 Validity 类中的类型。

  implicit val reads:Reads [Validity] =(
(JsPath \id)。readNullable [UUID] and // readNullable reads to Option
(JsPath \objectType)。阅读[String]和
(JsPath \since)。read [DateTime] and
(JsPath \until)。read [DateTime] and
(JsPath \读取[UUID]和
(JsPath \validityTargetId)。read [UUID]和
(JsPath \validityTargetType)。read [String]
)( Validity.apply _)

读取已存在对于 UUID DateTime ,所以这应该可以。



<同样,写入[有效性] 看起来像这样:

 隐式val写入:写入[有效性] =(
(JsPath \id)。writeNu (JsPath \objectType)。write [String]和
(JsPath \since)。write [DateTime]和
(JsPath \写入[UUID]和
(JsPath \validityTargetId)。write [UUID]和
(写入) JsPath \validityTargetType)。write [String]
)(unlift(Validity.unapply))


I have a Crud Controller in my application which works perfectly with JsonInception, but fail with a custom json converter.

Follow the given case class:

case class Validity(id: Option[UUID], objectType: String, since: DateTime, until: DateTime, objectId: UUID, validityTargetId: UUID, validityTargetType: String)

I have an object companion as follow:

object Validity extends CrudObject[Validity] {
  implicit val reads = Json.reads[Validity]
  implicit val writes = Json.writes[Validity]
}

Where my CrudObject is a trait with the given code:

trait CrudObject[T] {
  val reads: Reads[T]
  val writes: Writes[T]
}

This is needed since I'm working in a Generic Crud. Without this, Play is unable to find any implicit converter.

So my Generic Crud Controller, is something like this:

trait CrudController[T] extends Controller {

  def service: ServiceModule[T]
  def companion: CrudObject[T]

  def search...
  def insert...

  implicit def reads: Reads[T] = companion.reads
  implicit def writes: Writes[T] = companion.writes

and for each controller, I have the follow:

object ValidityController extends CrudController[Validity] {
  override def service: GenericServiceModule[Validity] = ServiceModule
  override def companion: CrudObject[Validity] = Validity
}

Ok, with this design in mind, as I said, works perfectly, I need to design a custom json converter. Yes, I know, it's pretty simple, but something is happening and I don't know how to get rid of that.

Now I'm trying to do the following:

implicit val reads: Reads[Validity] = (
      (JsPath \ "id").read[String] and
      (JsPath \ "objectType").read[String] and
      (JsPath \ "since").read[Long] and
      (JsPath \ "until").read[Long] and
      (JsPath \ "objectId").read[String] and
      (JsPath \ "validityTargetId").read[String] and
      (JsPath \ "validityTargetType").read[String]
    )(unlift(Validity.apply _))

and it gives me:

Type mismatch, expected: (NotInferedA) => Option[NotInferedB], actual: (CrudObject[Nothing]) => CrudObject[Nothing]

I believe this is happen cuz CrudObject is a trait and does not have apply and unapply.

Anyway, removing CrudObject gives me a similar error:

Type mismatch, expected: (NotInferedA) => Option[NotInferedB], actual: (Option[UUID], String, DateTime, DateTime, UUID, UUID, String) => Validity

but even if I can solve this, I can't imagine living without CrudObject due my GenericCrud.

Any Thoughts?

PS: Thanks to @m-z who has been giving me some assist through stackoverflow =)

UPDATE

I'm almost there with this approach:

implicit object validityFormat extends Format[Validity] {
    override def writes(o: Validity): JsValue = {
      Json.obj(
        "id" -> JsString(o.id.getOrElse(null).toString),
        "objectType" -> JsString(o.objectType),
        "since" -> JsString(o.since.toString),
        "until" -> JsString(o.since.toString),
        "objectId" -> JsString(o.objectId.toString),
        "validityTargetId" -> JsString(o.validityTargetId.toString),
        "validityTargetType" -> JsString(o.validityTargetType))
    }

    override def reads(json: JsValue): JsResult[Validity] = {
      JsSuccess(Validity(
        (json \ "id").as[Option[UUID]],
        (json \ "objectType").as[String],
        (json \ "since").as[DateTime],
        (json \ "until").as[DateTime],
        (json \ "objectId").as[UUID],
        (json \ "validityTargetId").as[UUID],
        (json \ "validityTargetType").as[String])
      )
    }
  }

Using this way, which is different from documentation Scala Combinators, I don't get the previous error, which is good, no type mismatch =)

Now I'm working out on to figure out how to convert to UUID and DateTime.

UPDATE

I did an example that works, but I accepted the @m-z answer because there are less boilerplate than mine, but both worked fine. The big difference is, in my approach I needed to provide some custom converters for DateTime and for UUID, whereas @m-z approach you don't!

implicit object UUIDFormatter extends Format[UUID] {
    override def reads(json: JsValue): JsResult[UUID] = {
      val uuid = json.validate[String]
      JsSuccess(UUID.fromString(uuid.get))
    }

    override def writes(o: UUID): JsValue = {
      JsString(o.toString)
    }
  }

  implicit object DateTimeFormatter extends Format[DateTime] {
    override def reads(json: JsValue): JsResult[DateTime] = {
      val datetime = json.validate[Long]
      JsSuccess(new DateTime(datetime.get))
    }

    override def writes(o: DateTime): JsValue = {
      JsNumber(o.getMillis)
    }
  }

  implicit object validityFormat extends Format[Validity] {
    override def writes(o: Validity): JsValue = {
      Json.obj(
        "id" -> JsString(o.id.getOrElse(null).toString),
        "objectType" -> JsString(o.objectType),
        "since" -> JsNumber(o.since.getMillis),
        "until" -> JsNumber(o.since.getMillis),
        "objectId" -> JsString(o.objectId.toString),
        "validityTargetId" -> JsString(o.validityTargetId.toString),
        "validityTargetType" -> JsString(o.validityTargetType))
    }

    override def reads(json: JsValue): JsResult[Validity] = {
      JsSuccess(Validity(
        (json \ "id").as[Option[UUID]],
        (json \ "objectType").as[String],
        (json \ "since").as[DateTime],
        (json \ "until").as[DateTime],
        (json \ "objectId").as[UUID],
        (json \ "validityTargetId").as[UUID],
        (json \ "validityTargetType").as[String])
      )
    }

解决方案

There are a couple problems here, but neither of them are relevant to generics, because you're dealing with the concrete type Validity.

First, the last argument using Reads combinators should be (Validity.apply _). You would only use unlift with Writes.

Second, the types in the combinators must map to the types in your Validity class.

implicit val reads: Reads[Validity] = (
  (JsPath \ "id").readNullable[UUID] and    // readNullable reads to Option
  (JsPath \ "objectType").read[String] and
  (JsPath \ "since").read[DateTime] and
  (JsPath \ "until").read[DateTime] and
  (JsPath \ "objectId").read[UUID] and
  (JsPath \ "validityTargetId").read[UUID] and
  (JsPath \ "validityTargetType").read[String]
)(Validity.apply _)

Reads already exist for UUID and DateTime, so this should work okay.

Similarly, Writes[Validity] would look like this:

implicit val writes: Writes[Validity] = (
  (JsPath \ "id").writeNullable[UUID] and
  (JsPath \ "objectType").write[String] and
  (JsPath \ "since").write[DateTime] and
  (JsPath \ "until").write[DateTime] and
  (JsPath \ "objectId").write[UUID] and
  (JsPath \ "validityTargetId").write[UUID] and
  (JsPath \ "validityTargetType").write[String]
)(unlift(Validity.unapply))

这篇关于玩 - 通用Crud自定义Json的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆