8

誰かがグーグルのguiceの使用を難読化(特にプロガード)と組み合わせようとしたことがありますか?難読化されたバージョンのコードは、guiceが型パラメーターの欠落について不平を言っているため、googleguiceでは機能しません。この情報は、関連するクラスが難読化から除外されている場合でも、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)

問題を再現しているように見える小さな例を(guiceを使用せずに)作成しようとしました:

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

    }

}

このコードをsbfuscatedなしで実行すると、出力は次のようになります。

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

しかし、プロガードで難読化されたバージョンを実行すると、次のようになります。

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に入れて、それを難読化しないという明白な回避策は別として)?

よろしく、
ステファン

4

4 に答える 4

8

JDK 5.0 以降でコンパイルするときにジェネリック型にアクセスするには、"Signature" 属性が必要です。

-keepattributes Signature を使用して、ParameterizedType のエラーを修正します

于 2010-03-12T11:35:52.483 に答える
8

プロガードをかなりの時間使用してきたので、リフレクションに関する問題を解決する方法を以下に示します (Guice はその使用例にすぎません)。

クラス名またはメソッド名が文字列として入力されていない限り、Proguard でリフレクションを使用できます。

つまり、このコードは有効であり、ProGuard の難読化後に機能します。

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

このコードは機能しませんが

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

さらに、Proguard は呼び出されていないメソッドとコンストラクターを縮小します。結果として、このClass.newInstance方法は機能しません。残念ながら、通常の Guice バインディングはこの方法を使用して動作します。

これは Guice コードに影響を与えます。

  • コンストラクターが明示的に呼び出されないため、ProGuard はクラスを縮小するため、すべてのインジェクションは @Provides アノテーション付きメソッドを使用して生成する必要があります。
  • Proguard は、モジュール クラスのコードを圧縮してはなりません。
  • ProGuard は、注釈がどこにあっても縮小してはなりません (これは構成できますが、場所を思い出せません)。
于 2010-03-11T15:22:38.243 に答える
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>(...);
}

Guiceによって作成されたクラスを明示的に保持することに加えて、例えば

-keep class com.example.Service
于 2012-04-25T08:25:42.690 に答える
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>;
}
于 2011-04-30T18:45:05.473 に答える