Creating your own reflector

By default db4o uses JdkReflector(Java) or NetReflector (.NET) as a GenericReflector delegate.

However, the programmer can instruct db4o to use a specially designed reflection implementation:

Java: Db4o.configure().reflectWith(reflector)

where reflector is one of the available reflectors or your own reflector implementation.

At present db4o comes with SelfReflector, which was designed for environments, which do not have built-in support for reflections (J2ME for example). In this implementation all the classes' information is stored in special registry. User classes should implement self_get and self_set methods to be registered individually and become "known" to SelfReflector.

Specific reflectors can be written for special usecases.

Let's look how to create a reflector. Remember that db4o relies on reflector to read the database, so errors in reflector may prevent your database from opening.

To keep things simple we will write a LoggingReflector, its only difference from standard reflector is that information about loaded classes is outputted to console. All reflectors used by db4o should implement com.db4o.reflect.Reflector interface.

LoggingReflector.java
01/* Copyright (C) 2004 - 2005 db4objects Inc. http://www.db4o.com */ 02 03package com.db4odoc.f1.reflections; 04 05import com.db4o.reflect.ReflectArray; 06import com.db4o.reflect.ReflectClass; 07import com.db4o.reflect.Reflector; 08import com.db4o.reflect.jdk.JdkClass; 09 10public class LoggingReflector implements Reflector { 11 private ReflectArray _array; 12 13 private Reflector _parent; 14 15 16 public LoggingReflector() { 17 18 } 19 20 public ReflectArray array() { 21 if(_array == null){ 22 _array = new LoggingArray(_parent); 23 } 24 return _array; 25 } 26 27 public boolean constructorCallsSupported() { 28 return true; 29 } 30 31 public ReflectClass forClass(Class clazz) { 32 ReflectClass rc = new JdkClass(_parent, clazz); 33 System.out.println("forClass: " + clazz+" -> "+(rc== null ? "" : rc.getName())); 34 return rc; 35 } 36 37 public ReflectClass forName(String className) { 38 try { 39 Class clazz = Class.forName(className); 40 ReflectClass rc = forClass(clazz); 41 System.out.println("forName: " + className+" -> "+(rc== null ? "" : rc.getName())); 42 return rc; 43 } catch (ClassNotFoundException e) { 44 return null; 45 } 46 } 47 48 public ReflectClass forObject(Object a_object) { 49 if (a_object == null) { 50 return null; 51 } 52 ReflectClass rc = _parent.forClass(a_object.getClass()); 53 System.out.println("forObject:" + a_object+" -> "+(rc== null ? "" : rc.getName())); 54 return rc; 55 } 56 57 public boolean isCollection(ReflectClass claxx) { 58 return false; 59 } 60 61 public void setParent(Reflector reflector) { 62 _parent = reflector; 63 } 64 65 public Object deepClone(Object context) { 66 return new LoggingReflector(); 67 } 68}

It is easy to see that this reflector provides the same functionality as JdkReflector or NetReflector extended by console output. The following simple test will show how it works:

ReflectorExample.java: testReflector
01public static void testReflector() 02 { 03 LoggingReflector logger = new LoggingReflector(); 04 Db4o.configure().reflectWith(logger); 05 ObjectContainer db=Db4o.openFile(YAPFILENAME); 06 try { 07 ReflectClass rc = db.ext().reflector().forName(Car.class.getName()); 08 System.out.println("Reflected class: " + rc); 09 } finally { 10 db.close(); 11 } 12 }

The output can help you to track all the loaded classes.

Reflection is a powerful tool, which plays a fundamental role in db4o. Understanding reflection will help you to understand the whole db4o functionality in detail.