I have a class that takes a few optional Enumeration
types in its constructor:
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])
I've been struggling to create an implicit Json reads
method that works. I keep ending up with errors such as:
[error] /Users/zbeckman/Projects/Glimpulse/Server/project/glimpulse-server/app/utility/GPMedia.scala:57: overloaded method value apply with alternatives:
etc...
What I'm trying to do is translate the inbound Json strings, turning them into the right kind of Option
instance (eg., a MIME type "image/png" in the Json would turn into Option(GPMediaType(v))
. The GPMediaType constructor will map the string, and return a correct value (one of which is GPMediaType.Unknown
).
Here's the implicit reads
that I've worked up so far, implemented on the GPMedia class' companion object...
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 _)
}
This works, but when I try to add other apply()
methods, it all goes to heck. How can I apply a specific apply method in the Json reads
implementation? For example, when I add this apply
method:
def apply(data: Array[Byte]) = new GPMedia(None, None, None, data, None, None, None)
I end up with:
[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 _)
I've tried a few different approaches, such as (GPMedia.apply(...))
but I can't seem to get the parameters right.
I'm new to the whole Json implicit reader/writer and Json decoding syntax. Clearly I'm missing something here...
Edit
Here's another example, regarding my attempt to call a specific apply
method:
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))
This results in:
[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] ^
This is not possible. The compiler does not know which
apply
method to use. This is just one of the caveats of using overloaded methods. The only way you can make this like "nice" is to rename the methods, or alias the overloadedapply
methods with different names and use those.Your second attempt does not work because the compiler is expecting a function with a signature similar to
apply
, like:But you're trying to use:
Which doesn't work, because we don't yet have a
GPMedia
object, just the tupled fields. It would look more like:Which does not look good. Usually we can make it look better like this:
Except that you will end up with the same problem that you started with, because the compiler will not be able to choose the correct
apply
method. So you really have no choice but to rename or make things ugly.