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();
}
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*
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With