如何在 Scala 的隐式 Json `reads` 中使用特定的应用方法
How to use specific apply method in implicit Json `reads` from Scala
我有一个 class 在其构造函数中采用一些可选的 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
实例(例如,MIME 类型 "image/png" 在Json 将变成 Option(GPMediaType(v))
。GPMediaType 构造函数将映射字符串,并且 return 是一个正确的值(其中之一是 GPMediaType.Unknown
)。
这是我目前已经完成的 implicit reads
,在 GPMedia class' 伴随对象上实现...
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
实现中应用 specific 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 隐式 reader/writer 和 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] ^
这是不可能的。编译器不知道使用哪个 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)
Except 您最终会遇到与开始时相同的问题,因为编译器将无法选择正确的 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]
)
)
我有一个 class 在其构造函数中采用一些可选的 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
实例(例如,MIME 类型 "image/png" 在Json 将变成 Option(GPMediaType(v))
。GPMediaType 构造函数将映射字符串,并且 return 是一个正确的值(其中之一是 GPMediaType.Unknown
)。
这是我目前已经完成的 implicit reads
,在 GPMedia class' 伴随对象上实现...
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
实现中应用 specific 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 隐式 reader/writer 和 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] ^
这是不可能的。编译器不知道使用哪个 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)
Except 您最终会遇到与开始时相同的问题,因为编译器将无法选择正确的 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]
)
)