Java 如何处理Findbugs“;serializable类“中的非瞬态非序列化实例字段”;?
考虑下面的类。如果我对它运行Findbugs,它将在第5行(而不是第7行)给出一个错误(“serializable类中的非瞬态非序列化实例字段”)Java 如何处理Findbugs“;serializable类“中的非瞬态非序列化实例字段”;?,java,serialization,findbugs,Java,Serialization,Findbugs,考虑下面的类。如果我对它运行Findbugs,它将在第5行(而不是第7行)给出一个错误(“serializable类中的非瞬态非序列化实例字段”) 1 public class TestClass implements Serializable { 2 3 private static final long serialVersionUID = 1905162041950251407L; 4 5 private Set<Integer> mySet; // Findbu
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 }
1公共类TestClass实现可序列化{
2.
3私有静态最终长serialVersionUID=1905162041950251407L;
4.
5私有集mySet;//Findbugs错误
6.
7私有HashSet-myOtherSet;
8.
9 }
这是正确的,因为java.util.Set从未在其层次结构中实现Serializable,而java.util.HashSet则实现了。
然而,最好的做法是根据接口而不是具体的实现进行编码
我怎样才能最好地处理这件事
我可以在第3行添加@Suppresswarnings(justify=“No bug”,values=“SE_BAD_FIELD”)。在我的实际代码中有相当多的集合和列表,我担心它会太多地乱扔我的代码
有更好的方法吗
然而,编写代码是最佳实践
针对接口而不是混凝土
实现
我认为不,在这种情况下不是。Findbugs非常正确地告诉您,一旦在该字段中设置了不可序列化的集
实现,您就有可能遇到NotSerializableException
。这是你应该处理的事情。如何,这取决于类的设计
- 如果这些集合是在类内初始化的,并且从不从外部设置,那么我认为为字段声明具体类型绝对没有错,因为字段是实现细节。请在公共接口中使用接口类型
- 如果集合通过公共接口传递到类中,则必须确保它们实际上是可序列化的。为此,请创建一个接口
,并将其用于您的字段。然后,要么:SerializableSet extends Set,Serializable
- 在公共接口中使用
,并提供实现它的实现类李>SerializableSet
- 检查通过可序列化的
实例传递给类的集合,如果不是,则将它们复制到可序列化的集合中
- 在公共接口中使用
set
字段设置为transient,这将修复FindBugs错误
public class TestClass implements Serializable {
private static final long serialVersionUID = 1905162041950251407L;
private transient Set<Integer> mySet;
}
公共类TestClass实现可序列化{
私有静态最终长serialVersionUID=1905162041950251407L;
私有瞬态集mySet;
}
我更喜欢这种方法,而不是强制API的用户强制转换为具体类型,除非它只是内部类型,那么Michael Borgwardt的回答更有意义。您可以使用捕获助手来确保传入集支持两个接口:
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);
}
}
private静态类SerializableTestClass&Serializable>Serializable for SerializableSet(T集)
{
返回新的SerializableTestClass(集合);
}
}
通过这种方式,您可以拥有一个强制可序列化的公共API,而无需检查/要求特定的实现细节。我对集合字段使用findbugs排除过滤器:
<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>
请参见通过向类中添加以下方法,您可以消除那些严重的警告消息:
private void writeObject(ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
}
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
}
对内部表示使用一个具体的可序列化集,但使任何公共接口都使用该集接口
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);
}
}
公共类TestClass实现可序列化{
私有静态最终长serialVersionUID=1905162041950251407L;
私有HashSet-mySet;
公共测试类(集合s){
超级();
setMySet(s);;
}
公共无效集合集(集合s){
mySet=(s==null)?new HashSet():new HashSet(s);
}
}
如果您正在使用findbugs maven插件,并且必须保留一个字段,而该字段是一个未实现可序列化接口的类,例如,一个在第三方中定义了类的字段。您可以手动配置findbugs的排除文件
如果这是唯一的情况,请将其添加到排除文件中:
pom:
org.codehaus.mojo
&
关于SE_BAD_字段:serializable类中的非瞬态非序列化实例字段,我认为它不应该检查实体。因为,javax.persistence.AttributeConverter
提供了将字段外部序列化的方法(implements Serializable是要序列化的内部方法)。我对可序列化类中的受保护字段发出了高警告。为解决我的问题的字段添加瞬态:
protected transient Object objectName;
电子战。即使在这种情况下,我也不喜欢使用具体的字体。我认为这是一个完全可以忽略的警告。您可能需要担心的唯一一点是,您是否真的有任意代码设置此集合,这可能会将其设置为不可序列化的集合实例。@Michael在内部使用具体类型可能不是“问题”,但我认为这是一种不好的做法。即使它是在外部设置的,您也只需要担心您是否在处理您无法控制的代码。我觉得在这种情况下,设计的清洁度(使用界面)超过了这个警告的(理论上)有用性。我同意@jtahlborn。当您确实需要一个HashSet时,不能让每个方法都只接受HashSet。调用方不需要传递哈希集,任何可序列化集实现都可以。这是您现在无法用Java表达的东西,这是您必须处理的语言设计限制。我认为使用界面忽略这个警告更安全(或者只是检查一下你是否正常,而不是100%确定)。@ymajoros:对于“安全”这个词,没有一个合理的定义可以证明你的说法是正确的。事实上,安全正是使用混凝土类型比ignor更好的解决方案的原因
<?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;
protected transient Object objectName;