| # 11. Constructors Sometimes you may find that db4o refuses to store instances of certain classes, or appears to store them, but delivers incomplete instances on queries. To understand the problem and the alternative solutions at hand, we'll have to take a look at the way db4o "instantiates" objects when retrieving them from the database. ## 11.1. Instantiating objects Db4o currently knows three ways of creating and populating an object from the database. The approach to be used can be configured globally and on a per-class basis. ## 11.1.1. Using a constructor The most obvious way is to call an appropriate constructor. Db4o does not require a public or no-args constructor. It can use any constructor that accepts default (null/0) values for all of its arguments without throwing an exception. Db4o will test all available constructors on the class (including private ones) until it finds a suitable one. What if no such constructor exists? ## 11.1.2. Bypassing the constructor Db4o can also bypass the constructors declared for this class using platform-specific mechanisms. (For Java, this option is only available on JREs >= 1.4.) This mode allows reinstantiating objects whose class doesn't provide a suitable constructor, However, it will (silently) break classes that rely on the constructor to be executed, for example in order to populate transient members. If this option is available in the current runtime environment, it will be the default setting. ## 11.1.3. Using a translator If none of the two approaches above is suitable, db4o provides a way to specify in detail how instances of a class should be stored and reinstantiated by implementing the Translator interface and registering this implementation for the offending class. We'll cover translators in detail in the next chapter . ## 11.2. Configuration The instantiation mode can be configured globally or on a per class basis.
`Db4o.configure().callConstructors(true);`
This will configure db4o to use constructors to reinstantiate any object from the database. (The default isfalse).
`Db4o.configure().objectClass(Foo.class).callConstructor(true);`
This will configure db4o to use constructor calls for this class and all its subclasses. ## 11.3. Troubleshooting At least for development code, it is always a good idea to instruct db4o to check for available constructors at storage time. (If you've configured db4o to use constructors at all.)
`Db4o.configure().exceptionsOnNotStorable(true);`
If this setting triggers exceptions in your code, or if instances of a class seem to lose members during storage, check the involved classes (especially their constructors) for problems similar to the ones shown in the following section. ## 11.4. Examples
`class C1 { private String s; private C1(String s) { this.s=s; } public String toString() { return s; } }`
The above class is fine for use with and without callConstructors set.
`class C2 { private transient String x; private String s; private C2(String s) { this.s=s; this.x="x"; } public String toString() { return s+x.length(); } }`
The above C2 class needs to have callConstructors set to true. Otherwise, since transient members are not stored and the constructor code is not executed, toString() will potentially run into a NullPointerException on x.length().
`class C3 { private String s; private int i; private C3(String s) { this.s=s; this.i=s.length(); } public String toString() { return s+i; } }`
The above C3 class needs to have callConstructors set to false (the default), since the (only) constructor will throw a NullPointerException when called with a null value.
`class C4 { private String s; private transient int i; private C4(String s) { this.s=s; this.i=s.length(); } public String toString() { return s+i; } }`
This class cannot be cleanly reinstantiated by db4o: Both approaches will fail, so one has to resort to configuring a translator. -- generated by Doctor courtesy of db4objects Inc.