RETOUR A L'INDEX
RETOUR AUX CARACTERISTIQUES
JOAFIP peut stocker tout type d'objets : voir comment et comment être optimum
Il y a des contraintes
sur le code à cause de l'utilisation des proxies pour le lazy
load, cela peut être
surmonté par la transformation de bytecode du java agent.
Il est conseillé de prendre en compte les contraintes plutôt que
d'utiliser le "java agent" pour des raisons de performances.
Cela n'est possible que si c'est vous qui maitrisez le code des classes
persistantes. Si vous n'avez pas le contrôle du code et qui n'y a pas
de voies de contournement des contraintes, alors la transformation de
byte code est l'ultime solution.
il n'est pas requis que les classes implémentent Serializable ou Externalizable
si la classe implémente Serializable or Externalizable, alors JOAFIP utilise le mécanisme java standard de sérialisation pour créer et lire l'état de l'objet.
JOAFIP redéfinit ObjetOutputStream pour ecrire un enregistrement
JOAFIP redéfinit ObjetInputStream pour lire dans un enregistrement
pour ecrire JOAFIP crée un enregistrement conteant l'état de l'objet. L'enregistrement contient la valeur de tous les champs non transient: valeur pour un type primitif, et identificateur d'enregistrement pour une référence sur un objet ( dans la plupart des cas une autre POJO persisté).
pour crée un objet à partir de l'état de cette objet stocké dans le fichier, JOAFIP crée un proxy. L'état de l'objet est positionné seulement quand cela est nécessaire ( lazy load ).Pour cela le proxy intercept les appels aux méthodes de l'objet pour positionner l'état de l'objet.
Les champs transient et static ne sont pas persistés.
peut stocker sous forme sérialisé ( compressé ou non, le format GZIP est conseillé).
lecture et ecriture spécifiques ( fait perdre l'usage de proxy pour ces objects)
classe de substitution (même interface avec une implementation n'utilisant que des POJO persistant JOAFIP)
substitution
activation : setSubstitutionOfJavaUtilCollection()
Les substitutions fournient sont (principalement les collections):
java.util.LinkedList:
le
substitut est
PLinkedList ,le "synchronizer" est
LinkedListSynchronizer
PTreeList peut être utilisé
java.util.ArrayList:
le
substitut est
PArrayList ,le "synchronizer" est
ArrayListSynchronizer
PTreeList peut être utilisé
java.util.HashSet:
le substitut est PLinkedHashSet , le "synchronizer" est SetSynchronizer
java.util.HashSet:
le substitut est PHashSet ,le "synchronizer" est SetSynchronizer
java.util.LinkedHashSet:
le
substitut est
PLinkedHashSet ,le "synchronizer" est SetSynchronizer
PLinkedTreeSet
a linked tree set (see TreeSet), peut être utilisé si les éléments sont
comparables
java.util.TreeSet:
le substitut est PTreeSet ,le "synchronizer" est SetSynchronizer
java.util.Hashtable:
le substitut est PLinkedHashMap ,le "synchronizer" est MapSynchronizer
java.util.HashMap:
le substitut est PHashMap ,le "synchronizer" est MapSynchronizer
java.util.LinkedHashMap:
le
substitute est
PLinkedHashMap ,le "synchronizer" est MapSynchronizer
PLinkedTreeMap
a linked tree map (see TreeMap), peut être utilisé si les clés sont
comparables
java.util.LinkedHashMap:
le substitut est PLinkedHashMap ,le "synchronizer" est MapSynchronizer
java.util.TreeMap:
le substitut est PTreeMap ,le "synchronizer" est MapSynchronizer
Les liens donnent plus de
détails: raisons et solutions
La solution ultime est l'utilisation du java
agent "anti persistence constraint", mais le contre-coup et
la vitesse d'exécution.
la persistance des classes interes ne marche pas (MARCHE DEPUIS JOAFIP 2.0.0)
les classes avec leur état dans un champs transient ne sont pas optimum pour la persistance
The reason is
that final class
can not be enhanced by derivation.
Cas de la librairie java sun pour lesquel JOAFIP a des
entrées/sorties en fichier spécifiques
primitive type object
autree classe très utile
Solutions pour persister des instances de classe final:
Si une méthode public est
finale elle
ne peut être surchargée pour ajouter l'interception de son appel pour
positionner l'état de l'objet en lisant dans le fichier.
Solutions:
Dans certain cas il n'est peut être pas nécessaire de surcharger la
méthode pour que l'état de l'objet soit positionné. Il est possible de
forcer la création du proxy en invoquant setForceEnhance
de IFilePersistence.
Il est possible de désactiver le "lazy load" pour cette classe en
annotant StoreNoLazyLoad ou en invoquant setNoLazyLoad de
IFilePersistence
Un test avec cglib montre le problème ... ( cglib n'est plus utilisé depuis 2.0.0 )
class
DataClass {
.....
private
class InnerDataClass {
.....
private
int value;
.....
}
.....
private int value1;
.....
private InnerDataClass
value2;
.....
}
Solutions:
utiliser joafip 2.0.0 et versions suivantes !
modifier le code pour externaliser la classe interne
crée une entrées/sortie specifique ou une classe de substitution
désactiver le
"lazy load" pour cette classe en annotant StoreNoLazyLoad
ou en invoquant setNoLazyLoad de IFilePersistence
Cas des librairies java sun pour lequels JOAFIP a des classes de substitution en interne:
PArrayList ou PTreeList pour ArrayList
PHashTable pout HashTable
PLinkedHashMap pour HashMap et LinkedHashMap
PLinkedHashSet pour LinkedHashSet
PLinkedList ou PTressList pour LinkedList
PPriorityQueue pour PriorityQueue
PTreeSet pour TreeSet
Pour certaines classes ( HashMap ), le mécanisme de sérialisation appel une fonction d'initialisation des champs "transient". L'utilisation des mécanismes de sérialisation standard fonctionnent avec JOAFIP, mais fait perdre l'avantage du "lazy load".
Solutions:
modifier le code pour garantir qu'écrire la valeur du champ est suffisant pour positionner l'état de l'objet
crée une entrées/sortie specifique ou une classe de substitution
utiliser le mécanismes de sérialisation standard de java
Il n'est plus possible d'utiliser une comparaison stricte des types des objets comme:
x.getClass() == A.class ou x.getClass().equals(A.class)
x.getClass() peut retourner la classe du proxy, sous classe de la classe d'origine, la comparaison echouera.
Il est possible dans le code de la classe X de diretement accéder à un membre privé d'une autre instance de la classe X. Le problème est que la classe peut ne pas avoir été chargé par le proxy.
Dans le cas d'un accés en
lecture le champ
peut être non initialisé (état de l'objet non chargé). La seule
solution pour résoudre le problème est d'appeler le getter public à la
place de l'accès direct.
Exemple ci-dessous d'une lecture de champ pour l'implémentation
de equals().
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;
}
Dans le cas d'une écriture avec un objet non chargé la valeur ecrite sera perdue au chargement de l'état de l'objet. La seule solution est d'appeler un setter public à la place de l'accès directe au champ.
Il est possible dans le code de la classe X d'accéder directement au champ public d'une autre classe Y.It is possible in a class X code to access directly to public member of an other class Y instance. Le problème est que la classe peut ne pas avoir été chargé par le proxy.
Dans le cas d'une écriture avec un objet non chargé la valeur ecrite sera perdue au chargement de l'état de l'objet. La seule solution est d'appeler un setter public à la place de l'accès directe au champ.
Pas de problèmes avec l'invocation de méthodes publiques. Mais la lecture et l'ecriture de champs peut être fait sur des objets non chargés. Pour résoudre le problème un appel de ProxyManager2#forceload assure l'état correcte de l'objet.
Il est possible dans le code d'une classe X d'invoquer drectement une méthode privé d'une autre instance de la classe X. Le problèmes est cette instance peut ne pas avoir été chargé par le proxy, les champs de la classes ne sont pas initialisés. La seule solution est de déclarer la méthode publique ou protégée.
Il n'est pas possible d'utiliser l'introspection pour accéder
aux
champs d'un objet persisté car cela ne force pas la chargement de
l'objet,
les valeurs lus seront fausses et les valeurs ecrites seront perdues.
La
classe obtenue avec clazz=object.getClass() peut être la
classe de
l'objet proxy, pas la classe original de l'objet,
alors clazz.getDeclaredFields() retournera les champs du
proxy,
pas ceux de l'objet proxié.
crée
une persistence où les objets sont stockés en mémoire plutôt que dans
un fichier et sans utilisation de proxy
import
net.sf.joafip.heapfile.service.HeapMemoryDataManagerMock
IHeapDataManager
dataManager = new HeapMemoryDataManagerMock();
filePersistence =
new FilePersistence(dataManager, false);
créer une gestion de persistance où les données sont dans un fichier mais sans utilisation de proxy
filePersistence = new FilePersistence(path, false);
final FilePersistenceBuilder builder = new
FilePersistenceBuilder();
builder.setPathName(path);
builder.setProxyMode(true);//optionnaly
filePersistence
= builder.build();