Injection with google guice does not work anymore after obfuscation with proguard

Posted by sme on Stack Overflow See other posts from Stack Overflow or by sme
Published on 2010-03-03T09:16:19Z Indexed on 2010/03/12 11:37 UTC
Read the original article Hit count: 558

Filed under:
|
|

Has anyone ever tried to combine the use of google guice with obfuscation (in particular proguard)? The obfuscated version of my code does not work with google guice as guice complains about missing type parameters. This information seems to be erased by the transformation step that proguard does, even when the relevant classes are excluded from the obfuscation.

The stack trace looks like this:

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)

I tried to create a small example (without using guice) that seems to reproduce the problem:

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

    }

}

If you run this code unsbfuscated, the output looks like this:

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

But running the version obfuscated with proguard yields:

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

These are the options I used for 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);
}

Does anyone have an idea of how to solve this (apart from the obvious workaround to put the relevant files into a seperate jar and not obfuscate it)?

Best regards,
Stefan

© Stack Overflow or respective owner

Related posts about guice

Related posts about proguard