Salat in four minutes... or less
Salat is a bi-directional Scala case class serialization library that leverages
MongoDB's DBObject
(which uses BSON underneath) as its target format.
The Salat project focuses on speed and simplicity of serializing case classes to and from target formats.
Salat is not a fully-fledged ORM and does not attempt to match the flexibility, compability or functionality of an ORM that would let you define relationships between classes, provide a query language, or serialize/deserialize every collection type known to Java or Scala.
- Documentation available on our wiki.
- Salat-related discussion and questions belong on the mailing list.
- Follow Rose on Twitter - @prasinous
Add these repos to your SBT or Maven project:
val novusRels = "repo.novus rels" at "http://repo.novus.com/releases/"
val novusSnaps = "repo.novus snaps" at "http://repo.novus.com/snapshots/"
The main dependency is salat-core
.
Salat 0.0.7
release is available for Scala 2.8.1
.
val salat = "com.novus" % "salat-core" % "0.0.7"
Salat 0.0.8-SNAPSHOT
is available for both Scala 2.8.1
and 2.9.0-1
.
val salat = "com.novus" %% "salat-core" % "0.0.8-SNAPSHOT"
-
Convert an instance of any Scala case class to a
DBObject
suitable for insertion into a MongoDB database. -
Given a
DBObject
(which may have come from MongoDB, or elsewhere), instantiate an instance of the corresponding case class. -
Achieve goals 1 and 2 without sacrificing performance. This rules out use of reflection.
-
Achieve goals 1, 2, and 3 as functionally as possible.
In developing Salat, we have made a key decision to make these particular sacrifices and not look back.
Scala case classes have key features that Salat uses to improve and speed up object serialization, including:
-
A single accessible constructor. Can be retrieved either by reflecting on the class itself, or through generated companion object.
-
The
productIterator
method provided by theProduct
interface: a non-reflective way to retrieve programmatically values of the case class' data members. -
Data members can have default values; information missing in
DBObject
instance during re-inflation can be subbed in using default args defined at compile time.
So the first big improvement Salat offers for serialization is in being able to use case classes as products to get a list of indexed fields and their default arguments.
Well begun, but only half done. The other half is getting as much type information about the case class as possible, and then keeping that information on tap instead of having to derive it over and over again.
With these two pieces in hand, fast, reliable serialization without having to resort to runtime reflection is easy.
So thank you to EFPL for their wonderfully undocumented ScalaSig
, which Salat uses to memoize hi-fi type
information about each field in the case class.
Details about pickled Scala sigs are thin on the ground. Here's where we got started:
- the source code for
scala.tools.scalap.scalax.rules.scalasig.ScalaSigParser
- SID # 10 (draft) - Storage of pickled Scala signatures in class files
Requiring Product
and a single constructor rules out using anything but a case class. Technically, in the distant future,
we may be able to flex on the case class requirement enough to only require something very, very case class like.
However, Salat will never support classes defined in pure Java because they do not supply the requisite pickled Scala sig.
NB: it turns out that ScalaSig is incapable of "parsing" classes defined in the REPL. See SI-4567 for the gory details.
None of this code will work with classes that have no corresponding .class
file or ScalaSig
annotation.
Our ticket has been accepted as an improvement, but until this is fixed, if you want to experiment with serialization in the REPL:
- define your model classes
- run
sbt console
Salat is and will always be primarily focused on serializing and deserializing what's in the case class constructor.
There are some annotations that can be used to customize serialization at the case class level:
- Support for typing concrete case class instances to a trait or abstract superclass using
@Salat
- Use
@Key
to change a key name - Use
@Persist
to persist a value not in case class constructor - Use
@Ignore
to ignore a field in the case class constructor (requires default value) - Use
@EnumAs
to choose whether to handle enums by id or by value
In addition, you can customize your persistence context with regards to:
- type hinting strategy
- type hinting key name
- global key overrides
- global enum handling strategy
- default math context for BigDecimals
However, a lot of Salat's internal workings are not easily exposed or overriden right now. We are working to make Salat a more general-use serialization tool with future releases.
"Salat" is a transliteration of the Russian word "салат", for "salad".
Salat is light and doesn't slow you down through use of runtime reflection.