2010-03-03 25 views
7

Có ai từng cố gắng kết hợp việc sử dụng google guice với obfuscation (đặc biệt proguard)? Phiên bản bị xáo trộn của mã của tôi không hoạt động với google guice vì guice phàn nàn về các thông số loại bị thiếu. Thông tin này dường như bị xóa bởi bước chuyển đổi mà proguard làm, ngay cả khi các lớp học liên quan được loại trừ khỏi obfuscation.Tiêm với google guice không hoạt động nữa sau khi obfuscation với proguard

Các vết đống trông như thế này:

com.google.inject.CreationException: Guice creation errors: 

1) Cannot inject a Provider that has no type parameter 
    while locating com.google.inject.Provider 
    for parameter 0 at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setPasswordPanelProvider(SourceFile:499) 
    at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setPasswordPanelProvider(SourceFile:499) 
    while locating de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel 
    for parameter 0 at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65) 
    at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65) 
    at de.repower.lvs.client.admin.user.administration.o.a(SourceFile:38) 

2) Cannot inject a Provider that has no type parameter 
    while locating com.google.inject.Provider 
    for parameter 0 at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setWindTurbineAccessGroupProvider(SourceFile:509) 
    at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setWindTurbineAccessGroupProvider(SourceFile:509) 
    while locating de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel 
    for parameter 0 at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65) 
    at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65) 
    at de.repower.lvs.client.admin.user.administration.o.a(SourceFile:38) 

2 errors 
    at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:354) 
    at com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:152) 
    at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:105) 
    at com.google.inject.Guice.createInjector(Guice.java:92) 
    at com.google.inject.Guice.createInjector(Guice.java:69) 
    at com.google.inject.Guice.createInjector(Guice.java:59) 

tôi đã cố gắng để tạo ra một ví dụ nhỏ (không sử dụng Guice) mà dường như để tạo lại vấn đề:

package de.repower.common; 

import java.lang.reflect.Method; 
import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 

class SomeClass<S> { 
} 

public class ParameterizedTypeTest { 

    public void someMethod(SomeClass<Integer> param) { 
     System.out.println("value: " + param); 
     System.setProperty("my.dummmy.property", "hallo"); 
    } 

    private static void checkParameterizedMethod(ParameterizedTypeTest testObject) { 
     System.out.println("checking parameterized method ..."); 
     Method[] methods = testObject.getClass().getMethods(); 
     for (Method method : methods) { 
      if (method.getName().equals("someMethod")) { 
       System.out.println("Found method " + method.getName()); 
       Type[] types = method.getGenericParameterTypes(); 
       Type parameterType = types[0]; 
       if (parameterType instanceof ParameterizedType) { 
        Type parameterizedType = ((ParameterizedType) parameterType).getActualTypeArguments()[0]; 
        System.out.println("Parameter: " + parameterizedType); 
        System.out.println("Class: " + ((Class) parameterizedType).getName()); 
       } else { 
        System.out.println("Failed: type ist not instance of ParameterizedType"); 
       } 
      } 
     } 
    } 

    public static void main(String[] args) { 
     System.out.println("Starting ..."); 
     try { 
      ParameterizedTypeTest someInstance = new ParameterizedTypeTest(); 
      checkParameterizedMethod(someInstance); 
     } catch (SecurityException e) { 
      e.printStackTrace(); 
     } 

    } 

} 

Nếu bạn chạy mã này unsbfuscated , đầu ra trông giống như sau:

Starting ... 
checking parameterized method ... 
Found method someMethod 
Parameter: class java.lang.Integer 
Class: java.lang.Integer 

Nhưng chạy phiên bản bị xáo trộn với pro sản lượng bảo vệ:

Starting ... 
checking parameterized method ... 
Found method someMethod 
Failed: type ist not instance of ParameterizedType 

Đây là những lựa chọn tôi sử dụng cho obfuscation:

-injars classes_eclipse\methodTest.jar 
-outjars classes_eclipse\methodTestObfuscated.jar 

