考虑下面的课程。如果我对它运行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”)。我的实际代码中有很多集合和列表,我担心它会丢失我的代码太多了。
有更好的方法吗?
答案 0 :(得分:28)
然而,编码是最佳做法 反对接口而不是具体 的实施方式。
我提出不,在这种情况下不是。 Findbugs非常正确地告诉您,只要您在该字段中具有不可序列化的NotSerializableException
实施,就有可能遇到Set
。这是你应该处理的事情。怎么样,这取决于你的课程设计。
Serializable
。为此,请创建一个界面SerializableSet extends Set, Serializable
并将其用于您的领域。然后,要么:
SerializableSet
并提供实现它的实现类。 instanceof Serializable
传递给班级的馆藏,如果不是,请将其复制到相应的内容中。答案 1 :(得分:11)
我知道这是一个已经回答过的旧问题,但其他人知道,如果你没有兴趣序列化那个能解决你的FindBugs错误的特定字段,你可以将Set<Integer>
字段设置为瞬态。 / p>
public class TestClass implements Serializable {
private static final long serialVersionUID = 1905162041950251407L;
private transient Set<Integer> mySet;
}
我更喜欢这种方法,而不是强迫你的API用户投射到你的具体类型,除非它只是内部的,然后Michael Borgwardt的回答更有意义。
答案 2 :(得分:9)
您可以通过向您的班级添加以下方法来删除这些Critical
警告消息:
private void writeObject(ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
}
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
}
答案 3 :(得分:8)
您可以使用捕获帮助程序来确保传入的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,而无需检查/需要特定的实现细节。
答案 4 :(得分:6)
我使用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>
答案 5 :(得分:1)
为内部表示使用具体的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);
}
}
答案 6 :(得分:0)
对于可序列化类中的受保护字段,我发出了高警告。为该字段添加瞬态解决了我的问题:
protected transient Object objectName;
答案 7 :(得分:-1)
如果您使用的是findbugs-maven-plugin并且必须持久化字段,并且该字段是未实现Serializable接口的类,例如,具有在第三方中定义的类的字段。您可以为findbugs手动配置排除文件,
如果这是唯一的情况,请将其添加到排除文件中: POM:
RouterModule.forChild(dfqRoutes),
exclude.xml:
<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 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"/>
这样的字段上添加注释的解决方案,因为构建工具最好不要渗透业务代码。maven plugin usage&amp; findbugs filters both include and exclude
关于 SE_BAD_FIELD:可序列化类中的非瞬态非序列化实例字段,我认为它不应该检查实体。因为,@edu.umd.cs.findbugs.annotations.SuppressWarnings(justification="No bug", values="SE_BAD_FIELD")
提供了将字段序列化的方法(实现Serializable是一个内部方法来序列化)。