Question

J'utilise Java 1.4 avec Log4J.

Certains de mes codes impliquent de sérialiser et de désérialiser des objets de valeur (POJO).

Chacun de mes POJO déclare un enregistreur avec

private final Logger log = Logger.getLogger(getClass());

Le sérialisateur se plaint que org.apache.log4j.Logger n'est pas sérialisable.

Dois-je utiliser

private final transient Logger log = Logger.getLogger(getClass());

à la place?

Était-ce utile?

La solution

Pourquoi ne pas utiliser un enregistreur statique? Ou avez-vous besoin d'une référence de consignateur différente pour chaque instance de la classe? Les champs statiques ne sont pas sérialisés par défaut; vous pouvez explicitement déclarer les champs à sérialiser avec un tableau privé, statique, final de ObjectStreamField nommé serialPersistentFields . Voir la documentation Oracle

Contenu ajouté: Lorsque vous utilisez getLogger (getClass ()) , vous utiliserez le même enregistreur dans chaque cas. Si vous souhaitez utiliser un enregistreur distinct pour chaque instance, vous devez différencier le nom de l'enregistreur dans la méthode getLogger (). par exemple. getLogger (getClass (). getName () + hashCode ()). Vous devez ensuite utiliser l'attribut transitoire pour vous assurer que le consignateur n'est pas sérialisé.

Autres conseils

L’enregistreur doit être statique; cela le rendrait non sérialisable.

Il n'y a aucune raison de rendre l'enregistreur non statique, à moins que vous n'ayez une raison sérieuse de le faire.

Si vous voulez réellement adopter l'approche transitoire, vous devez réinitialiser le journal lorsque votre objet est désérialisé. Pour ce faire, vous devez implémenter la méthode:

 private void readObject(java.io.ObjectInputStream in) 
   throws IOException, ClassNotFoundException;

Les javadocs de Serializable contient des informations. sur cette méthode.

Votre mise en oeuvre ressemblera à quelque chose comme:

 private void readObject(java.io.ObjectInputStream in) 
     throws IOException, ClassNotFoundException {
   log = Logger.getLogger(...);
   in.defaultReadObject();
 }

Si vous ne le faites pas, le journal sera nul après la désérialisation de votre objet.

Déclarez votre champ enregistreur comme statique ou transitoire.

Dans les deux cas, la méthode writeObject () ne tentera pas d'écrire le champ dans le flux de sortie lors de la sérialisation.

Habituellement, les champs de journalisation sont déclarés statiques, mais si vous avez besoin que ce soit un champ d'instance, déclarez-le transitoire, comme c'est habituellement le cas pour tout champ non sérialisable. Lors de la désérialisation, le champ de journalisation sera null, cependant, vous devez donc implémenter une méthode readObject () pour l’initialiser correctement.

Essayez de rendre l’enregistreur statique à la place. Vous n'avez pas à vous soucier de la sérialisation car elle est gérée par le chargeur de classes.

Ce type de cas, en particulier dans les EJB, est généralement mieux géré via l’état local du thread. En règle générale, le cas d'utilisation est comme si une transaction particulière rencontrait un problème et que vous deviez passer la journalisation au débogage pour cette opération afin de pouvoir générer une journalisation détaillée de l'opération à l'origine du problème. Transportez un état local de thread à travers la transaction et utilisez-le pour sélectionner le bon enregistreur. Franchement, je ne sais pas où il serait avantageux de définir le niveau sur une INSTANCE dans cet environnement car le mappage des instances dans la transaction devrait être une fonction de niveau conteneur, vous ne pourrez pas réellement contrôler quelle instance est utilisée dans un environnement. transaction donnée quand même.

Même dans les cas où vous traitez avec un DTO, il n’est généralement pas judicieux de concevoir votre système de telle sorte qu’une instance donnée soit requise, car la conception peut facilement évoluer de manière à en faire un mauvais choix. . Vous pourriez arriver dans un mois et décider que des considérations d'efficacité (mise en cache ou toute autre optimisation visant à modifier le cycle de vie) briseront votre hypothèse concernant la mise en correspondance d'instances en unités de travail.

Si vous voulez que le Logger soit par instance, alors oui, vous voulez le rendre transitoire si vous voulez sérialiser vos objets. Les enregistreurs Log4J ne sont pas sérialisables, pas dans la version de Log4J que j'utilise de toute façon. Par conséquent, si vous ne rendez pas les champs de l'enregistreur temporaires, vous obtiendrez des exceptions lors de la sérialisation.

Les enregistreurs n'étant pas sérialisables, vous devez utiliser transitoire pour les stocker dans des champs d'instance. Si vous souhaitez restaurer l’enregistreur après la désérialisation, vous pouvez stocker le niveau (chaîne) indide de votre objet qui sera sérialisé.

Il existe de bonnes raisons d'utiliser un enregistreur d'instance. Un très bon cas d’utilisation consiste à déclarer le logger dans une super-classe et à l’utiliser dans toutes les sous-classes (le seul inconvénient est que les journaux de la super-classe sont attribués à la sous-classe, mais il est généralement facile de les enregistrer. voir ça).

(Comme d'autres l'ont déjà mentionné, utilisez statique ou transitoire).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top