Platform implementations of #clone is not compatible with TP.
Both java and .NET object implementations provide
#clone
method for default objects, which is enabled by
implementing Cloneable/ICloneable
interface. This
implementation is a shallow clone, i.e. only the top-level object
fields are duplicated, all the referenced(children) objects are only
copied as references to the same object in the parent clone. But how it
affects Transparent Persistence?
If you remember
Transparent Persistence Implementation
you must know that a special Activator
field is used to
bind an object to the object container. Consequently, the default clone
will copy this Activatable
field to the object's
duplicate, which will produce ambiguity as the object container won't
know which object should be activated for write.
Let's look how it will affect db4o in practice. We will use a usual
Car class and make it cloneable. Use the following code to store a
car object and it's clone:
01private static void storeCar() throws CloneNotSupportedException { 02
new File(DB4O_FILE_NAME).delete(); 03
ObjectContainer container = database(Db4o.newConfiguration()); 04
if (container != null) { 05
try { 06
// create a car 07
Car car = new Car("BMW", new Pilot("Rubens Barrichello")); 08
container.store(car); 09
// clone 10
Car car1 = (Car)car.clone(); 11
container.store(car1); 12
} finally { 13
closeDatabase(); 14
} 15
} 16
}
So it works for the first store, but what if we will clone an object retrieved from the database?
01private static void testClone() throws CloneNotSupportedException{ 02
storeCar(); 03
Configuration configuration = configureTP(); 04
05
ObjectContainer container = database(configuration); 06
if (container != null) { 07
try { 08
ObjectSet result = container.queryByExample(new Car(null, null)); 09
listResult(result); 10
Car car = null; 11
Car car1 = null; 12
if (result.size() > 0) 13
{ 14
car = (Car)result.get(0); 15
System.out.println("Retrieved car: " + car); 16
car1 = (Car)car.clone(); 17
System.out.println("Storing cloned car: " + car1); 18
container.store(car1); 19
} 20
} finally { 21
closeDatabase(); 22
} 23
} 24
}
The code above throws an exception when the cloned object is being
bound to the object container. Luckily we can easily fix it by
overriding #clone method and setting activator to null:
1public Object clone() throws CloneNotSupportedException { 2
Car test = (Car)super.clone(); 3
test._activator = null; 4
return test; 5
}