How to handle a Findbugs "Non-transient non-serializable instance field in serializable class"?

JavaSerializationFindbugs

Java Problem Overview


Consider the class below. If I run Findbugs against it it will give me an error ("Non-transient non-serializable instance field in serializable class") on line 5 but not on line 7.

1 public class TestClass implements Serializable {
2
3  private static final long serialVersionUID = 1905162041950251407L;
4
5  private Set<Integer> mySet;      // Findbugs error
6
7  private HashSet<Integer> myOtherSet;
8
9 }

That's correct because java.util.Set never implements Serializable in its hierarchy and java.util.HashSet does. However it is best practice to code against interfaces instead of concrete implementations.

How can I best handle this?

I can add a @Suppresswarnings(justification="No bug", values="SE_BAD_FIELD") on line 3. I have quite a lot of Sets and Lists in my actual code and I'm afraid it will litter my code too much.

Are there better ways?

Java Solutions


Solution 1 - Java

> However it is best practice to code > against interfaces instead of concrete > implementations.

I submit that no, in this case it is not. Findbugs quite correctly tells you that you risk running into a NotSerializableException as soon as you have a non-serializable Set implementation in that field. This is something you should deal with. How, that depends on the design of your classes.

  • If those collections are initialized within the class and never set from outside, then I see absolutely nothing wrong with declaring the concrete type for the field, since fields are implementation details anyway. Do use the interface type in the public interface.
  • If the collection are passed into the class via a public interface, you have to ensure that they are in fact Serializable. To do that, create an interface SerializableSet extends Set, Serializable and use it for your field. Then, either:
  • Use SerializableSet in the public interface and provide implementation classes that implement it.
  • Check collections passed to the class via instanceof Serializable and if they're not, copy them into something that is.

Solution 2 - Java

I know this is an old question that's already answered but just so others know is that you can set the Set<Integer> field as transient if you have no interest in serializing that particular field which will fix your FindBugs error.

public class TestClass implements Serializable {

    private static final long serialVersionUID = 1905162041950251407L;
    private transient Set<Integer> mySet;

}

I prefer this method instead of forcing users of your API to cast to your concrete type, unless it's just internal, then Michael Borgwardt's answer makes more sense.

Solution 3 - Java

You can get rid of those Critical warning messages by adding the following methods to your class:

private void writeObject(ObjectOutputStream stream)
        throws IOException {
    stream.defaultWriteObject();
}

private void readObject(ObjectInputStream stream)
        throws IOException, ClassNotFoundException {
    stream.defaultReadObject();
}

Solution 4 - Java

You could use a capture helper to ensure that a passed in Set supports two interfaces:

private static class SerializableTestClass<T extends Set<?> & Serializable> implements Serializable
{
	private static final long serialVersionUID = 1L;
	private final T serializableSet;

	private SerializableTestClass(T serializableSet)
	{
		this.serializableSet = serializableSet;
	}
}

public static class PublicApiTestClass
{
	public static <T extends Set<?> & Serializable> Serializable forSerializableSet(T set)
	{
		return new SerializableTestClass<T>(set);
	}
}

In this way you can have a public API that enforces Serializable without checking/requiring specific implementation details.

Solution 5 - Java

I use a findbugs-exclude Filter for collection-Fields:

<Match>
	<Field type="java.util.Map" />
	<Bug pattern="SE_BAD_FIELD" />
</Match>
<Match>
	<Field type="java.util.Set" />
	<Bug pattern="SE_BAD_FIELD" />
</Match>
<Match>
	<Field type="java.util.List" />
	<Bug pattern="SE_BAD_FIELD" />
</Match>

See http://findbugs.sourceforge.net/manual/filter.html

Solution 6 - Java

Use a concrete Serializable set for your internal representation, but make any public interfaces use the Set interface.

public class TestClass implements Serializable {
    private static final long serialVersionUID = 1905162041950251407L;

    private HashSet<Integer> mySet;

    public TestClass(Set<Integer> s) {
	    super();
	    setMySet(s);
    }

    public void setMySet(Set<Integer> s) {
	    mySet = (s == null) ? new HashSet<>() : new HashSet<>(s);
    }
}

Solution 7 - Java

I had HIGH Warning for a protected field in a serializable class. Add transient for the field resolved my problem:

 protected transient Object objectName;

Solution 8 - Java

In case you are using findbugs-maven-plugin and have to persist a field, and that field is a class not implementing Serializable interface, for example, a field that has a class defined in a 3rd party. You can manually configure exclude file for findbugs,

If this is the only case, add it in an exclude file: pom:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>findbugs-maven-plugin</artifactId>
    <version>3.0.3</version>
    <configuration>
          <xmlOutput>true</xmlOutput>
          <xmlOutputDirectory>target/findbugs/</xmlOutputDirectory>
          <excludeFilterFile>findbugs-exclude.xml</excludeFilterFile>
          <includeFilterFile>findbugs-include.xml</includeFilterFile>
          <failOnError>true</failOnError>
    </configuration>
...

exclude.xml:

<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
    <Match>
        <Class name="com.xxx.Foo" /> 
        <Field type="org.springframework.statemachine.StateMachineContext"/>
    </Match>

Entity:

@Entity
public class Foo extends Boo {
    StateMachineContext<A, B> stateMachineContext;

Although I don't understand why adding <Bug category="SE_BAD_FIELD"/> would not work. Besides, I don't agree with the solution of adding annotation on the field like @edu.umd.cs.findbugs.annotations.SuppressWarnings(justification="No bug", values="SE_BAD_FIELD"), because building tools better not penetrate business code.maven plugin usage & findbugs filters both include and exclude

About SE_BAD_FIELD: Non-transient non-serializable instance field in serializable class, I think it should not check on entities. Because, javax.persistence.AttributeConverter offers methods to serialize a field out side (implements Serializable is an inside method to serialize).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKoohoolinnView Question on Stackoverflow
Solution 1 - JavaMichael BorgwardtView Answer on Stackoverflow
Solution 2 - JavaGrahamView Answer on Stackoverflow
Solution 3 - JavaVlad MihalceaView Answer on Stackoverflow
Solution 4 - JavajontejjView Answer on Stackoverflow
Solution 5 - JavaHarald BrabenetzView Answer on Stackoverflow
Solution 6 - JavaPaul CroarkinView Answer on Stackoverflow
Solution 7 - JavaThiago de AndradeView Answer on Stackoverflow
Solution 8 - JavaTiinaView Answer on Stackoverflow