[英]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.