2013-04-18 43 views
7

是否有明確的方法阻止ProGuard從實現接口更改類?如何阻止ProGuard從類中剝離Serializable接口

我有一個類實現java.io.Serializable,我們稱之爲com.my.package.name.Foo。我發現在運行ProGuard後,它不再實現Serializable。我從Serializable轉換爲Foofalse後,我得到null如果我使用instanceof Serializable檢查實例。我已經取得了一定要設置的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的jar中。使用這些類的代碼包括將它們放在Bundle中,這就是爲什麼我需要Serializable。我認爲ProGuard可能以某種方式認爲Foo永遠不會被用作Serializable,但這似乎不太可能,因爲我將它作爲參數傳遞給Bundle.putSerializable(String, Serializable),並且我也進行了隱式投射:Serializable serializable = foo;。實際上,當我調試時,我可以看到Foo被放入Bundle,我可以檢查Bundle並在那裏看到Foo的實例,但是當檢索它時,轉換失敗。

回答

4

ProGuard不會從處理的代碼(如Foo)中剝離在庫中定義的接口(如Serializable)。庫代碼可能會轉換爲這些接口,因此它們不能被刪除。

我得到空我從序列化投給foo

這意味着該實例必須爲空下手了。如果您遇到ClassCastException,您的分析將是正確的。您可以檢查Foo仍然使用javap實現Serializable。問題可能在別處。有關序列化的提示,您可以查看ProGuard手冊>示例>Processing serializable classes

更新:

在這種情況下,它原來是一個配置問題。 ProGuard只能處理類文件,如果它知道其層次結構的所有內容(就像編譯器一樣)。你真的需要指定運行時類:

-libraryjars <java.home>/lib/rt.jar 

或爲Android:

-libraryjars /usr/local/android-sdk/platforms/android-17/android.jar 

Android的螞蟻/ Eclipse構建自動指定你所有必要的-injars/-outjars/-libraryjars選項,但在自定義構建過程中,您必須自己指定它們。 (CFR)。 ProGuard手冊>示例>A complete Android application

請注意,選項-dontwarn使警告消失,但不是問題。只有在真正需要時才使用它。

+0

感謝輸入,但我已經對'javap'檢查和'Foo'沒有實現'Serializable'了。您對'ClassCastException'的評論對我來說也是有意義的,但它似乎並沒有這樣工作。我懷疑是在收縮和優化中發生了什麼事情,以改變你所期望的普通Java代碼所做的行爲,因爲此時它不再是Java,而是字節碼。 – kabuko

+0

我發現如果我將ProGuard設置爲'-dontshrink',然後明確使用'-keep,allowoptimization,allowhrinking,allowobfuscation Foo',那麼'Foo'仍然會實現'Serializable',但不幸的是這對我來說不是一個解決方案正如我想縮小一般。 – kabuko

+0

如果你有一個小樣本來說明問題,我會研究它。您可以在ProGuard網站的反饋頁面上找到我的郵件地址。 –

21

我有同樣的問題修復使用下面的配置。

-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

+2

文檔:http://proguard.sourceforge.net/manual/examples.html#serializable – shkschneider

+1

在我看來,這應該是proguard中的默認規則。 – nilsmagnus

+0

謝謝!我花了很多時間試圖讓這個工作。 – Eduard