[JAVA] Point 86: mettre en œuvre sérialisable avec beaucoup de prudence

86. Soyez très prudent lors de la mise en œuvre de Serializable

Coût pour le rendre sérialisable

La sérialisation peut être effectuée en quelques secondes, mais elle peut être très coûteuse à long terme.

L'implémentation de Serializable perd la flexibilité de changer la classe d'implémentation une fois publiée

Le fait que la classe implémente Serializable signifie que la version codée bytestream (ci-après la forme sérialisée) devient une partie de l'API publiée. Une fois qu'une classe est publiée, il est nécessaire de la prendre en charge pour toujours. En outre, dans le formulaire sérialisé par défaut non personnalisé, les champs privés font également partie de l'API publique, rendant la conception qui minimise les champs accessibles (Item15) sans signification.

Si vous acceptez le formulaire sélialisé par défaut et modifiez ultérieurement la représentation interne de la classe, des modifications incompatibles se produiront. Des problèmes se produisent lorsque le client sérialise une instance avec une ancienne version de la classe et la désérialise avec une version plus récente de la classe. Il est possible de faire la conversion, mais c'est difficile et rend le code sale. Lors de l'implémentation de Serializable, il est nécessaire d'envisager une utilisation à long terme et d'essayer d'en concevoir une de haute qualité (Item87,90).

À titre d'exemple des restrictions imposées à l'implémentation de Serializable, l'UID de la version série est impliqué. Toutes les classes Serializable ont un numéro UID de version série pour faire leurs preuves. (** Il semble identifier si la version de la classe est différente avant et après la restauration. **) (http://www.ne.jp/asahi/hishidama/home/tech/java/serial.html) Si vous ne le définissez pas comme un champ long final statique, il sera automatiquement alloué au moment de l'exécution. Cette valeur est affectée par le nom de la classe, les membres, etc., et si quelque chose est changé, cette valeur changera également. Si vous ne définissez pas d'UID et que la compatibilité est rompue, une exception InvalidClassException se produira au moment de l'exécution.

La mise en œuvre de Serializable augmente le potentiel de bogues et de failles de sécurité

La désérialisation est comme un "constructeur invisible". Il est facile d'oublier qu'il faut garantir l'invariant établi par le constructeur et empêcher un attaquant d'accéder à l'objet en cours de construction car il est invisible. S'appuyer sur le mécanisme de désérialisation par défaut peut facilement détruire ou obtenir un accès non autorisé à un invariant.

L'implémentation de Serializable augmente l'effort requis pour publier une nouvelle version de la classe

Lorsqu'une classe qui implémente Serializable est révisée, il est nécessaire de vérifier si l'instance de la nouvelle version peut être sérialisée, l'ancienne version peut être désérialisée, et vice versa. Par conséquent, le nombre de cas de test augmente proportionnellement au produit du nombre de versions et de la classe d'implémentation de sérialisation. Les exigences de test peuvent être réduites si la première édition de la classe d'implémentation Serializable est soigneusement conçue et incluse (Item87,90).

L'implémentation de Serializable n'est pas facile à décider

L'implémentation de Serializable est essentielle pour intégrer des classes dans des frameworks qui utilisent la sérialisation Java pour le transport et la persistance d'objets. En outre, l'implémentation de Serializable le rend facile à gérer en tant que composant d'autres classes. Cependant, comme mentionné ci-dessus, il existe divers coûts associés à la mise en œuvre de Serializable. Lors de la conception des classes, ils doivent être pesés.

Historiquement, les classes de valeur telles que les classes BigInteger et Instant implémentent Serializable, mais rarement dans les classes qui représentent des entités actives telles que le pool de threads.

Les classes et interfaces conçues pour l'héritage sont basiques, implémentent Serializable, ne doivent pas être héritées

Briser cette règle impose un lourd fardeau aux sous-classes de cette classe. En tant qu'exception à cette règle, il est compréhensible que les classes et les interfaces qui existent dans le framework qui nécessitent une implémentation Serializable pour tout ce qui est impliqué implémentent Serializable. Throwable et Component implémentent Serializable. Throwable implémente Serializable, afin que RMI puisse lever des exceptions du serveur vers le client. Puisque le composant implémente Serializable, les éléments GUI sont transportés et enregistrés. Cette fonctionnalité n'a pas été beaucoup utilisée à l'apogée de Swing et AWT.

Soyez prudent lors de l'implémentation d'une classe sérialisable, extensible et comportant des champs

Les sous-classes ne doivent pas remplacer la méthode finalize s'il existe une variante dans le champ d'instance. Sinon, il y a un risque d'attaque du finalizer (Item8).

De plus, si l'invariant de la classe est corrompu par l'initialisation du champ d'instance, il est nécessaire d'ajouter la méthode readObjectNoData.

private void readObjectNoData()
     throws ObjectStreamException;

(** Mystère ici **)

Précautions quand il devient non sérialisable

L'écriture de sous-classes sérialisables est plus fastidieuse lorsque vous choisissez de ne pas les rendre sérialisables dans votre classe d'héritage. La désérialisation normale de telles classes nécessite un constructeur sans argument avec accès à la superclasse. Si cela n'est pas disponible, utilisez le modèle de proxy de sérialisation (élément 90).

La classe interne ne doit pas implémenter Serializable

La classe interne utilise des champs synthétiques. Les champs synthétiques sont générés par le compilateur et contiennent une référence à l'instance englobante et une référence à une variable locale de la portée englobante.

Comme la forme de sérialisation pour les champs synthétiques n'est pas définie, les implémentations sérialisables dans les classes internes doivent être évitées. Cependant, les classes membres statiques peuvent être implémentées Serializable.

Recommended Posts

Point 86: mettre en œuvre sérialisable avec beaucoup de prudence
Implémenter GraphQL avec Spring Boot
reload jCaptcha implémenté avec ajax