cav*_*llo 2 java android proguard serialversionuid deserialization
不久前,我发布了一个序列化/反序列化用户对象的应用程序。
public String serializeUser(final User user) {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
final ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(user);
objectOutputStream.close();
} catch (final IOException exception) {
...
}
return new String(Base64.encode(byteArrayOutputStream.toByteArray(), DEFAULT));
}
public User deserializeString(final String userString) {
final byte userBytes[] = Base64.decode(userString.getBytes(), DEFAULT);
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(userBytes);
final ObjectInputStream objectInputStream;
final User user;
try {
objectInputStream = new ObjectInputStream(byteArrayInputStream);
user = (User) objectInputStream.readObject();
objectInputStream.close();
} catch (final IOException | ClassNotFoundException exception) {
...
}
return user;
}
Run Code Online (Sandbox Code Playgroud)
该对象是这样实现的:
public class User implements Serializable {
private String email;
private String name;
...
}
Run Code Online (Sandbox Code Playgroud)
然后,在修改我的对象(我添加了一个新字段)之后,我学到了一种艰难的方法,即必须设置以防serialVersionUID对象定义发生更改,否则反序列化器将无法识别存储的对象(因为它将自动生成serialVersionUID)。所以我继续这样做:
public class User implements Serializable {
private static final long serialVersionUID = 123L;
...
}
Run Code Online (Sandbox Code Playgroud)
但现在我已经重新发布了包含这些更改的应用程序,我不断收到错误报告,表明该对象无法反序列化:
引起原因:java.io.InvalidClassException:com.myproject.he;本地类不兼容:流classdesc serialVersionUID = 184861231695454120,本地类serialVersionUID = -2021388307940757454
我非常清楚设置新的串行版本将使任何以前的串行版本(link1,link2)无效,但事实并非如此。正如您所看到的,错误日志指向的serialVersionUID(18486...和-20213...) 与我手动设置到我的User类 ( 123L) 的错误日志完全不同。
我缺少什么?
如果有任何相关性,我将使用带有默认配置的 Proguard。
经过谷歌搜索很长一段时间后,我偶然发现了这个问题:How to stop ProGuard from stripping the Serialized interface from a class。因此,我继续深入研究 APK(可以在 Android Studio 中分析 APKUser ),找到我的类,并查看其字节码:
class public Lcom/myproject/h/e;
.super Ljava/lang/Object;
.source "User.java"
# interfaces
.implements Ljava/io/Serializable;
# annotations
...
# instance fields
.field private a:Ljava/lang/String;
.field private b:Ljava/lang/String;
...
# direct methods
...
Run Code Online (Sandbox Code Playgroud)
如您所见,serialVersionUID找不到 Static 字段。所以我继续按照文档的建议添加了以下配置:
[应用程序] 可能包含序列化的类。根据它们的使用方式,可能需要特别注意。[...]有时,序列化的数据会被存储,并在稍后读回到新版本的可序列化类中。然后,必须注意这些类与其未处理的版本以及未来处理的版本保持兼容。在这种情况下,相关类很可能有
serialVersionUID字段。以下选项应该足以确保随着时间的推移兼容性:
-keepnames class * implements java.io.Serializable`
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
Run Code Online (Sandbox Code Playgroud)
因此,如果我转到新生成的 APK 并检查对象的字节码,它现在指定serialVersionUID不应丢弃或重命名:
class public Lcom/myproject/model/User;
.super Ljava/lang/Object;
.source "User.java"
...
# static fields
.field private static final serialVersionUID:J
# instance fields
...
Run Code Online (Sandbox Code Playgroud)
我希望应用程序在反序列化我的对象时不再遇到任何问题。
| 归档时间: |
|
| 查看次数: |
1042 次 |
| 最近记录: |