Why Java.Util.Optional Is Not Serializable, How to Serialize the Object with Such Fields

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 a javafx.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



Leave a reply



Submit