Let's say we want to build a big social network (because social networks are all the rage at the moment). We'll start with a simple premise that anyone who wants to use our social network should be able to register under their name and then become friends or fall out with other people registred with us:
import scala.collection._
class Person (var name: String) {
private val _friends = new mutable.HashSet[Person]
def befriends (p: Person) { _friends+=p }
def fallsOutWith (p: Person) { _friends-=p }
def friends () = _friends toSet
override def toString = name
}
So far so good:
val brad = new Person("Brad Pitt")
val angelina = new Person("Angelina Jolie")
brad befriends angelina
angelina befriends brad
Good stuff! A final touch, let's see the list of all Brad's friends:
brad.friends.foreach(println)
It works, and we're about to take the world by a storm with our wonderful social network that is all 100% Scala!
Now on to the boring, technical bits. We'd need to be able to persist data and db4o seems as a good choice, some more code:
db store brad // job done!
And then restore Brad from hard drive:
val q = db.query
q.constrain(classOf[Person])
q.descend("name").constrain("Brad Pitt")
val brad = q.execute.get(0)
See the list of friends once again...
brad.friends.foreach(println)
and BANG! NullPointerException! With a bit of debugging it turns out that underlying data store of mutable.HashSet that we're relying on to keep track of friends is defined as transient in scala.collection.mutable.FlatHashTable:
@transient protected var table: Array[AnyRef] = new Array(initialCapacity)
and hence when we telling db4o to store a Person the actual list of friends in not serialised. It seems that db4o ought to be using readObject and writeObject methods of HashSet instead.
I wonder if there is way of telling db4o to serialise / deserialise HashSet correctly or if there is a more suitable Scala Set implementation that is db4o friendly?