如何处理Findbugs“在序列化类中的非暂时性不可序列化的实例字段”?

考虑下面的类。 如果我运行findbugs它会给我一个错误(“序列化类中的非瞬时不可序列化的实例字段”)在第5行,但不是第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 } 

这是正确的,因为java.util.Set从不在其层次结构中实现Serializable,java.util.HashSet也不会。 然而,最好的做法是对接口进行编码而不是具体的实现。

我怎样才能最好地处理这个?

我可以在第3行添加一个@Suppresswarnings(justification =“No bug”,values =“SE_BAD_FIELD”)。我在我的实际代码中有很多设置和列表,我恐怕会乱扔我的代码太多。

有更好的方法吗?

但是,最好的做法是对接口进行编码,而不是具体的实现。

我提出不,在这种情况下不是。 Findbugs相当正确地告诉你,只要你在那个字段中有一个不可序列化的Set实现,你就冒着运行到NotSerializableException风险。 这是你应该处理的事情。 怎么样,这取决于你的课程devise。

  • 如果这些集合是在类中初始化的,并且从来没有从外部设置的话,那么我认为声明字段的具体types绝对没有错,因为字段无论如何都是实现细节。 在公共接口中使用接口types。
  • 如果通过公共接口将集合传递给类,则必须确保它们实际上是可Serializable 。 为此,创build一个接口SerializableSet extends Set, Serializable并将其用于您的字段。 然后,要么:
    • 在公共接口中使用SerializableSet ,并提供实现它的实现类。
    • 检查通过instanceof Serializable传递给类的集合,如果它们不是,则将它们复制到某些内容中。

我知道这是一个已经回答的老问题,但是别人知道,如果你不想序列化那个能够解决FindBugs错误的特殊字段,你可以把Set<Integer>字段Set<Integer>为transient。

 public class TestClass implements Serializable { private static final long serialVersionUID = 1905162041950251407L; private transient Set<Integer> mySet; } 

我更喜欢这种方法,而不是强迫你的API的用户投到你的具体types,除非它只是内部的,那么Michael Borgwardt的回答更有意义。

您可以使用捕获帮助程序来确保在Set中传入支持两个接口:

 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); } } 

通过这种方式,您可以拥有一个强制Serializable的公共API,而不需要检查/要求具体的实现细节。

我使用findbugs-excludefilter来收集字段:

 <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> 

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

通过将以下方法添加到您的课堂,您可以摆脱这些Critical警告消息:

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

为您的内部表示使用一个具体的Serializable集合,但是使任何公共接口使用Set接口。

 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); } } 

使用

 private transient Set<Integer> mySet;