【问题标题】:How to stop ProGuard from stripping the Serializable interface from a class如何阻止 ProGuard 从类中剥离 Serializable 接口
【发布时间】:2013-04-10 23:44:02
【问题描述】:

是否有明确的方法来阻止 ProGuard 更改类以实现接口?

我有一个实现java.io.Serializable 的类,我们称之为com.my.package.name.Foo。我发现通过 ProGuard 运行后,它不再实现Serializable。如果我使用instanceof Serializable 检查实例,我会在从Serializable 转换为Foofalse 后得到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 使用。使用这些类的代码包括将它们放在Bundles 中,这就是我需要Serializable 的原因。我认为 ProGuard 可能以某种方式认为 Foo 从未用作 Serializable,但考虑到我将它作为参数传递给 Bundle.putSerializable(String, Serializable) 并且我做了一个隐式转换:Serializable serializable = foo;,这似乎不太可能。事实上,当我调试时,我可以看到Foo 被放入Bundle 中,我可以检查Bundle 并在那里看到Foo 的实例,但是在检索它时转换失败。

【问题讨论】:

    标签: java android proguard serializable


    【解决方案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 使警告消失,而不是问题。仅在确实需要时才使用它。

    【讨论】:

    • 感谢您的输入,但我已经检查了 javapFoo 不再实现 Serializable。您对ClassCastException 的评论对我来说也很有意义,但它似乎并没有那样工作。我怀疑在缩小和优化中发生了一些事情,以改变您可能期望普通 Java 代码执行的行为,因为此时它不再是 Java,而是字节码。
    • 我发现如果我将 ProGuard 设置为 -dontshrink,然后明确使用 -keep,allowoptimization,allowshrinking,allowobfuscation Foo,那么 Foo 仍将实现 Serializable,但不幸的是,这不是我的解决方案,因为我'希望缩小到一般情况下。
    • 如果你有一个说明问题的小样本,我会调查它。您可以在 ProGuard 网站的反馈页面上找到我的邮件地址。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-15
    相关资源
    最近更新 更多