Skip to content

Instantly share code, notes, and snippets.

@rktoomey
Created August 4, 2011 13:47
Show Gist options
  • Save rktoomey/1125182 to your computer and use it in GitHub Desktop.
Save rktoomey/1125182 to your computer and use it in GitHub Desktop.
Binary "when necessary" type hinting with Salat
package com.novus.salat.test
import com.novus.salat.util.encoding.TypeHintEncoding
import com.novus.salat.{ TypeHintFrequency, BinaryTypeHintStrategy, Context }
package object when_necessary_binary_type_hint_encoding {
implicit val ctx = new Context {
val name = Some("WhenNecessary-BinaryTypeHint")
override val typeHintStrategy = BinaryTypeHintStrategy(when = TypeHintFrequency.WhenNecessary,
typeHint = "t",
encoding = TypeHintEncoding.UsAsciiEncoding)
}
}
package object model {
@Salat
trait SomeTrait extends Product
case class SomeTraitImpl1(x: String) extends SomeTrait
case class SomeTraitImpl2(y: Int) extends SomeTrait
}
salat-core:master:0.0.8-SNAPSHOT> test:console
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.8.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import com.novus.salat._
import com.novus.salat._
scala> import com.novus.salat.test.when_necessary_binary_type_hint_encoding._
import com.novus.salat.test.when_necessary_binary_type_hint_encoding._
scala> import com.novus.salat.test.model._
import com.novus.salat.test.model._
scala> val x: SomeTrait = SomeTraitImpl2(y = 3)
x: com.novus.salat.test.model.SomeTrait = SomeTraitImpl2(3)
scala> val dbo = grater[SomeTrait].asDBObject(x)
2 [run-main] INFO com.novus.salat.test.when_necessary_binary_type_hint_encoding.package$$anon$7 - accept: ctx='WhenNecessary-BinaryTypeHint' accepted grater[com.novus.salat.test.model.SomeTrait]
8 [run-main] INFO com.novus.salat.test.when_necessary_binary_type_hint_encoding.package$$anon$7 - accept: ctx='WhenNecessary-BinaryTypeHint' accepted grater[com.novus.salat.test.model.SomeTraitImpl2]
285 [run-main] INFO com.novus.salat.BinaryTypeHintStrategy - toTypeHint: put 'com.novus.salat.test.model.SomeTraitImpl2' ---> 184477527298863911571054983976302194159472974158232255170769888682740810047
286 [run-main] INFO com.novus.salat.BinaryTypeHintStrategy - fromTypeHint: put 184477527298863911571054983976302194159472974158232255170769888682740810047 ---> 'com.novus.salat.test.model.SomeTraitImpl2'
dbo: com.mongodb.casbah.Imports.DBObject = { "t" : <Binary Data> , "y" : 3}
scala> import com.mongodb.casbah.Imports._
import com.mongodb.casbah.Imports._
scala> val dbo:MongoDBObject = grater[SomeTrait].asDBObject(x)
dbo: com.mongodb.casbah.Imports.MongoDBObject = Map((t,[B@a7046e7), (y,3))
scala> val x_* = grater[SomeTrait].asObject(dbo)
x_*: com.novus.salat.test.model.SomeTrait = SomeTraitImpl2(3)
scala> x == x_*
res0: Boolean = true
Binary type hint encoding uses a charset to create a base N representation for encoding and decoding
String <-> BigInt (which is saved as a ByteArray). Requires latest 0.0.8-SNAPSHOT of salat-core.
Novus is currently using binary type hint encoding in our staging environment.
See com.novus.salat.util.encoding.TypeHintEncoding and com.novus.salat.BinaryTypeHintStrategy for
details.
Details include:
* binary type hint encoding to customized charset
** Array[Byte] <-> BigInt <-> String
* the conversion is expensive relative to just using strings, but it is memoized in both directions
(that's what the log statements with the BigInts in the test:console session above are about)
* backwards compatible with String type hints - on receiving a String, the decoder just passes it
through
* if you use com.mongodb.util.JSON for parsing JSON, it's going to fall down because it handles
Binary/byte[] as the string "<Binary Data>" - we forked and patched the mongo-java-driver locally and I
will submit a pull request to 10gen once I have time to write a unit test for it
When using US ASCII for Java identifiers, the binary representation is about 20% more efficient than the
String. The full list of every unicode character that is a legal Java identifier is around 2X the size
of the string (we supply this charset just in case you want to play around with it), so you will need
to fine tune your charset if you use non-US ASCII characters in your package or class names.
CAVEAT: CASE OBJECTS
Right now, if you choose a binary type hinting strategy, type hints for everything EXCEPT case objects
will be encoded and persisted to MongoDB as byte arrays.
Since we have queries around our case objects, we prefer to have case object type hints encoded as
Strings. (@patriknw, we will be making this configurable very soon, I promise... :)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment