scala play 2.1.1 json功能语法将数据映射到不同的格式

时间:2021-06-13 22:04:48

I'm trying to write a custom json serializer using the functional syntax and I can't seem to find the right way to solve this particular problem. I have a couple of joda DateTime objects that I want to write in a specific format for the UI consuming it. Can anyone show me where I've gone wrong?

我正在尝试使用函数语法编写自定义json序列化程序,我似乎无法找到解决此特定问题的正确方法。我有几个joda DateTime对象,我想以特定的格式编写用于使用它的UI。有谁能告诉我哪里出错了?

Here is the case class I am dealing with at the moment, nothing special going on.

以下是我正在处理的案例类,没有什么特别的。

case class Banner(
  id: Int = 0,
  ownerId: Int = 0,
  licenseeId: Option[Int] = None,
  statusColor: Option[String] = None,
  content: Option[String] = None,
  displayStart: DateTime = new DateTime(),
  displayEnd: DateTime = new DateTime(),
  created: DateTime = new DateTime(),
  updated: DateTime = new DateTime()
)

These are my imports for the serializer object.

这些是我对序列化程序对象的导入。

import play.api.libs.json._
import play.api.libs.functional.syntax._
import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat

First off, the joda DateTime converts to a long just fine implicitly so the macro expander works great if that's all I wanted.

首先,joda DateTime会隐式转换为long,因此宏扩展器可以很好地工作,如果这就是我想要的。

object MySerializers {
  implicit val writesBanner = Json.writes[Banner]
}

What I need is to convert the displayStart and displayEnd objects to a particular string format rather than the long value. This is what I tried to do.

我需要的是将displayStart和displayEnd对象转换为特定的字符串格式而不是long值。这就是我试图做的事情。

object MySerializers {
  val userDateFormatter = DateTimeFormat.forPattern("MM/dd/yyyy HH:mm a")

  implicit val writesBanner = (
    (__ \ "id").write[Int] and
    (__ \ "ownerId").write[Int] and
    (__ \ "licenseeId").write[Int] and
    (__ \ "statusColor").writeNullable[String] and
    (__ \ "content").writeNullable[String] and
    (__ \ "displayStart").write[DateTime].inmap[String](dt => userDateFormatter.print(dt)) and
    (__ \ "displayEnd").write[DateTime].inmap[String](dt => userDateFormatter.print(dt)) and
    (__ \ "created").write[DateTime] and
    (__ \ "updated").write[DateTime]
  )(unlift(Banner.unapply))
}

But the compiler is not happy about that, so I don't seem to understand the correct way to use the inmap function.

但编译器对此并不满意,所以我似乎并不理解使用inmap函数的正确方法。

could not find implicit value for parameter fu: 
play.api.libs.functional.InvariantFunctor[play.api.libs.json.OWrites]
[error]     (__ \ "displayStart").write[DateTime].inmap[String](dt =>     
userDateFormatter.print(dt)) and
[error]                                ^

Any advice is much appreciated.

任何建议都非常感谢。

2 个解决方案

#1


5  

I managed to get this one figured out, I was using the wrong type of functor map operations and had the types I was working with backwards. Here are working reads/writes implementations in the much nicer functional syntax.

我设法弄清楚了这一点,我使用了错误类型的仿函数映射操作,并且我正在使用向后的类型。以下是更好的功能语法中的读/写实现。

implicit val writesBanner = (
    (__ \ "id").write[Int] and
    (__ \ "ownerId").write[Int] and
    (__ \ "licenseeId").writeNullable[Int] and
    (__ \ "statusColor").writeNullable[String] and
    (__ \ "content").writeNullable[String] and
    (__ \ "displayStart").write[String].contramap[DateTime](dt => userDateFormatter.print(dt)) and
    (__ \ "displayEnd").write[String].contramap[DateTime](dt => userDateFormatter.print(dt)) and
    (__ \ "created").write[DateTime] and
    (__ \ "updated").write[DateTime]
  )(unlift(Banner.unapply))

implicit val readsBanner = (
    (__ \ "id").read[Int] and
    (__ \ "ownerId").read[Int] and
    (__ \ "licenseeId").readNullable[Int] and
    (__ \ "statusColor").readNullable[String] and
    (__ \ "content").readNullable[String] and
    (__ \ "displayStart").read[String].fmap[DateTime](dt => DateTime.parse(dt, userDateFormatter)) and
    (__ \ "displayEnd").read[String].fmap[DateTime](dt => DateTime.parse(dt, userDateFormatter)) and
    (__ \ "created").read[DateTime] and
    (__ \ "updated").read[DateTime]
  )(Banner)

#2


2  

I'm definitely no expert on this, but I'm pretty sure the way you use inmap is a combination of how you're using contramap/fmap.

我绝对不是这方面的专家,但我很确定你使用inmap的方式是你如何使用contramap / fmap的组合。

That is:

implicit val formatBanner = (
<truncated>
    (__ \ "displayStart").format[String].inmap(DateTime.parse(_, userDateFormatter), userDateFormatter.print(_)) and
<truncated>
  )(Banner.apply, unlift(Banner.unapply))

#1


5  

I managed to get this one figured out, I was using the wrong type of functor map operations and had the types I was working with backwards. Here are working reads/writes implementations in the much nicer functional syntax.

我设法弄清楚了这一点,我使用了错误类型的仿函数映射操作,并且我正在使用向后的类型。以下是更好的功能语法中的读/写实现。

implicit val writesBanner = (
    (__ \ "id").write[Int] and
    (__ \ "ownerId").write[Int] and
    (__ \ "licenseeId").writeNullable[Int] and
    (__ \ "statusColor").writeNullable[String] and
    (__ \ "content").writeNullable[String] and
    (__ \ "displayStart").write[String].contramap[DateTime](dt => userDateFormatter.print(dt)) and
    (__ \ "displayEnd").write[String].contramap[DateTime](dt => userDateFormatter.print(dt)) and
    (__ \ "created").write[DateTime] and
    (__ \ "updated").write[DateTime]
  )(unlift(Banner.unapply))

implicit val readsBanner = (
    (__ \ "id").read[Int] and
    (__ \ "ownerId").read[Int] and
    (__ \ "licenseeId").readNullable[Int] and
    (__ \ "statusColor").readNullable[String] and
    (__ \ "content").readNullable[String] and
    (__ \ "displayStart").read[String].fmap[DateTime](dt => DateTime.parse(dt, userDateFormatter)) and
    (__ \ "displayEnd").read[String].fmap[DateTime](dt => DateTime.parse(dt, userDateFormatter)) and
    (__ \ "created").read[DateTime] and
    (__ \ "updated").read[DateTime]
  )(Banner)

#2


2  

I'm definitely no expert on this, but I'm pretty sure the way you use inmap is a combination of how you're using contramap/fmap.

我绝对不是这方面的专家,但我很确定你使用inmap的方式是你如何使用contramap / fmap的组合。

That is:

implicit val formatBanner = (
<truncated>
    (__ \ "displayStart").format[String].inmap(DateTime.parse(_, userDateFormatter), userDateFormatter.print(_)) and
<truncated>
  )(Banner.apply, unlift(Banner.unapply))