如何阻止 ProGuard 从类中剥离 Serializable 接口
Posted
技术标签:
【中文标题】如何阻止 ProGuard 从类中剥离 Serializable 接口【英文标题】:How to stop ProGuard from stripping the Serializable interface from a class 【发布时间】:2013-04-10 23:44:02 【问题描述】:是否有明确的方法来阻止 ProGuard 更改类以实现接口?
我有一个实现java.io.Serializable
的类,我们称之为com.my.package.name.Foo
。我发现通过 ProGuard 运行后,它不再实现Serializable
。如果我使用instanceof Serializable
检查实例,我会在从Serializable
转换为Foo
和false
后得到null
。我确保将 ProGuard 设置为忽略此类:
-keep class com.my.package.name.Foo
我也试过了:
-keep class com.my.package.name.Foo *;
我也通过这样做尝试了整个包:
-keep class com.my.package.name.** *;
或:
-keep class com.my.package.** *;
也只是为了保留所有Serializable
类:
-keep class * implements java.io.Serializable *;
但无济于事。我在同级包中有另一个类(大致为:com.my.package.name2.Bar
),它也实现了Serializable
,并且使用类似但没有问题。
我不确定它是否相关,但我将它打包在一个罐子中以供 android 使用。使用这些类的代码包括将它们放在Bundle
s 中,这就是我需要Serializable
的原因。我认为 ProGuard 可能以某种方式认为 Foo
从未用作 Serializable
,但考虑到我将它作为参数传递给 Bundle.putSerializable(String, Serializable)
并且我做了一个隐式转换:Serializable serializable = foo;
,这似乎不太可能。事实上,当我调试时,我可以看到Foo
被放入Bundle
中,我可以检查Bundle
并在那里看到Foo
的实例,但是在检索它时转换失败。
【问题讨论】:
【参考方案1】:我使用下面的配置解决了同样的问题。
-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();
官方文档 http://proguard.sourceforge.net/manual/examples.html#serializable
【讨论】:
在我看来,这应该是proguard中的默认规则。 谢谢!我花了很多时间试图让它发挥作用。【参考方案2】:ProGuard 不会从已处理代码中的类(如 Foo)中剥离库中定义的接口(如 Serializable)。库代码可能会转换为这些接口,因此无法删除。
从 Serializable 转换为 Foo 后我得到 null
这意味着实例必须为 null 才能开始。如果您得到 ClassCastException,您的分析将是正确的。您可以使用javap
检查 Foo 是否仍然实现 Serializable。问题可能出在其他地方。有关序列化的提示,您可以查看 ProGuard 手册 > 示例 > Processing serializable classes。
更新:
在这种情况下,结果证明是配置问题。 ProGuard 只能处理类文件,如果它知道所有关于它们的层次结构(就像编译器一样)。您确实必须指定运行时类:
-libraryjars <java.home>/lib/rt.jar
或对于 Android:
-libraryjars /usr/local/android-sdk/platforms/android-17/android.jar
Android Ant/Eclipse 构建会自动为您指定所有必要的 -injars/-outjars/-libraryjars 选项,但在自定义构建过程中,您必须自己指定它们。参照。 ProGuard 手册 > 示例 > A complete Android application.
请注意,选项 -dontwarn 使警告消失,而不是问题。仅在确实需要时才使用它。
【讨论】:
感谢您的输入,但我已经检查了javap
和 Foo
不再实现 Serializable
。您对ClassCastException
的评论对我来说也很有意义,但它似乎并没有那样工作。我怀疑在缩小和优化中发生了一些事情,以改变您可能期望普通 Java 代码执行的行为,因为此时它不再是 Java,而是字节码。
我发现如果我将 ProGuard 设置为 -dontshrink
,然后明确使用 -keep,allowoptimization,allowshrinking,allowobfuscation Foo
,那么 Foo
仍将实现 Serializable
,但不幸的是,这不是我的解决方案,因为我'希望缩小到一般情况下。
如果你有一个说明问题的小样本,我会调查它。您可以在 ProGuard 网站的反馈页面上找到我的邮件地址。以上是关于如何阻止 ProGuard 从类中剥离 Serializable 接口的主要内容,如果未能解决你的问题,请参考以下文章