问题描述
在我的应用程序中有一个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 ])
)
}
}
使用这种方式,这与文档不同,我没有得到以前的错误,这是好的,没有类型不匹配=)
现在我正在研究如何转换为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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!