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.
there is no requirement that the classes implements Serializable or Externalizable
if the class implements Serializable or Externalizable, then JOAFIP uses the standard Java mechanism to create and read object state data record.
JOAFIP overrides ObjetOutputStream to write in data record
JOAFIP overrides ObjetInputStream to read from data record
to write object in file, JOAFIP creates a data record containing the state of the object. The data record contains all the non transient field values: primitive type field value, and a record identifier referencing a non primitive object ( in most cases it is an other persistent POJO ).
to create object from its state stored in file data record, JOAFIP creates a proxy. The object state is set from file record data only when needed ( lazy load ). To do that, the proxy intercepts a method calls to set the state of the object.
The transient and static fields are not persisted.
can store object in serialized form ( compressed of not, you are encourage to use GZIP format ).
specific state reading and writing ( with loose usage of proxy for these objects )
substitution class ( same interface with an implementation using only JOAFIP persistent POJO )
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.
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.
persistence of inner class do not work (WORKS SINCE JOAFIP 2.0.0)
class with state in transient field are not optimum for persistence
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
Byte
other useful class
Solutions to persist instance of final class:
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
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:
use joafip 2.0.0 and next release !
modify your code externalizing the inner class
create a specific input/output or a substitute class works
disable lazy load for this class using annotation StoreNoLazyLoad or invoking setNoLazyLoad of IFilePersistence
Case of java sun library wich for JOAFIP have builtin substitute class:
PArrayList for ArrayList
PHashTable for HashTable
PLinkedHashMap for HashMap and LinkedHashMap
PLinkedHashSet for LinkedHashSet
PLinkedList for LinkedList
PPriorityQueue for PriorityQueue
PTreeSet for TreeSet
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:
modify your code to guarantee that setting the field value is sufficient to restore the object state
create a specific input/output or a substitute class works
use java standard serialization mechanism
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.
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.
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;
}
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.
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.
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.
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.
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.
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.
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.
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);
create a file persistence where data are managed in file and without proxy
filePersistence = new FilePersistence(path, false);
final
FilePersistenceBuilder builder = new
FilePersistenceBuilder();
builder.setPathName(path);
builder.setProxyMode(true);//optionnaly
filePersistence
= builder.build();
feedback
/ send your comments
chat
channel
joafip
users mailing list
forums