2010-03-03 80 views
7

有没有人试图将谷歌guice的使用与混淆(特别是proguard)? 我的代码的混淆版本不适用于谷歌guice,因为guice抱怨缺少类型参数。这些信息似乎被proguard所做的转换步骤所消除,即使相关类被排除在混淆之外。注入谷歌guice不再工作了与proguard混淆后

堆栈跟踪看起来是这样的:

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) 

我试图创建一个小例子(不使用吉斯),这似乎重现该问题:

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(); 
     } 

    } 

} 

如果你运行这段代码unsbfuscated ,输出看起来是这样的:

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

但运行的版本与Pro混淆后卫产量:

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

这些是我用来迷惑选项:

-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); 
} 

有谁有如何从显而易见的解决方法解决这个问题(除了把相关的文件到一个单独的一个想法jar和不混淆它)?

最好的问候,
斯特凡

回答

8

曾使用proguard的一个很好的时间,这里是我决定如何解决有关反射的问题(吉斯只是其中的一个用例)。

只要没有类或方法名称作为字符串输入,反射可以与Proguard一起使用。

这就是说这段代码是有效的,ProGuard的混淆

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

后会工作,而该代码将无法正常工作

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

此外,Proguard的会收缩多余的方法和构造函数。因此,Class.newInstance方法将不起作用。不幸的是,通常的Guice绑定使用这种方法。

这对Guice代码有一些影响。

  • 所有注射必须使用@Provides批注的方法生成,因为ProGuard会缩小类,因为它们的构造函数没有明确地调用。
  • Proguard不得缩小模块类的代码。
  • ProGuard不得收缩注释,不管它们在哪里和哪里(可以配置,但我不记得在哪里)。
+1

哇,这是一个可怕的消息,你必须使用@Provides方法来阻止ProGuard去除依赖关系。这需要一个工具来帮助。我认为它也可以工作(几乎同样令人讨厌)在proguard配置中保留一堆-keep行吗? – 2011-11-17 23:03:34

+0

也许是因为添加-keep注释会使重构效率降低,因为我们必须确保在输出jar中类名称是有效的。在我看来,在纯Java级别上运行会使我们的代码更符合重构(如果存在这种情况) – Riduidel 2011-11-18 13:43:05

7

需要“签名”属性才能在JDK 5.0和更高版本中编译时访问泛型类型。

使用-keepattributes签名来修复错误与ParameterizedType

+0

它没有解决上述示例中的问题。我仍然必须尝试使用​​google guice的原始问题。 – sme 2010-03-16 12:34:03

+1

这对我来说固定它在android上没有aop构建,我有与OP一样的问题。我也有以下proguard配置。 -keepclassmembers class * { @ com.google.inject.Inject (...); } – abombss 2010-11-18 05:26:08

+0

这也适用于我,与问题提问者一样的问题! – Peterdk 2011-04-30 18:36:51

0

下面的代码工作对我来说,有过同样的问题。

-keepattributes Signature是修复。

-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

使用ProGuard的当前版本(4.7)我能得到它的工作,加入以下内容: -

-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>(...); 
} 

除了明确保留由吉斯如

创建的任何类
-keep class com.example.Service 
+0

这种修改并不需要明确地加入你的@Inject类(如在其他职位说明是容易出错): '-keepclasseswithmembers,allowoptimization,allowobfuscation类* { @ com.google.inject.Inject ; } -keepclassmembers,allowobfuscation,allowoptimization class * { @ com.google.inject.Provides ; }' – enl8enmentnow 2014-08-22 17:24:20