Refactoring API

Db4o provides special API which can help you to move classes between packages (Java)/namespaces(.NET), rename classes or fields:

Java:
Db4o.configure().objectClass("package.class").rename("newPackage.newClass")
Db4o.configure().objectClass("package.class").objectField("oldField").rename("newField")

The safe order of actions for rename calls is:

  1. Backup you database and aaplication
  2. Close all open objectContainers if any
  3. Rename classes or fields or copy classes to the new package/namespace in your application. (Do not remove old classes yet).
  4. Issue ObjectClass#rename and objectField#rename calls without having an ObjectContainer open.
  5. Open database file and close it again without actually working with it.
  6. Remove old classes (if applicable).

After that you will only see the new classes/fields in ObjectManager, the old ones will be gone.

Let's look how it works on an example. We will use initial class Pilot:

Pilot.java
01/* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com */ 02 03package com.db4odoc.refactoring; 04 05public class Pilot { 06 private String name; 07 08 public Pilot(String name) { 09 this.name = name; 10 } 11 12 public String getName() { 13 return name; 14 } 15 16 public String toString() { 17 return name; 18 } 19}

and change it to the new class PilotNew renaming field and changing package/namespace at the same time:

PilotNew.java
01/* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com */ 02 03package com.db4odoc.refactoring; 04 05public class PilotNew { 06 private String identity; 07 08 private int points; 09 10 public PilotNew(String name, int points) { 11 this.identity = name; 12 this.points = points; 13 } 14 15 public String getIdentity() { 16 return identity; 17 } 18 19 public String toString() { 20 return identity + "/" + points; 21 } 22}

First let's create a database and fill it with some values:

RefactoringExample.java: setObjects
01private static void setObjects(){ 02 new File(DB4O_FILE_NAME).delete(); 03 ObjectContainer container = Db4o.openFile(DB4O_FILE_NAME); 04 try { 05 Pilot pilot = new Pilot("Rubens Barrichello"); 06 container.set(pilot); 07 pilot = new Pilot("Michael Schumacher"); 08 container.set(pilot); 09 } finally { 10 container.close(); 11 } 12 }
RefactoringExample.java: checkDB
1private static void checkDB(){ 2 ObjectContainer container = Db4o.openFile(DB4O_FILE_NAME); 3 try { 4 ObjectSet result=container.get(new Object()); 5 listResult(result); 6 } finally { 7 container.close(); 8 } 9 }

We already have PilotNew class so we can go on with renaming:

RefactoringExample.java: changeClass
1private static void changeClass(){ 2 Configuration configuration = Db4o.newConfiguration(); 3 configuration.objectClass(Pilot.class).rename("com.db4odoc.f1.refactoring.PilotNew"); 4 configuration.objectClass(PilotNew.class).objectField("name").rename("identity"); 5 ObjectContainer container = Db4o.openFile(configuration, DB4O_FILE_NAME); 6 container.close(); 7 }

Now the data for the old Pilot class should be transferred to the new PilotNew class, and "name" field data should be stored in "identity" field.

To make our check more complicated let's add some data for our new class:

RefactoringExample.java: setNewObjects
01private static void setNewObjects(){ 02 ObjectContainer container = Db4o.openFile(DB4O_FILE_NAME); 03 try { 04 PilotNew pilot = new PilotNew("Rubens Barrichello",99); 05 container.set(pilot); 06 pilot = new PilotNew("Michael Schumacher",100); 07 container.set(pilot); 08 } finally { 09 container.close(); 10 } 11 }

We can check what is stored in the database now:

RefactoringExample.java: retrievePilotNew
1private static void retrievePilotNew(){ 2 ObjectContainer container = Db4o.openFile(DB4O_FILE_NAME); 3 try { 4 ObjectSet result = container.query(PilotNew.class); 5 listResult(result); 6 } finally { 7 container.close(); 8 } 9 }

There is one thing to remember. The rename feature is intended to rename a class from one name to the other. Internally this will rename the meta-information. If you will try to rename class to the name that is already stored in the database, the renaming will fail, because the name is reserved. In our example it will happen if setNewObjects method will be called before changeClass.