You are here: Advanced Features > Type Handling > Typehandlers > Custom Typehandler Example

Custom Typehandler Example

For a custom typehandler example we will try to write a very simple typehandler for the StringBuilder class. We want to handle a StringBuilder as a value type, therefore we implement the ValueTypeHandler interface. Not that there's a whole collection of interfaces for typehandlers. Take a look at the TypeHandler4 type hierarchy.

To keep it simple we will skip information required for indexing - please look at IndexableTypeHandler in db4o sources to get more information on how to handle indexes.

The first thing should be the write method, which determines how the object is persisted:

public void Write(IWriteContext writeContext, object o)
{
    StringBuilder builder = (StringBuilder) o;
    string str = builder.ToString();
    byte[] bytes = Encoding.UTF8.GetBytes(str);
    writeContext.WriteInt(bytes.Length);
    writeContext.WriteBytes(bytes);
}
StringBuilderHandler.cs: Write the StringBuilder
Public Sub Write(ByVal writeContext As IWriteContext, ByVal o As Object) _
    Implements IValueTypeHandler.Write
    Dim builder As StringBuilder = DirectCast(o, StringBuilder)
    Dim str As String = builder.ToString()
    Dim bytes As Byte() = Encoding.UTF8.GetBytes(str)
    writeContext.WriteInt(bytes.Length)
    writeContext.WriteBytes(bytes)
End Sub
StringBuilderHandler.vb: Write the StringBuilder

As you can see from the code above, there are 3 steps:

  1. Get the buffer from WriteContext/I WriteContext
  2. Convert the string-content to a byte-array using the UTF8 encoding.
  3. Write the length of the resulted byte-array.
  4. Write the byte array of the string.

Next step is to read the stored object. It is just opposite to the write method:

    public Object Read(IReadContext readContext)
    {
        int length = readContext.ReadInt();
        byte[] data = new byte[length];
        readContext.ReadBytes(data);
        return new StringBuilder(Encoding.UTF8.GetString(data));
    }
}
StringBuilderHandler.cs: Read the StringBuilder
Public Function Read(ByVal readContext As IReadContext) As Object _
    Implements IValueTypeHandler.Read
    Dim length As Integer = readContext.ReadInt()
    Dim data As Byte() = New Byte(length - 1) {}
    readContext.ReadBytes(data)
    Return New StringBuilder(Encoding.UTF8.GetString(data))
End Function
StringBuilderHandler.vb: Read the StringBuilder

Delete is simple - we just reposition the buffer offset to the end of the slot:

public void Delete(IDeleteContext deleteContext)
{
    SkipData(deleteContext);
}

private static void SkipData(IReadBuffer deleteContext)
{
    int numBytes = deleteContext.ReadInt();
    deleteContext.Seek(deleteContext.Offset() + numBytes);
}
StringBuilderHandler.cs: Delete the content
Public Sub Delete(ByVal deleteContext As IDeleteContext) _
    Implements IValueTypeHandler.Delete
    SkipData(deleteContext)
End Sub

Private Shared Sub SkipData(ByVal deleteContext As IReadBuffer)
    Dim numBytes As Integer = deleteContext.ReadInt()
    deleteContext.Seek(deleteContext.Offset() + numBytes)
End Sub
StringBuilderHandler.vb: Delete the content

The last method left: #defragment. This one only moves the offset to the beginning of the object data, i.e. skips Id and size information (to be compatible to older versions):

public void Defragment(IDefragmentContext defragmentContext)
{
    SkipData(defragmentContext);
}
StringBuilderHandler.cs: Defragment the content
Public Sub Defragment(ByVal defragmentContext As IDefragmentContext) _
    Implements IValueTypeHandler.Defragment
    SkipData(defragmentContext)
End Sub
StringBuilderHandler.vb: Defragment the content

Now to use this type handler we need to configure db4o. To register a typehandler you have to provide a predicate which decides if a type is handled by the typehandler and the typehandler itself.

IEmbeddedConfiguration configuration = Db4oEmbedded.NewConfiguration();
configuration.Common.RegisterTypeHandler(
    new SingleClassTypeHandlerPredicate(typeof(StringBuilder)), new StringBuilderHandler());
TypeHandlerExample.cs: Register type handler
Dim configuration As IEmbeddedConfiguration = Db4oEmbedded.NewConfiguration()
configuration.Common.RegisterTypeHandler(
    New SingleClassTypeHandlerPredicate(GetType(StringBuilder)), New StringBuilderHandler())
TypeHandlerExample.vb: Register type handler

After that all string builders are handled by you're type handler.