-libraryjars 'C:\Program Files\Java\jre6\lib\rt.jar' 

-dontskipnonpubliclibraryclasses 
-dontskipnonpubliclibraryclassmembers 
-dontshrink 
-printusage classes_eclipse\shrink.txt 
-dontoptimize 
-dontpreverify 
-verbose 


-keep class **.ParameterizedTypeTest.class { 
    <fields>; 
    <methods>; 
} 

-keep class ** { 
    <fields>; 
    <methods>; 
} 

# Keep - Applications. Keep all application classes, along with their 'main' 
# methods. 
-keepclasseswithmembers public class * { 
    public static void main(java.lang.String[]); 
} 

# Also keep - Enumerations. Keep the special static methods that are required in 
# enumeration classes. 
-keepclassmembers enum * { 
    public static **[] values(); 
    public static ** valueOf(java.lang.String); 
} 

# Also keep - Database drivers. Keep all implementations of java.sql.Driver. 
-keep class * extends java.sql.Driver 

# Also keep - Swing UI L&F. Keep all extensions of javax.swing.plaf.ComponentUI, 
# along with the special 'createUI' method. 
-keep class * extends javax.swing.plaf.ComponentUI { 
    public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent); 
} 

# Keep names - Native method names. Keep all native class/method names. 
-keepclasseswithmembers,allowshrinking class * { 
    native <methods>; 
} 

# Keep names - _class method names. Keep all .class method names. This may be 
# useful for libraries that will be obfuscated again with different obfuscators. 
-keepclassmembers,allowshrinking class * { 
    java.lang.Class class$(java.lang.String); 
    java.lang.Class class$(java.lang.String,boolean); 
} 

Có ai có một ý tưởng về cách giải quyết này (ngoài các workaround rõ ràng để đưa các tập tin có liên quan vào một riêng biệt jar và không obfuscate nó)?

Trân trọng,
Stefan

Trả lời

8

Sau khi sử dụng Proguard cho một số lượng tốt của thời gian, ở đây là làm thế nào tôi đã quyết định để giải quyết các vấn đề liên quan đến phản ánh (và Guice chỉ là một trường hợp sử dụng của nó).

Phản ánh có thể được sử dụng với Proguard miễn là KHÔNG có lớp hoặc tên phương thức được nhập dưới dạng Chuỗi.

Đó là để nói mã này là hợp lệ và sẽ làm việc sau khi ProGuard obfuscation

Class someClass = Class.forName(SomeClass.class.getName()); 

trong khi mã này sẽ không hoạt động

Class someClass = Class.forName("SomeClass"); 

Hơn nữa, Proguard sẽ co lại phương pháp bôi và constructor. Do đó, phương thức Class.newInstance sẽ không hoạt động. Liên kết Guice không may, thường lệ hoạt động bằng phương pháp này.

Điều này có một số hậu quả đối với mã Guice.

  • Tất cả các mũi tiêm của bạn phải được tạo bằng cách sử dụng @Provides annotated methods, vì ProGuard sẽ thu nhỏ lớp do thực tế các trình tạo của chúng không được gọi là explictely.
  • Proguard không được thu nhỏ mã của các lớp mô-đun của bạn.
  • ProGuard không được thu nhỏ chú thích, tùy theo điều kiện nào và bất cứ nơi nào (chú thích có thể được định cấu hình, nhưng tôi không thể nhớ vị trí).
+1

Ồ, đây là tin khủng khiếp mà bạn phải sử dụng @Provides phương pháp chỉ để ngăn ProGuard loại bỏ các phụ thuộc. Điều này đòi hỏi một công cụ để giúp đỡ. Tôi giả sử nó cũng sẽ làm việc (gần như bằng nhau khó chịu) để dính một loạt các dòng -keep trong cấu hình proguard? –

+0

Có thể vì việc thêm chú thích -keep sẽ làm cho việc tái cấu trúc kém hiệu quả hơn, vì chúng ta sẽ phải đảm bảo trong lọ đầu ra rằng các tên lớp là hợp lệ. Để tâm trí của tôi, hoạt động trên một cấp độ Java thuần túy làm cho mã của chúng tôi tuân thủ nhiều quy tắc tái cấu trúc (nếu có một điều như vậy) – Riduidel

