La classe Enum est Serializable donc il n'y a aucun problème pour sérialiser un objet avec des enums. L'autre cas est celui où la classe a des champs de la classe java.util.Optional. Dans ce cas, l'exception suivante est levée: java.io.NotSerializableException: java.util.Optional
Comment gérer de telles classes, comment les sérialiser? Est-il possible d'envoyer de tels objets à Remote EJB ou via RMI?
Voici l'exemple:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Optional;
import org.junit.Test;
public class SerializationTest {
static class My implements Serializable {
private static final long serialVersionUID = 1L;
Optional<Integer> value = Optional.empty();
public void setValue(Integer i) {
this.i = Optional.of(i);
}
public Optional<Integer> getValue() {
return value;
}
}
//java.io.NotSerializableException is thrown
@Test
public void serialize() {
My my = new My();
byte[] bytes = toBytes(my);
}
public static <T extends Serializable> byte[] toBytes(T reportInfo) {
try (ByteArrayOutputStream bstream = new ByteArrayOutputStream()) {
try (ObjectOutputStream ostream = new ObjectOutputStream(bstream)) {
ostream.writeObject(reportInfo);
}
return bstream.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
java
serialization
java-8
optional
vanarchi
la source
la source
Optional
était marqué commeSerializable
, que se passerait-il siget()
retournait quelque chose qui n'était pas sérialisable?NotSerializableException,
bien sûr.Réponses:
Cette réponse est en réponse à la question du titre, "L'option facultative ne devrait-elle pas être sérialisable?" La réponse courte est que le groupe d'experts Java Lambda (JSR-335) l'a considérée et rejetée . Cette note, et celle-ci et celle-ci indiquent que l'objectif principal de conception pour
Optional
est d'être utilisé comme valeur de retour des fonctions lorsqu'une valeur de retour peut être absente. L'intention est que l'appelant vérifie immédiatement leOptional
et extrait la valeur réelle si elle est présente. Si la valeur est absente, l'appelant peut remplacer une valeur par défaut, lever une exception ou appliquer une autre stratégie. Cela se fait généralement en chaînant les appels de méthode fluent à la fin d'un pipeline de flux (ou d'autres méthodes) qui renvoient desOptional
valeurs.Il n'a jamais été conçu pour
Optional
être utilisé d'une autre manière, comme pour des arguments de méthode facultatifs ou pour être stocké sous forme de champ dans un objet . Et par extension, rendreOptional
sérialisable lui permettrait d'être stocké de manière persistante ou transmis sur un réseau, ce qui encourage les utilisations bien au-delà de son objectif de conception d'origine.Il existe généralement de meilleures façons d'organiser les données que de les stocker
Optional
dans un champ. Si un getter (tel que lagetValue
méthode dans la question) renvoie le réelOptional
du champ, il force chaque appelant à implémenter une politique pour traiter une valeur vide. Cela entraînera probablement un comportement incohérent entre les appelants. Il est souvent préférable que les jeux de codes de ce champ appliquent une politique au moment où ils sont définis.Parfois, les gens veulent mettre
Optional
dans des collections, commeList<Optional<X>>
ouMap<Key,Optional<Value>>
. Ceci aussi est généralement une mauvaise idée. Il est souvent préférable de remplacer ces utilisations deOptional
par des valeurs Null-Object (pas denull
références réelles ), ou simplement d'omettre complètement ces entrées de la collection.la source
Un grand nombre de
Serialization
problèmes connexes peuvent être résolus en découplant le formulaire sérialisé persistant de l'implémentation d'exécution réelle sur laquelle vous travaillez.La classe
Optional
implémente un comportement qui permet d'écrire du bon code lorsqu'il s'agit de valeurs éventuellement absentes (par rapport à l'utilisation denull
). Mais cela n'ajoute aucun avantage à une représentation persistante de vos données. Cela ne ferait qu'agrandir vos données sérialisées…L'esquisse ci-dessus peut sembler compliquée, mais c'est parce qu'elle montre le modèle avec une seule propriété. Plus votre classe a de propriétés, plus sa simplicité doit être révélée.
Et ne pas oublier, la possibilité de modifier
My
complètement l'implémentation de sans avoir besoin d'adapter la forme persistante…la source
class My
, ce que vous faites généralement car il est également pratique pour d'autres utilisations,readResolve
pourrait être une implémentation sur une seule ligne, réduisant ainsi le passe-partout à une seule ligne par propriété. Ce qui n'est pas grand-chose étant donné que chaque propriété mutable a de toute façon au moins sept lignes de code dans la classeMy
.Si vous souhaitez une option sérialisable, envisagez d'utiliser à la place l'option de goyave qui est sérialisable.
la source
C'est une curieuse omission.
Vous devrez marquer le champ comme
transient
et fournir votre proprewriteObject()
méthode personnalisée qui a écrit leget()
résultat lui-même, et unereadObject()
méthode qui a restauré leOptional
en lisant ce résultat à partir du flux. Sans oublier d'appelerdefaultWriteObject()
etdefaultReadObject()
respectivement.la source
La bibliothèque Vavr.io (anciennement Javaslang) a également la
Option
classe qui est sérialisable:la source
Si vous souhaitez conserver une liste de types plus cohérente et éviter d'utiliser null, il existe une alternative bizarre.
Vous pouvez stocker la valeur à l'aide d'une intersection de types . Couplé à un lambda, cela permet quelque chose comme:
La
temp
séparation de la variable évite de fermer le propriétaire duvalue
membre et donc de trop sérialiser.la source