feedback / send your comments

mail to luc peuvrier
chat channel
joafip users mailing list
forums

BACK TO INDEX
BACK TO FEATURE

En Français

JOAFIP Persistent POJO 

JOAFIP can store any kind of object : see how, and how to be optimal

There are constraints on the code because proxies are used for lazy load, this can be overcome by bytecode transformation using java agent.

It is advisable to keep with constraints rather than using the transformation of byte code, because of execution time trade off. This is possible if you are the writer of the code of classes to persist. If you do not have the control of the code of persisted classes, and there is no constraints workaround, then the byte code transformation is the ultimate solution.

JOAFIP uses a generic way to persist the object in file:

specific input/output

substitution activation : setSubstitutionOfJavaUtilCollection()

The built in substitution are (mainly for collections):

java.util.LinkedList:

substitute is PLinkedList ,synchronizer is LinkedListSynchronizer
PTreeList can be use

java.util.ArrayList:

substitute is PArrayList ,synchronizer is ArrayListSynchronizer
PTreeList can be use

java.util.HashSet:

substitute is PLinkedHashSet ,synchronizer is SetSynchronizer

java.util.HashSet:

substitute is PHashSet ,synchronizer is SetSynchronizer

java.util.LinkedHashSet:

substitute is PLinkedHashSet ,synchronizer is SetSynchronizer
PLinkedTreeSet a linked tree set (see TreeSet), can be use if elements are comparable

java.util.TreeSet:

substitute is PTreeSet ,synchronizer is SetSynchronizer

java.util.Hashtable:

substitute is PLinkedHashMap ,synchronizer is MapSynchronizer

java.util.HashMap:

substitute is PHashMap ,synchronizer is MapSynchronizer

java.util.LinkedHashMap:

substitute is PLinkedHashMap ,synchronizer is MapSynchronizer
PLinkedTreeMap a linked tree map (see TreeMap), can be use if keys are comparables

java.util.LinkedHashMap:

substitute is PLinkedHashMap ,synchronizer is MapSynchronizer

java.util.TreeMap:

substitute is PTreeMap ,synchronizer is MapSynchronizer


java.util.Vector
stored natively without substitution.

_The different constraints for JOAFIP PPOJO:

Links gives more details: reasons and solutions
The ultimate solution is the use of java agent "anti persistence constraint", but the trade off is execution speed.

class must not be final

Final class can not be enhanced by derivation, so create a proxy for final class is not possible..

Case of Java Sun library which for JOAFIP have built-in specific input/output in file for final classes

primitive type object

other useful class

Solutions to persist instance of final class:

public method can not be final

If a public method is final it can not be overridden to add method call interception to set object state reading in file.

Solutions:

In some case it is not necessary to override the method to set object state. It is possible to force enhance invoking setForceEnhance of IFilePersistence.

It is possible to disable lazy load for this class using annotation StoreNoLazyLoad or invoking setNoLazyLoad of IFilePersistence

persistence of inner class do not works ONLY BEFORE JOAFIP 2.0.0

Test with cglib show problems ... ( cglib no more used since joafip 2.0.0 )


class DataClass {

.....
private class InnerDataClass {

.....
private int value;
.....

}
..... 
private int value1;
..... 
private InnerDataClass value2;
.....

}


Solutions:

     

class with state in transient field are not optimized for persistence

Case of java sun library wich for JOAFIP have builtin substitute class:

for some of these class ( HashMap ), the standard serialization call an initialization function to set the transient field state. The use of standard serialization mechanism by JOAFIP works, but make loose benefit of lazy load.


Solutions:

class of object comparison

It is not possible for programmer to use  strict comparison for object type as:

x.getClass() == A.class or x.getClass().equals(A.class)

x.getClass() may return the proxy class, subclass of original class, so the comparison will fail.

direct field access consideration

private field

It is possible in a class X code to access directly to private member of an other class X instance. The problem is that this instance can be a not loaded proxy.

reading field

In case of read access the field can be not initialized (object state not loaded). The only way to solve the problem is to call public getter instead of direct field access for read.

Example below for field reading in the equals() implementation.

public class MyClass {

private byte[] value;
....................................

// @Override
public boolean equals(final Object object) {

final boolean equals;
if (object == this) {

equals = true;

} else {

/*
 * use "object instanceof MyClass" since can be a proxy
 */
//if (object instanceof MyClass) { 
if (object.getClass().isAssignableFrom(MyClass.class))

final MyClass myClass = (MyClass) object;
/*
 * use myclass.getValue() instead of myclass.value to load state if
 * object is a proxy
 */
equals =  Arrays.equals(value, myClass.getValue());

} else {

equals = false;

}

}
return equals;

}

writing field

In case of write access on a not loaded object state the value writed will be loose when object state is loaded. The only way to solve the problem is to call public setter instead of direct field access for write.

public field

It is possible in a class X code to access directly to public member of an other class Y instance. The problem is that this instance can be a not loaded proxy.

reading field

In case of read access the field can be not initialized (object state not loaded). The only way to solve the problem is to call public getter instead of direct field access.

writing field

In case of write access on a not loaded object state the value writed will be loose when object state is loaded. The only way to solve the problem is to call public setter instead of direct field access for write.

reflection

No problems for public method invocation. But reading or writing object field can be done on not loaded object. To solve this a call to ProxyManager2#forceload ensure right state of object.

private method invocation

It is possible in a class X to invoke directly a private method of an other class X instance. The problem is that this instance can be a not loaded proxy, so the classe's fields can be not initialized. The only way to solve the problem is to make the method protected or public.

use of reflection

It is not possible to use reflection to access fields of persisted object because it does not force the object loading, values read can be wrong and writed values loose.
The class obtains using clazz=object.getClass() can return the object proxy class, not the original class of object, so clazz.getDeclaredFields() will return fields of proxy, not the fields of proxied object.

Help for discover the problems

1) test in memory with small amount of data

create a file persistence where data are managed in memory instead of file and without proxy
  

import net.sf.joafip.heapfile.service.HeapMemoryDataManagerMock
IHeapDataManager dataManager = new HeapMemoryDataManagerMock();
filePersistence = new FilePersistence(dataManager, false);

2) test in file without proxy

create a file persistence where data are managed in file and without proxy

filePersistence = new FilePersistence(path, false);

3) test in normal use ( in file with proxy )

final FilePersistenceBuilder builder = new FilePersistenceBuilder();
builder.setPathName(path);
builder.setProxyMode(true);//optionnaly
filePersistence = builder.build();



feedback / send your comments
mail to luc peuvrier
chat channel
joafip users mailing list
forums



Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.
© 2007-2012, joafip