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

RETOUR A L'INDEX
RETOUR AUX CARACTERISTIQUES

In English

POJO persistants de JOAFIP

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.

JOAFIP utilise une façon générique de persister les objets dans le fichier:

specific input/output

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


java.util.Vector
stocké nativement sans substitution.

_Les differentes contraintes pour les POJO JOAFIP:

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.

les classes ne doivent pas être "final"

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:

les méthodes public ne peuvent être 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

la persistance des classes internes ne marche pas SEULEMENT AVANT JOAFIP 2.0.0

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:

les classes avec leur état dans un champ "transient" ne sont pas optimum pour la persistance

Cas des librairies java sun pour lequels JOAFIP a des classes de substitution en interne:

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:

class of object comparison

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.

considerations sur l'accès direct aux champs

private field

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.

lecture d'un champ

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;

}

ecriture d'un champ

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.

public field

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.

lecture du champ
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.
ecriture du champ

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.

reflection

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.

invocation de méthode privé

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.

utilisation de l'introspection "reflection"

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é.

Aide pour découvrir les problèmes

1) faire des tests en mémoire avec une petite quantité de données

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);

2) tester dans un fichier sans proxy

créer une gestion de persistance où les données sont dans un fichier mais sans utilisation de proxy

filePersistence = new FilePersistence(path, false);

3) tester dans le cas normal ( en fichier et avec 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