java-如何处理Findbugs“可序列化类中的非瞬态不可序列化实例字段”?
考虑下面的类。 如果我对它运行Findbugs,它将在第5行而不是在第7行给我一个错误(“可序列化类中的非瞬态不可序列化实例字段”)。
1 public class TestClass implements Serializable {
2
3 private static final long serialVersionUID = 1905162041950251407L;
4
5 private Set mySet; // Findbugs error
6
7 private HashSet myOtherSet;
8
9 }
这是正确的,因为java.util.Set从未在其层次结构中实现Serializable,而java.util.HashSet却没有实现。但是,最佳实践是针对接口而不是具体的实现进行编码。
我该如何最好地处理呢?
我可以在第3行上添加@Suppresswarnings(justification =“ No bug”,values =“ SE_BAD_FIELD”)。我的实际代码中有很多Sets和Lists,恐怕它会使我的代码乱七八糟。
有更好的方法吗?
7个解决方案
28 votes
但是,最好的做法是进行编码 针对界面而非具体 实现。
我认为不可以,在这种情况下不是。 Findbugs非常正确地告诉您,一旦您在该字段中具有不可序列化的SerializableSet extends Set, Serializable实现,便有可能会遇到instanceof Serializable的风险。 这是您应该处理的事情。 如何,这取决于您的班级设计。
如果这些集合是在类中初始化的,并且从不从外部进行设置,那么声明字段的具体类型绝对不会出错,因为字段无论如何都是实现细节。 不要在公共接口中使用接口类型。
如果将集合通过公共接口传递给类,则必须确保它们实际上是instanceof Serializable。为此,请创建一个接口SerializableSet extends Set, Serializable,并将其用于您的字段。 然后,要么:在公共接口中使用instanceof Serializable,并提供实现它的实现类。
检查通过instanceof Serializable传递给班级的集合,如果不是,则将其复制到实际的集合中。
Michael Borgwardt answered 2020-01-05T16:50:49Z
12 votes
我知道这是一个已经解决的老问题,但是其他人也知道,如果您不希望序列化特定字段来解决FindBugs错误,可以将2689477726226026088960字段设置为瞬态。
public class TestClass implements Serializable {
private static final long serialVersionUID = 1905162041950251407L;
private transient Set mySet;
}
我更喜欢这种方法,而不是强迫API用户将其转换为您的具体类型,除非它只是内部类型,否则Michael Borgwardt的回答更有意义。
Graham answered 2020-01-05T16:51:14Z
9 votes
您可以通过在类中添加以下方法来摆脱那些Critical警告消息:
private void writeObject(ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
}
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
}
Vlad Mihalcea answered 2020-01-05T16:51:39Z
8 votes
您可以使用捕获助手来确保传入的Set支持两个接口:
private static class SerializableTestClass & 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 & Serializable> Serializable forSerializableSet(T set)
{
return new SerializableTestClass(set);
}
}
这样,您可以拥有一个公共API,该API强制执行Serializable,而无需检查/要求特定的实现细节。
jontejj answered 2020-01-05T16:52:03Z
7 votes
我对集合字段使用findbugs-exclude过滤器:
参见[http://findbugs.sourceforge.net/manual/filter.html]
brabenetz answered 2020-01-05T16:52:28Z
1 votes
对内部表示使用具体的Serializable集,但使所有公共接口都使用Set接口。
public class TestClass implements Serializable {
private static final long serialVersionUID = 1905162041950251407L;
private HashSet mySet;
public TestClass(Set s) {
super();
setMySet(s);
}
public void setMySet(Set s) {
mySet = (s == null) ? new HashSet<>() : new HashSet<>(s);
}
}
Paul Croarkin answered 2020-01-05T16:52:48Z
-1 votes
如果您使用的是findbugs-maven-plugin且必须保留一个字段,并且该字段是未实现Serializable接口的类,例如,某个字段在第三方定义了一个类。 您可以手动为findbug配置排除文件,
如果只有这种情况,请将其添加到排除文件中:pom:
org.codehaus.mojo
findbugs-maven-plugin
3.0.3
true
target/findbugs/
findbugs-exclude.xml
findbugs-include.xml
true
...
exclude.xml:
实体:
@Entity
public class Foo extends Boo {
StateMachineContext stateMachineContext;
尽管我不明白为什么无法添加javax.persistence.AttributeConverter。 此外,我不同意在像@edu.umd.cs.findbugs.annotations.SuppressWarnings(justification="No bug", values="SE_BAD_FIELD")这样的字段上添加注释的解决方案,因为构建工具最好不要渗透业务代码.maven插件用法和findbugs过滤器都包括和排除
关于SE_BAD_FIELD:可序列化类中的非瞬态不可序列化实例字段,我认为不应检查实体。 因为javax.persistence.AttributeConverter提供了将字段外序列化的方法(实现Serializable是内部进行序列化的方法)。
Tiina answered 2020-01-05T16:53:31Z