如何处理Findbugs“可序列化类中的非瞬态非可序列化实例字段”?

时间:2011-02-01 10:08:11

标签: java serialization 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”)。我的实际代码中有很多集合和列表,我担心它会丢失我的代码太多了。

有更好的方法吗?

8 个答案:

答案 0 :(得分:28)

  

然而,编码是最佳做法   反对接口而不是具体   的实施方式。

我提出不,在这种情况下不是。 Findbugs非常正确地告诉您,只要您在该字段中具有不可序列化的NotSerializableException实施,就有可能遇到Set。这是你应该处理的事情。怎么样,这取决于你的课程设计。

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

答案 1 :(得分:11)

我知道这是一个已经回答过的旧问题,但其他人知道,如果你没有兴趣序列化那个能解决你的FindBugs错误的特定字段,你可以将Set<Integer>字段设置为瞬态。 / p>

public class TestClass implements Serializable {

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

}

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

答案 2 :(得分:9)

您可以通过向您的班级添加以下方法来删除这些Critical警告消息:

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

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

答案 3 :(得分:8)

您可以使用捕获帮助程序来确保传入的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,而无需检查/需要特定的实现细节。

答案 4 :(得分:6)

我使用findbugs-exclude过滤器来收集字段:

<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

答案 5 :(得分:1)

为内部表示使用具体的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);
    }
}

答案 6 :(得分:0)

对于可序列化类中的受保护字段,我发出了高警告。为该字段添加瞬态解决了我的问题:

 protected transient Object objectName;

答案 7 :(得分:-1)

如果您使用的是findbugs-maven-plugin并且必须持久化字段,并且该字段是未实现Serializable接口的类,例如,具有在第三方中定义的类的字段。您可以为findbugs手动配置排除文件,

如果这是唯一的情况,请将其添加到排除文件中: POM:

    RouterModule.forChild(dfqRoutes),    

exclude.xml:

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

实体:

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

虽然我不明白为什么添加@Entity public class Foo extends Boo { StateMachineContext<A, B> stateMachineContext; 不起作用。此外,我不同意在<Bug category="SE_BAD_FIELD"/>这样的字段上添加注释的解决方案,因为构建工具最好不要渗透业务代码。maven plugin usage&amp; findbugs filters both include and exclude

关于 SE_BAD_FIELD:可序列化类中的非瞬态非序列化实例字段,我认为它不应该检查实体。因为,@edu.umd.cs.findbugs.annotations.SuppressWarnings(justification="No bug", values="SE_BAD_FIELD")提供了将字段序列化的方法(实现Serializable是一个内部方法来序列化)。