12. Translators


In the last chapter we have covered the alternative configurations db4o offers for object reinstantiation. What's left to see is how we can store objects of a class that can't be cleanly stored with either of these approaches.


    12.1. An example class


    For this example we'll be using a hypothetical LocalizedItemList class which binds together culture information with a list of items.

    System.Globalization.CultureInfo is particularly interesting because it internally holds a native pointer to a system structure which in turn cannot be cleanly stored by db4o.

    Imports System.Globalization
    Namespace com.db4o.f1.chapter6
        ''' <summary>
        ''' A CultureInfo aware list of objects.
        ''' CultureInfo objects hold a native pointer to
        ''' a system structure.
        ''' </summary>
        Public Class LocalizedItemList
            Private _culture As CultureInfo
            Private _items As String()
            Public Sub New(ByVal culture As CultureInfo, ByVal items As String())
                _culture = culture
                _items = items
            End Sub
            Public Overloads Overrides Function ToString() As String
                Return String.Join(String.Concat(_culture.TextInfo.ListSeparator, " "), _items)
            End Function
        End Class
    End Namespace


    We'll be using this code to store and retrieve and instance of this class with different configuration settings:

    Public Shared Sub TryStoreAndRetrieve()
        Dim db As ObjectContainer = Db4oFactory.OpenFile(Util.YapFileName)
        Try
            Dim champs As String() = New String() {"Ayrton Senna", "Nelson Piquet"}
            Dim LocalizedItemList As LocalizedItemList = New LocalizedItemList(CultureInfo.CreateSpecificCulture("pt-BR"), champs)
            System.Console.WriteLine("ORIGINAL: {0}", LocalizedItemList)
            db.[Set](LocalizedItemList)
        Catch x As Exception
            System.Console.WriteLine(x)
            Return
        Finally
            db.Close()
        End Try
        db = Db4oFactory.OpenFile(Util.YapFileName)
        Try
            Dim result As ObjectSet = db.[Get](GetType(LocalizedItemList))
            While result.HasNext()
                Dim LocalizedItemList As LocalizedItemList = DirectCast(result.[Next](), LocalizedItemList)
                System.Console.WriteLine("RETRIEVED: {0}", LocalizedItemList)
                db.Delete(LocalizedItemList)
            End While
        Finally
            db.Close()
        End Try
    End Sub



      12.1.1. Using the constructor


      [tryStoreWithCallConstructors]
      Db4oFactory.Configure().ExceptionsOnNotStorable(True)
      Db4oFactory.Configure().ObjectClass(GetType(CultureInfo)).CallConstructor(True)
      TryStoreAndRetrieve()
      OUTPUT:
      ORIGINAL: 42/Test: 4
      onStore for 42/Test: 4
      onStore for 42/Test: 4
      onInstantiate for [Ljava.lang.Object;@8af6ec
      onActivate for 42/Test: 4 / [Ljava.lang.Object;@1b24924
      RETRIEVED: 42/Test: 4


At storage time, db4o tests the only available constructor with null arguments and runs into a NullPointerException, so it refuses to accept our object.

(Note that this test only occurs when configured with exceptionsOnNotStorable - otherwise db4o will silently fail when trying to reinstantiate the object.)


12.1.2. Bypassing the constructor


[tryStoreWithoutCallConstructors]
Db4oFactory.Configure().ObjectClass(GetType(CultureInfo)).CallConstructor(False)
' trying to store objects that hold onto
' system resources can be pretty nasty
' uncomment the following line to see
' how nasty it can be
'TryStoreAndRetrieve();


This still does not work for our case because the native pointer will definetely be invalid. In fact this example crashes the Common Language Runtime.


12.2. The Translator API


So how do we get our object into the database, now that everything seems to fail? Db4o provides a way to specify a custom way of storing and retrieving objects through the ObjectTranslator and ObjectConstructor interfaces.


12.3. A translator implementation


To translate CultureInfo instances, we will store only their name since this is enough to recreate them later. Note that we don't have to do any work in onActivate(), since object reinstantiation is already fully completed in onInstantiate().

Imports System.Globalization
Imports com.db4o
Imports com.db4o.config
Namespace com.db4o.f1.chapter6
    Public Class CultureInfoTranslator
        Implements ObjectConstructor
        Public Function OnStore(ByVal container As ObjectContainer, ByVal applicationObject As Object) As Object Implements ObjectConstructor.OnStore
            System.Console.WriteLine("onStore for {0}", applicationObject)
            Return (DirectCast(applicationObject, CultureInfo)).Name
        End Function
        Public Function OnInstantiate(ByVal container As ObjectContainer, ByVal storedObject As Object) As Object Implements ObjectConstructor.OnInstantiate
            System.Console.WriteLine("onInstantiate for {0}", storedObject)
            Dim name As String = DirectCast(storedObject, String)
            Return CultureInfo.CreateSpecificCulture(name)
        End Function
        Public Sub OnActivate(ByVal container As ObjectContainer, ByVal applicationObject As Object, ByVal storedObject As Object) Implements ObjectConstructor.OnActivate
            System.Console.WriteLine("onActivate for {0}/{1}", applicationObject, storedObject)
        End Sub
        Public Function StoredClass() As j4o.lang.Class Implements ObjectConstructor.StoredClass
            Return j4o.lang.[Class].GetClassForType(GetType(String))
        End Function
    End Class
End Namespace


Let's try it out:

[storeWithTranslator]
Db4oFactory.Configure().ObjectClass(GetType(CultureInfo)).Translate(New CultureInfoTranslator())
TryStoreAndRetrieve()
Db4oFactory.Configure().ObjectClass(GetType(CultureInfo)).Translate(Nothing)
OUTPUT:
ORIGINAL: 42/Test: 4
onStore for 42/Test: 4
onStore for 42/Test: 4
onInstantiate for [Ljava.lang.Object;@4c5310
onActivate for 42/Test: 4 / [Ljava.lang.Object;@1233fdf
RETRIEVED: 42/Test: 4



12.4. Conclusion


For classes that cannot cleanly be stored and retrieved with db4o's standard object instantiation mechanisms, db4o provides an API to specify custom reinstantiation strategies. These also come in two flavors: ObjectTranslators let you reconfigure the state of a 'blank' application object reinstantiated by db4o, ObjectConstructors also take care of instantiating the application object itself.


12.5. Full source


Imports System
Imports System.Globalization
Imports com.db4o
Namespace com.db4o.f1.chapter6
    Public Class TranslatorExample
    Inherits Util
        Public Shared Sub Main(ByVal args As String())
            TryStoreWithCallConstructors()
            TryStoreWithoutCallConstructors()
            StoreWithTranslator()
        End Sub
        Public Shared Sub TryStoreWithCallConstructors()
            Db4oFactory.Configure().ExceptionsOnNotStorable(True)
            Db4oFactory.Configure().ObjectClass(GetType(CultureInfo)).CallConstructor(True)
            TryStoreAndRetrieve()
        End Sub
        Public Shared Sub TryStoreWithoutCallConstructors()
            Db4oFactory.Configure().ObjectClass(GetType(CultureInfo)).CallConstructor(False)
            ' trying to store objects that hold onto
            ' system resources can be pretty nasty
            ' uncomment the following line to see
            ' how nasty it can be
            'TryStoreAndRetrieve();
        End Sub
        Public Shared Sub StoreWithTranslator()
            Db4oFactory.Configure().ObjectClass(GetType(CultureInfo)).Translate(New CultureInfoTranslator())
            TryStoreAndRetrieve()
            Db4oFactory.Configure().ObjectClass(GetType(CultureInfo)).Translate(Nothing)
        End Sub
        Public Shared Sub TryStoreAndRetrieve()
            Dim db As ObjectContainer = Db4oFactory.OpenFile(Util.YapFileName)
            Try
                Dim champs As String() = New String() {"Ayrton Senna", "Nelson Piquet"}
                Dim LocalizedItemList As LocalizedItemList = New LocalizedItemList(CultureInfo.CreateSpecificCulture("pt-BR"), champs)
                System.Console.WriteLine("ORIGINAL: {0}", LocalizedItemList)
                db.[Set](LocalizedItemList)
            Catch x As Exception
                System.Console.WriteLine(x)
                Return
            Finally
                db.Close()
            End Try
            db = Db4oFactory.OpenFile(Util.YapFileName)
            Try
                Dim result As ObjectSet = db.[Get](GetType(LocalizedItemList))
                While result.HasNext()
                    Dim LocalizedItemList As LocalizedItemList = DirectCast(result.[Next](), LocalizedItemList)
                    System.Console.WriteLine("RETRIEVED: {0}", LocalizedItemList)
                    db.Delete(LocalizedItemList)
                End While
            Finally
                db.Close()
            End Try
        End Sub
    End Class
End Namespace




--
generated by
Doctor courtesy of db4objects Inc.