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