How can i serialize val element to Json

When serializing the next case class, the val element is not included. Why is this, and can I enable it?

case class Asset(id: Option[Int], description: Option[String]= None) {
  val url = "images/" + id.toString+".png"
}

      

Update: Added Json library and spec / intended use of url property.

I am using the Json library that comes with Play 2.1 / Scala 2.10.

In fact, the url property is for a function that will look for a transformation algorithm according to the configuration, for example, an image can be accessed locally or accessed from an external host.

+3


source to share


1 answer


While you can actually specify which json serialization library you are using, it is pretty much guaranteed that the following will do:

case class Asset(id: Option[Int], description: Option[String]= None, url = "images/" + id.toString+".png")

      

Given that the value url

has a default value, turning it into a parameter does not negatively affect your code (you can still do it Asset(None)

with an example as before). The only drawback is that the client code can now instantiate Asset

with a different value for url

, which may not be what you want.

In this case, you probably need to create a custom json format for your class Asset

, but not knowing which serialization library you are using. I cannot help more in this regard.


UPDATE

In general, I completely missed the fact that the default value for url

depends on another parameter ( id

) (thanks to @Kristian Domagala for noticing). So my above snippet doesn't compile. One simple solution is to put url

in the second parameter list suggested by @Kristian Domagala:



case class Asset(id:Option[Int],description:Option[String]=None)(val url:String = "images/" + id.toString+".png")

      

But that might not be ideal as it changed the semantics of equality Asset

( url

no longer taken into account when comparing instances) and also changes the construction syntax: when explicitly specifying a value, url

you need to do something like Asset(Some(123))("gfx/myImage.png")

instead of an example Asset(Some(123), url="gfx/myImage.png")

. If you can live with these cons, this is by far the simplest solution.

Otherwise there is another work to do: we can override Asset.apply

ourselve (manually):

case class AssetImpl( val id: Option[Int], val description: Option[String], val url: Option[String]) {
  override def productPrefix = "Asset"
}
type Asset = AssetImpl
object Asset {
  def apply( id: Option[Int], description: Option[String] = None, url: Option[String] = None ) = {
    new Asset( id, description, url.orElse( id.map( "images/" + _ + ".png") ) )
  }
}

      

As you can see, I turned url

into Option

with a default value None

(avoiding the previous compilation error, since it doesn't depend on anymore id

) because of and into def apply...

I create an instance Asset

with a default value for url

(here I actually get the value id

) id.map( "images/" + _ + ".png")

.

The rest is just noise to allow overrides Asset.apply

: it turns out that you cannot override the factory of the case class (you can only add individual overloads). So I renamed the class as AssetImpl

, added a type alias so no one would notice (;-)), and created my own object Asset

where I define a method apply

(which no longer conflicts with the auto-generated apply

one because this object is in a separate object AssetImpl

. I could have just turned Asset

into a standard class (non case class), but then I would have to override equals

and hashCode

, which I find more annoying given that it must be supported when adding / removing fields to a class.

+2


source







All Articles