好吧,受到 Ben Lawry 的想法的启发,但他没有提出实际的实现,我还编写了一个类爬虫,它可以查找“不可序列化字段”,即非静态、非瞬态字段,这些字段要么没有实现可序列化接口本身或包含非静态、非瞬态且不实现可序列化接口的字段。
你可以在main方法的列表中添加几个要测试的类(见注释)。输出是来自这些类或任何不能通过上述定义序列化的引用类的字段列表(但是,它并不完全等于实际可序列化字段,而是捕获后者的超集);对于本身实现 Serialized 接口的每个字段,都会给出该字段类型中引用的字段列表,这会导致该字段不可序列化(如果该列表为空,则该字段本身不实现 Serialized 接口)。
这是代码,希望对其他人也有帮助:
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import javax.swing.JComponent;
public class Crawler {
public static boolean crawlRecursively(Field field, HashSet<Class<?>> alreadyCrawled, HashMap<Field, HashSet<String>> badFields) {
if (alreadyCrawled.contains(field.getType())) {
return !badFields.keySet().contains(field);
}
alreadyCrawled.add(field.getType());
if (Modifier.isStatic(field.getModifiers())
|| Modifier.isTransient(field.getModifiers())
|| field.getType().isPrimitive()) {
return true;
} else if (Serializable.class.isAssignableFrom(field.getType())) {
boolean allGood = true;
for (Field f : field.getType().getDeclaredFields()) {
boolean isGood = crawlRecursively(f, alreadyCrawled, badFields);
if (!isGood) {
if (!badFields.containsKey(field)) {
badFields.put(field, new HashSet<>());
}
badFields.get(field).add(f.getType().getSimpleName() + " " + f.getName());
allGood = false;
}
}
return allGood;
} else {
if (!badFields.containsKey(field)) {
badFields.put(field, new HashSet<>());
}
return false;
}
}
public static HashMap<Field, HashSet<String>> initiateCrawling(Collection<Class<?>> roots) {
HashMap<Field, HashSet<String>> badFields = new HashMap<>();
for (Class<?> root : roots) {
for (Field f : root.getDeclaredFields()) {
crawlRecursively(f, new HashSet<>(), badFields);
}
}
return badFields;
}
public static void main(String[] args) {
LinkedList<Class<?>> roots = new LinkedList<>();
roots.add(JComponent.class); // ADD YOUR CLASSES HERE.
HashMap<Field, HashSet<String>> badFields = initiateCrawling(roots);
if (badFields.keySet().size() == 0) {
System.out.println("All fields are serializable (not having checked the given class(es) themselves).");
} else {
System.out.println("The following fields are not serializable in the class tree(s) given by " + roots + ":");
}
for (Field field : badFields.keySet()) {
System.out.println("<UnSer> "
+ field.getType().getSimpleName() + " "
+ field.getName() + " ("
+ field.getDeclaringClass().getName() + ") => " + badFields.get(field));
}
}
}
JComponent 类的输出示例:
The following fields are not serializable in the class tree(s) given by [class javax.swing.JComponent]:
<UnSer> Border border (javax.swing.JComponent) => []
<UnSer> ComponentInputMap windowInputMap (javax.swing.JComponent) => [JComponent component]
<UnSer> VetoableChangeSupport vetoableChangeSupport (javax.swing.JComponent) => [VetoableChangeListenerMap map, Object source]
<UnSer> SingleSelectionModel selectionModel (javax.swing.JPopupMenu) => []
<UnSer> JPopupMenu popupMenu (javax.swing.JComponent) => [SingleSelectionModel selectionModel]
<UnSer> Object source (java.beans.VetoableChangeSupport) => []
<UnSer> VetoableChangeListenerMap map (java.beans.VetoableChangeSupport) => []
<UnSer> JComponent component (javax.swing.ComponentInputMap) => [VetoableChangeSupport vetoableChangeSupport, JPopupMenu popupMenu, Border border, InputVerifier inputVerifier]
<UnSer> InputVerifier inputVerifier (javax.swing.JComponent) => []