Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with ProGuard and RoboGuice with @Inject annotations

I'm having some problems with proguard when optimizing my android app. It seems that there is something done to an annotation class (@com.google.inject.Inject) which Dalvik/Harmony is not happy with at runtime.

java.lang.annotation.IncompleteAnnotationException: The element optional is not complete for the annotation com.google.inject.Inject

com.google.inject.Inject looks like this (Part of Guice):

@Target(value={ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Documented
public abstract @interface com.google.inject.Inject extends Annotation {
  public abstract boolean optional() default false;
}

Here's the failure on launch:

04-07 09:48:00.864: ERROR/AndroidRuntime(9384): FATAL EXCEPTION: main
04-07 09:48:00.864: ERROR/AndroidRuntime(9384): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.bitgrind.wtb/com.bitgrind.wtb.activity.Main}: com.google.inject.b.q: com.google.inject.b.q: java.lang.annotation.IncompleteAnnotationException: The element optional is not complete for the annotation com.google.inject.Inject
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1622)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1638)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at android.app.ActivityThread.access$1500(ActivityThread.java:117)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:928)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at android.os.Handler.dispatchMessage(Handler.java:99)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at android.os.Looper.loop(Looper.java:123)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at android.app.ActivityThread.main(ActivityThread.java:3647)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at java.lang.reflect.Method.invokeNative(Native Method)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at java.lang.reflect.Method.invoke(Method.java:507)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at dalvik.system.NativeStart.main(Native Method)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384): Caused by: com.google.inject.b.q: com.google.inject.b.q: java.lang.annotation.IncompleteAnnotationException: The element optional is not complete for the annotation com.google.inject.Inject
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.do.a(MapMaker.java:553)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.do.a(MapMaker.java:419)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.w.get(CustomConcurrentHashMap.java:2041)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.av.b(FailableCache.java:46)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.q.a(ConstructorInjectorStore.java:52)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.n.a(ConstructorBindingImpl.java:57)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.aq.a(InjectorImpl.java:375)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.g.run(BindingProcessor.java:169)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.e.a(BindingProcessor.java:224)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.an.b(InjectorBuilder.java:120)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.an.a(InjectorBuilder.java:105)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.ab.a(Guice.java:92)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.ab.a(Guice.java:69)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.bitgrind.wtb.WTBApp.a(WTBApp.java:59)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at roboguice.application.RoboApplication.a_(RoboApplication.java:84)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at roboguice.activity.RoboActivity.a_(RoboActivity.java:192)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at roboguice.activity.RoboActivity.onCreate(RoboActivity.java:70)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.bitgrind.wtb.activity.Main.onCreate(Main.java:41)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1586)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     ... 11 more
04-07 09:48:00.864: ERROR/AndroidRuntime(9384): Caused by: com.google.inject.b.q: java.lang.annotation.IncompleteAnnotationException: The element optional is not complete for the annotation com.google.inject.Inject
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.do.a(MapMaker.java:553)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.do.a(MapMaker.java:419)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.w.get(CustomConcurrentHashMap.java:2041)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.av.b(FailableCache.java:46)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.br.a(MembersInjectorStore.java:66)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.q.b(ConstructorInjectorStore.java:69)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.q.a(ConstructorInjectorStore.java:31)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.r.a(ConstructorInjectorStore.java:35)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.aw.a(FailableCache.java:35)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.do.a(MapMaker.java:549)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     ... 30 more
04-07 09:48:00.864: ERROR/AndroidRuntime(9384): Caused by: java.lang.annotation.IncompleteAnnotationException: The element optional is not complete for the annotation com.google.inject.Inject
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at org.apache.harmony.lang.annotation.AnnotationFactory.invoke(AnnotationFactory.java:312)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at $Proxy1.optional(Native Method)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.e.n.<init>(InjectionPoint.java:85)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.e.p.a(InjectionPoint.java:384)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.e.n.a(InjectionPoint.java:353)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.e.n.b(InjectionPoint.java:295)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.br.b(MembersInjectorStore.java:78)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.br.a(MembersInjectorStore.java:35)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.bs.a(MembersInjectorStore.java:40)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.aw.a(FailableCache.java:35)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     at com.google.inject.b.do.a(MapMaker.java:549)
04-07 09:48:00.864: ERROR/AndroidRuntime(9384):     ... 39 more

