web-dev-qa-db-ja.com

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")を追加できます。実際のコードには非常に多くのセットとリストがあり、コードが散らかるのが怖いです。

もっと良い方法はありますか?

52
Koohoolinn

ただし、具体的な実装ではなく、インターフェイスに対してコーディングすることをお勧めします。

いいえ、この場合はそうではありません。 Findbugsは、そのフィールドに非シリアル化可能なNotSerializableException実装があるとすぐにSetにぶつかるリスクがあることを正確に伝えます。これはあなたが対処すべきものです。方法は、クラスの設計に依存します。

  • これらのコレクションがクラス内で初期化され、外部から設定されない場合、フィールドは実装の詳細であるため、フィールドの具象型を宣言することに何の問題もありません。パブリックインターフェイスでインターフェイスタイプを使用してください。
  • コレクションがパブリックインターフェイスを介してクラスに渡される場合、それらが実際にSerializableであることを確認する必要があります。それを行うには、インターフェースSerializableSet extends Set, Serializableを作成し、それをフィールドに使用します。次に、次のいずれか:
    • パブリックインターフェイスでSerializableSetを使用し、それを実装する実装クラスを提供します。
    • instanceof Serializableを介してクラスに渡されたコレクションを確認し、そうでない場合は、何かにコピーします。
28

これはすでに答えられている古い質問ですが、他の人が知っているように、Set<Integer>フィールドは、FindBugsエラーを修正する特定のフィールドをシリアル化することに興味がない場合は一時的です。

public class TestClass implements Serializable {

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

}

APIのユーザーに具体的な型へのキャストを強制するのではなく、このメソッドの方が好きです。それが内部的なものである場合を除き、Michael Borgwardtの答えはより意味があります。

12
Graham

これらのCritical警告メッセージを取り除くには、クラスに次のメソッドを追加します。

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

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

キャプチャヘルパーを使用して、渡されたSetが2つのインターフェイスをサポートしていることを確認できます。

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を使用できます。

8
jontejj

コレクションフィールドに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 を参照してください

7
brabenetz

内部表現には具体的な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);
    }
}
1
Paul Croarkin