[英]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>
為您的內部表示使用具體的 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.