Files
codeql/java/ql/src/Likely Bugs/Serialization/NonSerializableField.qhelp
Marcono1234 e21cbe82a9 Update Java documentation links to Java 11
Where possible update Java documentation links to Java 11.
Additionally update some other links to use HTTPS.
2021-02-26 00:43:51 +01:00

77 lines
3.5 KiB
XML

<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
If a serializable class is serialized using the default Java serialization mechanism,
each non-static, non-transient field in the class must also be serializable.
Otherwise, the class generates a <code>java.io.NotSerializableException</code> as its fields are written
out by <code>ObjectOutputStream.writeObject</code>.
</p>
<p>
As an exception, classes that define their own <code>readObject</code> and <code>writeObject</code>
methods can have fields that are not themselves serializable. The <code>readObject</code> and
<code>writeObject</code> methods are responsible for encoding any state in those fields that needs
to be serialized.
</p>
</overview>
<recommendation>
<p>
To avoid causing a <code>NotSerializableException</code>, do one of the following:</p>
<ul>
<li>
<strong>Mark the field as <code>transient</code> : </strong> Marking the field as <code>transient</code> makes the
serialization mechanism skip the field. Before doing this, make sure that the field is not really intended
to be part of the persistent state of the object.
</li>
<li>
<strong>Define custom <code>readObject</code> and <code>writeObject</code> methods for the <code>Serializable</code> class : </strong>
Explicitly defining the <code>readObject</code> and <code>writeObject</code> methods enables you to choose which fields
to read from, or write to, an object stream during serialization.
</li>
<li>
<strong>Make the type of the field <code>Serializable</code> : </strong> If the field is part of the object's persistent state and you wish
to use Java's default serialization mechanism, the type of the field must implement <code>Serializable</code>. When choosing this option,
make sure that you follow best practices for serialization.
</li>
</ul>
</recommendation>
<section title="Example 1">
<p>In the following example, <code>WrongPerformanceRecord</code> contains a field <code>factors</code>
that is not serializable but is in a serializable class. This causes a <code>java.io.NotSerializableException</code>
when the field is written out by <code>writeObject</code>. However, <code>PerformanceRecord</code>
contains a field <code>factors</code> that is marked as <code>transient</code>, so that the serialization
mechanism skips the field. This means that a correctly serialized record is output by <code>writeObject</code>.</p>
<sample src="NonSerializableField.java" />
</section>
<section title="Example 2">
<p>In this second example, <code>WrongPair</code> takes two generic parameters <code>L</code> and <code>R</code>.
The class itself is serializable, but users of this class are not forced to pass serializable objects to its
constructor, which could lead to problems during serialization. The solution is to set upper type bounds for the
parameters, to force the user to supply only serializable objects.
A similar example is the <code>WrongEvent</code> class, which takes a weakly typed <code>eventData</code> object.
A better solution is to force the user to supply an object whose class implements the <code>Serializable</code>
interface.</p>
<sample src="NonSerializableFieldTooGeneral.java" />
</section>
<references>
<li>
Java API Specification:
<a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Serializable.html">Serializable</a>,
<a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/ObjectOutputStream.html">ObjectOutputStream</a>.
</li>
</references>
</qhelp>