Help me write a Play Json format for generic (bounded types) class

999 views
Skip to first unread message

Noor Rayni

unread,
May 21, 2016, 2:04:30 PM5/21/16
to play-framework

I am trying to write a play Json formatter for the enum and classes below. I want to de-serialize a Json file to an instance of ImageDisplay (see below). When I run the following code, Play complains that I cannot find a deserializer for ImageDisplay[T]. I have written different formats but none of them actually worked. Please help.




environment.resourceAsStream("cdn.images.json").flatMap { is =>
      try {
        //          play.api.libs.json.Json.parse(IOUtils.toString(is)).as[ImageDisplay[T]]
        Json.fromJson[models.ImageDisplay[T]](Json.parse(IOUtils.toByteArray(is))).asOpt
      } finally {
        is.close()
      }
    }



object
Enum extends Enumeration {
  val
Primary = Value("primary", "0")
 
case class Category(name: String, val key: String) extends Val(nextId, name)
 
protected final def Value(name: String, key: String): Category = new Category(name, key)


}


case class BaseImage(category: Enum.Category, url: String, height: Int, width: Int, units: String, format: String)

abstract class ImageSet

case class ProductImageSet(swatchImage: BaseImage, smallImage: BaseImage, mediumImage: BaseImage, largeImage: BaseImage) extends ImageSet

case class ProfileImageSet(smallImage: BaseImage, mediumImage: BaseImage) extends ImageSet

case class ImageDisplay[T <: ImageSet](id: String, imageSets: Seq[T])

Will Sargent

unread,
May 21, 2016, 2:20:23 PM5/21/16
to play-fr...@googlegroups.com
I don't think you can use case classes with type parameters with JSON macros.  You may need to specify concrete instances.

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/f383f996-03a1-4c55-af30-03e28882c260%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Greg Methvin

unread,
May 21, 2016, 8:49:36 PM5/21/16
to play-framework
Hi Noor,

As Will said, it's not possible to use any of the JSON macros for this. You're going to have to write it manually. Also, you probably need an implicit Format[T] in your ImageDisplay, since to generate a Format for ImageDisplay you also need a Format for whatever type it contains.

You'll have to roll your own serializer for your Enumeration too, but for each of your ImageSets you can still use the Json.format macro.

Greg


For more options, visit https://groups.google.com/d/optout.



--
Greg Methvin
Senior Software Engineer

Noor Rayni

unread,
May 21, 2016, 9:13:30 PM5/21/16
to play-framework
Thanks Greg and Will for the answers. Appreciate the answers. Actually, I have defined some implicit Format[T] but Play still complains it cannot find a deserializer for ImageDisplay[T]. Here are the implicit formats I defined for my classes. Any suggestions please ?


object ProfileImageSet {

 
implicit def profileImageSetFormat: Format[ProfileImageSet] = (
   
(__ \ "smallImage").format[BaseImage] ~
   
(__ \ "mediumImage").format[BaseImage])(ProfileImageSet.apply _, unlift(ProfileImageSet.unapply _))
}

object ProductImageSet {
 
implicit def productImageSetFormat: Format[ProductImageSet] = (
   
(__ \ "swatchImage").format[BaseImage] ~
   
(__ \ "smallImage").format[BaseImage] ~
   
(__ \ "mediumImage").format[BaseImage] ~
   
(__ \ "largeImage").format[BaseImage])(ProductImageSet.apply _, unlift(ProductImageSet.unapply _))

}

object BaseImage {
 
implicit def baseImageFormat: Format[BaseImage] = (
   
(__ \ "category").format[Enum.Category] ~
   
(__ \ "url").format[String] ~
   
(__ \ "height").format[Int] ~
   
(__ \ "width").format[Int] ~
   
(__ \ "units").format[String] ~
   
(__ \ "format").format[String])(BaseImage.apply, unlift(BaseImage.unapply))
}

object ImageDisplay {
 
implicit def imageDisplayFormat[T: Format]: Format[ImageDisplay[T]] =
   
((__ \ "pin").format[String] ~
     
(__ \ "imageSets").format[Seq[T]])(ImageDisplay.apply _, unlift(ImageDisplay.unapply _))

 
implicit def profileImageDisplayFormat[T: Format]: Format[ImageDisplay[ProfileImageSet]] =
   
((__ \ "pin").format[String] ~
     
(__ \ "imageSets").format[Seq[ProfileImageSet]])(ImageDisplay.apply _, unlift(ImageDisplay.unapply _))

 
implicit def productImageDisplayFormat[T: Format]: Format[ImageDisplay[ProductImageSet]] =
   
((__ \ "pin").format[String] ~
     
(__ \ "imageSets").format[Seq[ProductImageSet]])(ImageDisplay.apply _, unlift(ImageDisplay.unapply _))
}

Noor Rayni

unread,
May 22, 2016, 7:30:08 AM5/22/16
to play-framework
Okay, I got it to work by having two services, on for each ImageSet, to parse my Jsons. I am duplicating code but at least got the de-serialization to work.
Reply all
Reply to author
Forward
0 new messages