7

Thuộc tính "Chữ ký" là bắt buộc để có thể truy cập các loại chung khi biên dịch trong JDK 5.0 trở lên.

Sử dụng-bảo quản Chữ ký để sửa lỗi với ParameterizedType

+0

Nó không khắc phục được vấn đề từ ví dụ trên. Tôi vẫn phải thử nó trên vấn đề ban đầu của tôi với google guice. – sme

+1

Điều này đã khắc phục sự cố cho tôi trên Android với bản dựng không có sẵn, tôi đã gặp vấn đề tương tự như OP. Tôi cũng có những điều sau trong cấu hình proguard. lớp -keepclassmembers * { @ com.google.inject.Inject (...); } – abombss

+0

Điều này cũng phù hợp với tôi, với cùng một vấn đề với người hỏi câu hỏi !! – Peterdk

0

Mã sau hoạt động cho tôi, có cùng sự cố.

-keepattributes Signature là bản sửa lỗi.

-optimizationpasses 5 
-dontusemixedcaseclassnames 
-dontskipnonpubliclibraryclasses 
-dontpreverify 
#-dontobfuscate 
-repackageclasses '' 
-keepattributes *Annotation* 
-keepattributes Signature 
-verbose 
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 

-keep public class * extends android.app.Activity 
-keep public class * extends android.app.Application 
-keep public class * extends android.app.Service 
-keep public class * extends android.content.BroadcastReceiver 
-keep public class * extends android.content.ContentProvider 
-keep public class * extends android.app.backup.BackupAgentHelper 
-keep public class * extends android.preference.Preference 
-keep public class com.android.vending.licensing.ILicensingService 

-keepclasseswithmembernames class * { 
    native <methods>; 
} 

-keepclasseswithmembernames class * { 
    public <init>(android.content.Context, android.util.AttributeSet); 
} 

-keepclasseswithmembernames class * { 
    public <init>(android.content.Context, android.util.AttributeSet, int); 
} 

-keepclassmembers enum * { 
    public static **[] values(); 
    public static ** valueOf(java.lang.String); 
} 
-keepattributes Signature 
-keep class * implements android.os.Parcelable { 
    public static final android.os.Parcelable$Creator *; 
} 
-keep class com.google.inject.Binder 
-keepclassmembers class * { 
    @com.google.inject.Inject <init>(...); 
} 
-keep public class * extends android.view.View { 
    public <init>(android.content.Context); 
    public <init>(android.content.Context, android.util.AttributeSet); 
    public <init>(android.content.Context, android.util.AttributeSet, int); 
    public void set*(...); 
} 

# I didn't need this one, maybe you need it. 
#-keep public class roboguice.** 

-keepclassmembers class **.R$* { 
    public static <fields>; 
} 
3

Với phiên bản hiện tại của Proguard (4.7) tôi đã có thể để có được nó làm việc bằng cách thêm những điều sau đây: -

-keepattributes *Annotation*,Signature 
-keep class com.google.inject.Binder  
-keep public class com.google.inject.Inject 
# keeps all fields and Constructors with @Inject 
-keepclassmembers,allowobfuscation class * { 
    @com.google.inject.Inject <fields>; 
    @com.google.inject.Inject <init>(...); 
} 

Ngoài giữ một cách rõ ràng bất kỳ lớp đó được tạo ra bởi Guice ví dụ

-keep class com.example.Service 
+0

Sửa đổi này không yêu cầu thêm các lớp @Inject của bạn một cách rõ ràng (như được ghi chú trong các bài đăng khác là dễ bị lỗi): '-keepclasseswithmembers, allowoptimization, allowobfuscation class * { @ com.google.inject.Inject ; } -keepclassmembers, allowobfuscation, lớp cho phép tối ưu hóa * { @ com.google.inject.Provides ; } ' – enl8enmentnow

Các vấn đề liên quan