Why java.util.Optional is not Serializable, how to serialize the object with such fields
This answer is in response to the question in the title, "Shouldn't Optional be Serializable?" The short answer is that the Java Lambda (JSR-335) expert group considered and rejected it. That note, and this one and this one indicate that the primary design goal for Optional
is to be used as the return value of functions when a return value might be absent. The intent is that the caller immediately check the Optional
and extract the actual value if it's present. If the value is absent, the caller can substitute a default value, throw an exception, or apply some other policy. This is typically done by chaining fluent method calls off the end of a stream pipeline (or other methods) that return Optional
values.
It was never intended for Optional
to be used other ways, such as for optional method arguments or to be stored as a field in an object. And by extension, making Optional
serializable would enable it to be stored persistently or transmitted across a network, both of which encourage uses far beyond its original design goal.
Usually there are better ways to organize the data than to store an Optional
in a field. If a getter (such as the getValue
method in the question) returns the actual Optional
from the field, it forces every caller to implement some policy for dealing with an empty value. This will likely lead to inconsisent behavior across callers. It's often better to have whatever code sets that field apply some policy at the time it's set.
Sometimes people want to put Optional
into collections, like List<Optional<X>>
or Map<Key,Optional<Value>>
. This too is usually a bad idea. It's often better to replace these usages of Optional
with Null-Object values (not actual null
references), or simply to omit these entries from the collection entirely.
NotSerializableException for java.util.Optional with Jackson
Yes, Optional
is not Serializable
. JPA attempts to serialize non-text (anything but String
, char[]
or Char[]
) fields marked with @Lob
.
The recommended approach would be using a JPA converter to serialize the object into a Json while persisting and deserialize the persisted Json on reads. Jackson supports serializing Optional fields, you just have to add jackson-datatype-jdk8
dependency and register Jdk8Module
on your ObjectMapper
.
A GradeConverter
implementation looks like this:
@Converter
public class GradeConverter implements AttributeConverter<Grade, String> {
private ObjectMapper objectMapper;
public GradeConverter() {
objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk8Module());
}
@Override
public String convertToDatabaseColumn(Grade grade) {
if (grade == null) {
return null;
}
return objectMapper.writeValueAsString(grade);
}
@Override
public Grade convertToEntityAttribute(String s) {
if (s == null) {
return null;
}
return objectMapper.readValue(s, Grade.class);
}
}
And on your Grade
field:
@Convert(converter = GradeConverter.class)
private Grade grade;
If you insist on serializing the field (I mean Java serialization), you should provide custom serialization methods.
You could read more about that here.
OptionalT as a Record Parameter in Java
I would not attempt to explain why the current version of IntelliJ doesn't issue a warning for a record having optional fields (that's a question for developers of the IDE).
In this post, I'm addressing the question regarding recommended practices of using Optional
, in particular with Java 16 Records.
Does the practice of not using
Optional<T>
types as parameters/fields not apply to record parameters
Firstly, Optional
is not intended to be used as a field type, for that reason Optional
doesn't implement Serializable
(see). Secondly, records are data-carriers, their fields are final
. Hence, if a record gets initialized with optionals that are empty, they would stay empty throughout all its time-span.
Usage of Optional
Here's a quote from the answer by @StuartMarks, Java and OpenJDK developer, regarding what Optional
is meant to be used for:
The primary use of
Optional
is as follows:Optional is intended to
provide a limited mechanism for library method return types where
there is a clear need to represent "no result," and where using null
for that is overwhelmingly likely to cause errors.
The only valid usage for Optional is returning it from a method where it was originated. And the caller should immediately unpack the optional (API offers plenty of methods for that). But if you're passing the optional object around and storing it somewhere, then what you're doing isn't a good practice.
Optional is not meant for
Optional is not meant to be used:
- As a field type;
- As a type of the method parameter;
- To be stored in a
Collection
; - Or utilized to perform null-checks. Substituting explicit null-check with
Optional.ofNullable()
is an antipattern.
Here's a quote from the answer by @Brian Goetz, Java Language Architect
(Should Java 8 getters return optional type?):
Of course, people will do what they want...
For example, you probably should never use it for something that
returns an array of results, or a list of results; instead return an
empty array or list. You should almost never use it as a field
of something or a method parameter.
Also, have a look at this answer by StuartMarks, here's a small quote:
having an
Optional
in a class field or in a data structure, is considered a misuse of the API. First, it goes against the main design goal of Optional as stated at the top. Second, it doesn't add any value.
Records are Transparent carriers for Immutable data
An object with Optional fields forces the one who deals with it always take into consideration that the object obtained via a getter isn't a value, but potentially empty optional, which might throw NoSuchElementException
if you blindly invoke get()
on it.
Also, having fields of Optional type in a Record is in contradiction with the general concept of Records.
Here's a definition of Record from the JEP 395:
records, which are classes that act as transparent carriers for immutable data. Records can be thought of as nominal tuples.
A record with Optional fields is no longer transparent, because we're not able to get a value directly from it via accessor method.
Since record fields are immutable, it doesn't make sense to store potentially empty optionals as record properties, it almost the same as storing null-references. Because fields in a record can't be changed, an empty optional will remain empty, and some of your tuples might not contain useful data at all.
There's no advantage in passing around optionals, storing them inside records in order to find out at a later point in time that they don't contain the actual data.
Instead, you have to extract a value (if present) from an Optional object obtained from somewhere right on the spot before creating a record.
Sonar Make transient or serializable error
The Map
interface does not extend the Serializable
interface, which is why Sonar is warning you.
When serializing an instance of Test
, you must choose whether or not you want otherProperties
to be serialized.
If you don't want to serialize otherProperties
, then the field should be marked as transient
:
private transient Map<String, Object> otherProperties;
Otherwise, you can change the type of otherProperties
to an implementation of Map
that implements Serializable
, such as HashMap
.
Can Java's XMLEncoder serialize objects that have non-serializable fields?
Doesn't that mean that
XMLEncoder
can serialize non-serializable objects such as ajavafx.scene.[paint.]color
if it is a field inside a JavaBean?
No. It means that it can serialize non-serializable objects such as a javafx.scene.paint.color
if they also observe the JavaBeans conventions, and provided their object-valued attributes do likewise, and so on until closure.
In this case, javafx.scene.paint.color
didn't have a no-args constructor. The fact that java.awt.Color
worked was due to it observing the JavaBeans conventions, not to its being Serializable
.
Related Topics
What Does an Assignment Expression Evaluate to in Java
Detecting Collision of Two Sprites That Can Rotate
What Does the "Assert" Keyword Do
Create a Autocompleting Textbox in Java with a Dropdown List
Bigdecimal Equals() Versus Compareto()
Pass String as Params from One Java App to Another
Persistence Unit as Resource_Local or Jta
Multiple Java Versions Running Concurrently Under Windows
How to Change the Dock Icon of a Java Program
Why Jscrollpane in Joptionpane Not Showing All Its Content
Mockito:How to Verify Method Was Called on an Object Created Within a Method
Make Arraylist.Toarray() Return More Specific Types
Why Doesn't Java Allow Generic Subclasses of Throwable
How to Convert String to Date Without Knowing the Format