我需要反序列化对象,但是当我使用 readObject 读取对象时,出现这样的异常:
Exception raised: java.lang.Enum; Incompatible class (SUID):
java.lang.Enum: static final long serialVersionUID =0L;
but expected java.lang.Enum: static final long serialVersionUID =0L;
代码如下:
public static void restore3x(PersistentHistory h, DictManager dictManager) throws Exception{
SharedPreferences prefs = tryToGuess(h.mContext);
if (prefs == null) return;
Log.e("shdd","Found history!");
String history = prefs.getString("History", null);
ObjectInputStream objIn = null;
try {
//prepare
objIn = new ObjectInputStream(new ByteArrayInputStream(Base64.decode(history))) {
@Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
ObjectStreamClass osc = super.readClassDescriptor();
if (osc.getName().contains("slovoed")) {
try {
Field f;
f = osc.getClass().getDeclaredField("svUID");
f.setAccessible(true);
Log.e("shdd","Setting serialVersionUID");
f.setLong(osc, serialVersionUID);
Log.e("shdd","Set ok");
f = osc.getClass().getDeclaredField("className");
f.setAccessible(true);
Log.e("shdd","Setting class name");
f.set(osc, WordItem.class.getName());
Log.e("shdd","Set ok");
} catch (Exception e) {
}
}
return osc;
}
};
//add to DB
Log.e("shdd","Getting items");
Collection<WordItem3x> items = (Collection<WordItem3x>) objIn.readObject();
Log.e("shdd","Got ok");
if (items.isEmpty()) return;
Log.e("shdd","List's not empty");
long timeSeconds = System.currentTimeMillis()/1000;
for (WordItem3x w : items) {
if (w.getWord() == null || w.getWord().length() == 0 || w.getIndexList() == 0) continue;
Log.e("shdd","Adding word");
h.add(w.getWord(), w.getIndexList(), timeSeconds--);
}
} catch (Exception e) {
Log.e("shdd","Exception raised: " + e.getMessage());
throw e;
} finally {
try { if (objIn != null) objIn.close(); } catch (Exception e) {}
//prefs.edit().remove("History").commit();
}
}
我不知道出了什么问题。也许有人见过这样的异常?
这是 WordItem3x readObject 方法:
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {
Log.e("shdd", "Reading object");
in.defaultReadObject();
int val1 = in.readInt();
int val2 = in.readInt();
if (val1 != -1 && val2 != -1) {
direction = new Direction(val1, val2);
} else
direction = null;
val1 = in.readInt();
if (val1 != -1)
typeList = eWordListType.values()[val1];
else
typeList = null;
}
但据我所知,它从未被调用过。
最佳答案
(注意:没有显示序列化代码,WordItem3x 实现大部分被省略)
根据代码,我能做出的最佳猜测是在 readClassDescriptor
中使用反射修改 serialVersionUID 的黑客攻击最终导致修改枚举的 serialVersionUID。根据 java 规范,所有枚举条目 serialVersionUID 都应为 0L。我敢打赌你在某个时候将枚举更改为 none 0L。这是 AOSP 中抛出的代码块:
// Check SUIDs, note all SUID for Enum is 0L
if (0L != classDesc.getSerialVersionUID() || 0L != superClass.getSerialVersionUID()) {
throw new InvalidClassException(superClass.getName(),
"Incompatible class (SUID): " + superClass + " but expected " + superClass);
}
在修改 serialVersionUID 之前尝试打印出对象的名称
ObjectStreamClass osc = super.readClassDescriptor();
osc.getName(); // is this an enum????
关于java - 反序列化期间出现奇怪的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15022230/