And this is my (current) proguard.cfg: (I've tried many things)

-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-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

# Needed for RoboGuice, etc
-keepattributes SourceFile,LineNumberTable,RuntimeVisibleAnnotations,RuntimeVisibleParameterAnnotations,RuntimeVisibleFieldAnnotations
-keep public class com.google.inject.Inject
-keep,allowobfuscation public class com.google.inject.name.Named
-keep,allowobfuscation public class * implements com.google.inject.Provider
-keep,allowobfuscation @com.google.inject.Provides class *
-keep,allowobfuscation @com.google.inject.Provides class *
-keep,allowobfuscation @com.google.inject.ProvidedBy class * 
-keep,allowobfuscation @com.google.inject.Singleton class *
-keep,allowobfuscation @com.google.inject.BindingAnnotation class *
-keep,allowobfuscation @com.google.inject.ScopeAnnotation class *

-keep class com.google.inject.Binder

#-keep public class roboguice.**

-keepclassmembers class * {
    @com.google.inject.Inject <init>(...);
}

-keepclassmembers class com.google.inject.Inject {
    public boolean optional();
}

# Annotations
#-keepclasseswithmembernames class * {
#    public ** value();
#}

-keepclassmembers class * implements java.lang.annotation.Annotation { 
    ** *(); 
}

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

-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# Guava primitives lexicographicalComparator() references sun.misc.Unsafe dynamically 
# which is obviously not provided in the Android Runtime
-dontwarn sun.misc.Unsafe

# Slf4j api is in libs for the server side stuff, not used in the app
-dontwarn org.slf4j.*

# Other dynamically referenced methods in Guava
-keepclassmembers class com.google.guava.* {
    void finalizeReferent();
    void startFinalizer(java.lang.Class,java.lang.Object);
}

# newBuilder() is referenced dynamically in generated ProtoBuf code
-keepclassmembers class * {
    ** newBuilder();
}
like image 907
Mark Renouf Avatar asked Apr 07 '11 14:04

Mark Renouf


2 Answers

Doesn't look like you are keeping annotations. They will be totally stripped out since they have no effect on the execution of code, And that's real bad since the only way to retrieve then is with reflection.

Try adding

-keepattributes *Annotation*
like image 176
Robby Pond Avatar answered Oct 05 '22 22:10

Robby Pond


To get RoboGuice 2 working for me, I had to add the following to what I already had:

-keep class com.google.inject.** { *; } 
-keep class javax.inject.** { *; } 
-keep class javax.annotation.** { *; } 
-keep class roboguice.** { *; } 

And run it with the non-optimization version from the SDK. My project.properties follows. Note that it is proguard-android.txt not proguard-android-optimization.txt, followed by a colon character and my custom proguard.cfg which is in my project root directory.

/project.properties:

# ProGuard configuration
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard.cfg

My final, which is probably safer than I need:

/proguard.cfg:

-keepattributes Signature
-keepattributes *Annotation*
-keep class roboguice.**

# if not using Google Maps library, safe to ignore these
-dontwarn roboguice.activity.RoboMapActivity
# safe to ignore testing classes, when proguard not being run against an instrumentation testing app
-dontwarn roboguice.test.**

-keep class com.google.inject.** { *; } 
-keepclassmembers class * {
    @com.google.inject.Inject <fields>;
    @com.google.inject.Inject <init>(...);
}
-keep class javax.inject.** { *; } 
-keep class javax.annotation.** { *; } 

# My application classes used by injection framework
-keep class com.myapp.RoboGuiceModule { *; }
-keep class com.myapp.AppProvider { *; }
-keep class com.myapp.MyInjectableSingletonExample { *; }
# ... other classes that are referenced in my custom RoboGuiceModule.configure() bindings
like image 31
Jon Adams Avatar answered Oct 06 '22 00:10

Jon Adams