繁体   English   中英

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

[英]How to handle a Findbugs “Non-transient non-serializable instance field in serializable class”?

考虑下面的类。 如果我针对它运行 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")。我的实际代码中有相当多的 Sets 和 Lists,我担心它会让我的代码乱七八糟。

有更好的方法吗?

然而,最佳实践是针对接口而不是具体实现进行编码。

我认为不,在这种情况下不是。 Findbugs 非常正确地告诉您,一旦在该字段中有不可序列化的Set实现,您就有可能遇到NotSerializableException 这是你应该处理的事情。 如何,这取决于您的课程设计。

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

我知道这是一个已经回答过的老问题,但只是让其他人知道,如果您对序列化该特定字段不感兴趣,您可以将Set<Integer>字段Set<Integer>为瞬态字段,这将修复您的 FindBugs 错误。

public class TestClass implements Serializable {

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

}

我更喜欢这种方法,而不是强迫您的 API 用户强制转换为您的具体类型,除非它只是内部类型,否则 Michael Borgwardt 的回答更有意义。

您可以通过将以下方法添加到您的类中来摆脱那些Critical警告消息:

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

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

您可以使用捕获助手来确保传入的 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-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

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

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

 protected transient Object objectName;

如果您正在使用 findbugs-maven-plugin 并且必须保留一个字段,并且该字段是一个未实现 Serializable 接口的类,例如,一个具有在 3rd 方中定义的类的字段。 您可以手动配置 findbugs 的排除文件,

如果这是唯一的情况,请将其添加到排除文件中: 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>
...

排除.xml:

<?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"/>不起作用。 此外,我不同意像@edu.umd.cs.findbugs.annotations.SuppressWarnings(justification="No bug", values="SE_BAD_FIELD")这样在字段上添加注释的解决方案,因为构建工具最好不要渗透业务代码。maven 插件使用findbugs 过滤器包括和排除

关于SE_BAD_FIELD: Non-transient non-serializable instance field in serializable class ,我认为它不应该检查实体。 因为, javax.persistence.AttributeConverter提供了在外部序列化字段的方法(实现 Serializable 是一个内部序列化方法)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM