Perché java.util.Optional non è serializzabile, come serializzare l’object con tali campi

La class Enum è serializzabile quindi non c’è alcun problema di serializzare oggetti con enumerazioni. L’altro caso è dove la class ha campi di class java.util.Optional. In questo caso viene generata la seguente eccezione: java.io.NotSerializableException: java.util.Optional

Come affrontare tali classi, come serializzarle? È ansible inviare tali oggetti a EJB remoto o tramite RMI?

Questo è l’esempio:

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 value = Optional.empty(); public void setValue(Integer i) { this.i = Optional.of(i); } public Optional getValue() { return value; } } //java.io.NotSerializableException is thrown @Test public void serialize() { My my = new My(); byte[] bytes = toBytes(my); } public static  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); } } } 

Questa risposta è in risposta alla domanda nel titolo, “Non dovrebbe essere opzionale Serializable?” La risposta breve è che il gruppo di esperti Java Lambda (JSR-335) ha preso in considerazione e respinto . Quella nota e questa e questa indicano che l’objective di progettazione principale per Optional deve essere utilizzato come valore di ritorno delle funzioni quando un valore di ritorno potrebbe essere assente. L’intento è che il chiamante verifichi immediatamente l’ Optional ed estrae il valore effettivo se è presente. Se il valore è assente, il chiamante può sostituire un valore predefinito, generare un’eccezione o applicare altri criteri. Ciò viene in genere eseguito concatenando chiamate di metodi fluidi alla fine di una pipeline di stream (o altri metodi) che restituiscono valori Optional .

Non è mai stato previsto che Optional possa essere utilizzato in altri modi, ad esempio per gli argomenti del metodo facoltativi o per essere archiviato come campo in un object . E per estensione, rendere serializzabile Optional consente di memorizzarlo in modo persistente o trasmetterlo attraverso una rete, entrambe le quali incoraggiano usi che vanno ben oltre il suo objective di progettazione originale.

Di solito ci sono modi migliori per organizzare i dati piuttosto che memorizzare un Optional in un campo. Se un getter (come il metodo getValue nella domanda) restituisce l’effettivo Optional dal campo, forza ogni chiamante ad implementare alcuni criteri per gestire un valore vuoto. Ciò probabilmente porterà a comportamenti inconsistenti tra i chiamanti. Spesso è meglio avere il codice impostato in quel campo per applicare una politica al momento della sua impostazione.

A volte le persone vogliono inserire Optional in raccolte, come List> o Map> . Anche questa è di solito una ctriggers idea. Spesso è meglio sostituire questi usi di Optional con valori Null-Object (non riferimenti null effettivi), o semplicemente omettere queste voci dalla collezione interamente.

Molti problemi relativi alla Serialization possono essere risolti disaccoppiando il modulo serializzato persistente dall’attuale implementazione di runtime su cui operate.

 /** The class you work with in your runtime */ public class My implements Serializable { private static final long serialVersionUID = 1L; Optional value = Optional.empty(); public void setValue(Integer i) { this.value = Optional.ofNullable(i); } public Optional getValue() { return value; } private Object writeReplace() throws ObjectStreamException { return new MySerialized(this); } } /** The persistent representation which exists in bytestreams only */ final class MySerialized implements Serializable { private final Integer value; MySerialized(My my) { value=my.getValue().orElse(null); } private Object readResolve() throws ObjectStreamException { My my=new My(); my.setValue(value); return my; } } 

La class Optional implementa un comportamento che consente di scrivere un buon codice quando si tratta di valori potenzialmente assenti (rispetto all’uso di null ). Ma non aggiunge alcun vantaggio a una rappresentazione persistente dei tuoi dati. Renderebbe i tuoi dati serializzati più grandi …

Lo schizzo sopra potrebbe sembrare complicato, ma è perché dimostra il modello con una sola proprietà. Più proprietà la tua class ha tanto più deve essere rivelata la sua semplicità.

E non dimenticare, la possibilità di cambiare completamente l’implementazione di My senza la necessità di adattare la forma persistente …

Se si desidera un opzionale serializzabile, si consideri invece l’uso facoltativo di guava che è serializzabile.

È una curiosa omissione.

Dovresti contrassegnare il campo come transient e fornire il tuo metodo writeObject() che ha scritto il risultato get() stesso e un metodo readObject() che ha ripristinato l’ Optional leggendo il risultato dallo stream. Senza dimenticare di chiamare rispettivamente defaultWriteObject() e defaultReadObject() .

La libreria Vavr.io (ex Javaslang) ha anche la class Option che è serializzabile:

 public interface Option extends Value, Serializable { ... }