Skip to content
rktoomey edited this page Jan 21, 2012 · 2 revisions

Annotations

Salat offers the following annotations to customize serialization behavior:

  • @Salat to support polymorphic instances of a trait or abstract superclass
  • @Key to change the name of a field
  • @Persist to serialize a value outside the case class constructor
  • @Ignore to ignore a field in the case class constructor
  • @EnumAs to customize the behavior of a particular enum

Importing annotations

To use these annotations, import the types:

import com.novus.salat.annotations._

The import statement is important! This package object import aliases each annotation to a type targeted with @getter.

If you import like this instead,

import com.novus.salat.annotations.raw.Persist

you will need to manually target to the getter like this:

@(Persist @getter) val someVal = ...

@Salat

See traits and abstract superclasses with Salat

@Key

Using @Key for ad hoc key remapping is as easy as declaring it in the case class constructor:

  case class Alpha(@Key("greeting") x: String)

  scala> val a = Alpha(x = "Hello world")
  a: com.novus.salat.test.model.Alpha = Alpha(Hello world)

  scala> val dbo = grater[Alpha].asDBObject(a)
  dbo: com.mongodb.casbah.Imports.DBObject = { "_typeHint" :
      "com.novus.salat.test.model.Alpha" , "greeting" : "Hello world"}

  scala> val a_* = grater[Alpha].asObject(dbo)
  a_*: com.novus.salat.test.model.Alpha = Alpha(Hello world)

  scala> a == a_*
  res0: Boolean = true

@Persist

Sometimes you want to serialize a value inside a case class but outside its constructor. The canonical example to me is a value you want to be able to sort on in Mongo but don't otherwise care about. @Persist to the rescue!

You can use @Persist on a val, var or lazy val.

  case class Psi(x: String) {
    @Persist val reversed = x.reverse
  }

  scala> val p = Psi(x = "persist me")
  p: com.novus.salat.test.model.Psi = Psi(persist me)

  scala> p.reversed
  res0: String = em tsisrep

  scala> val dbo = grater[Psi].asDBObject(p)
  dbo: com.mongodb.casbah.Imports.DBObject = { "_typeHint" : "com.novus.salat.test.model.Psi" ,
      "x" : "persist me" , "reversed" : "em tsisrep"}

  scala> val p_* = grater[Psi].asObject(dbo)
  p_*: com.novus.salat.test.model.Psi = Psi(persist me)

But it gets better: you can also use @Persist in an immediate trait or abstract superclass. Mix and match.

@Ignore

If, for whatever reason, you are passing something into your case class constructor that you don't want to serialize, you need only do two things:

  • annotate the parameter with @Ignore
  • supply a default argument so that the object can be deserialized
  case class Alpha(x: String, @Ignore y: Option[String] = None)

  scala> val a = Alpha(x = "Hello world", y = Some("Goodbye value I don't care about"))
  a: com.novus.salat.test.model.Alpha = Alpha(Hello world,Some(Goodbye value I don't care about))

  scala> val dbo = grater[Alpha].asDBObject(a)
  dbo: com.mongodb.casbah.Imports.DBObject = { "_typeHint" :
      "com.novus.salat.test.model.Alpha" , "x" : "Hello world"}

  scala> val a_* = grater[Alpha].asObject(dbo)
  a_*: com.novus.salat.test.model.Alpha = Alpha(Hello world,Some(Goodbye value I don't care about))

  scala> a == a_*
  res0: Boolean = true

@EnumAs

Enums? Our sympathies.

You have two choices for enum serialization: by id or by value. They both have their downsides. I'm assuming by this point in the game you already know what your poison is.

Salat's default enum handling is by value, set up at the context level.

But let's say that for just one enum you want to persist by value instead of id or vice versa. Very easy - just define your custom enum strategy at the enum level:

  // ThugLevel will use the context default handling for enums (which is by value)
  object ThugLevel extends Enumeration("Fairplay Tony", "Honour student", "Just a good boy who loves his mum", "Trouble, you") {
    val One, Two, Three, Four = Value
  }

  // but DoneIn will be mapped by id
  @EnumAs(strategy = EnumStrategy.BY_ID)
  object DoneIn extends Enumeration {
    val Napping, PiningForTheFjords, IsThereADoctorInTheHouse, OhDear, Definitely = Value
  }

  case class Hector(thug: ThugLevel.Value, doneInById: DoneIn.Value)

Clone this wiki locally