Error when injecting in POJOs

435 views
Skip to first unread message

Adrian-Costin Ţundrea

unread,
Jan 3, 2014, 1:56:00 PM1/3/14
to robo...@googlegroups.com
Hello,

I am a newbie when it comes to Android and Roboguice and in my project I have run into an (what I consider) weird issue when injecting into a few POJOs I use as services. I have the following case:

public class MyActivity extends RoboActivity {
    @Inject MyService1 myService1;
   
    @InjectView(R.id.resultTextView) TextView result;
}

public class MyService1 {
    @Inject
    MyService2 myService2;

    private Context context;

    @Inject
    public MyService1 (Provider<Context> contextProvider) {
        this.context = contextProvider.get(); 
    } 
}

public class MyService2 {
}

If I run this in debug mode there is no error, everything working as expected. However in release mode (with Proguard on... without optimizations) I get the following error:

java.lang.RuntimeException: Unable to start activity ComponentInfo{org.something.activity.MyActivity}: com.google.inject.ConfigurationException: Guice configuration errors:

1) Could not find a suitable constructor in org.something .c.b.a. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
at org.something.c.b.a.class(Unknown Source)
while locating org.something.c.b.a
for field at org.something.c.a.a.myService2(Unknown Source)
while locating org.something.c.a.a
for field at org.something.activity.MyActivity.myService1(Unknown Source)
while locating org.something.activity.MyActivity

From what I understand from the error it doesn't like the constructor from MyService2 although it is "zero-argument constructor that is not private" (the default one). However after many other attempts (as someone explained this situation very clear on http://stackoverflow.com/questions/8579272/roboguice-injecting-system-service) I have tried changing MyService 2:

public class MyService2 {
    @Inject
    public MyService1 (Provider<Context> contextProvider) {
    }
}

This is a "constructor annotated with @Inject"... but why does it work? Is the error message correct. Why do I need to inject the constructor of the last service?

Thanks for taking the time to read all this :)
Adrian

Michael Burton

unread,
Jan 3, 2014, 2:37:22 PM1/3/14
to robo...@googlegroups.com
Proguard is likely stripping out methods that aren't being called directly, but in fact are used by your app via reflection (injection)

--
You received this message because you are subscribed to the Google Groups "roboguice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to roboguice+...@googlegroups.com.
To post to this group, send email to robo...@googlegroups.com.
Visit this group at http://groups.google.com/group/roboguice.
For more options, visit https://groups.google.com/groups/opt_out.

Adrian-Costin Ţundrea

unread,
Jan 3, 2014, 2:45:49 PM1/3/14
to robo...@googlegroups.com
Here is my Proguard configuration... Also taken from stackoverflow as I couldn't find one for version 2 on Roboguice website. Is there anyway to make it safer?

#http://stackoverflow.com/questions/5582383/problem-with-proguard-and-roboguice-with-inject-annotations

-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 application!
-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.** { *; }

# Removing logging calls (verbose and debug levels) as per Google's Preparing for Release guide!
-assumenosideeffects class android.util.Log {
    public static *** v(...);
    public static *** d(...);
}

Adrian-Costin Ţundrea

unread,
Jan 3, 2014, 4:00:08 PM1/3/14
to robo...@googlegroups.com
Well I have played a little more with the configuration on StackOverflow and something I discarded initially seems to be very important.

-keep class org.something.myService2 { *; }

As you said probably Proguard doesn't find myService2's constructor used anywhere (since it is called by reflection by the injection framework) and decides to remove it. Hence the error message. Which does not happen if I declare it as injected. Am I close? And if so is there any easier way to make proguard work correctly... or at least ignore my classes... other then declaring them one by one which involves the risk of forgetting to add them once I create them.

Thank you for opening my eyes Michael,
Adrian




vineri, 3 ianuarie 2014, 21:37:22 UTC+2, Michael Burton a scris:

Michael Burton

unread,
Jan 3, 2014, 5:34:08 PM1/3/14
to robo...@googlegroups.com
I'm not a proguard expert unfortunately, anyone else?

I would use javap to decompile the proguarded class file and figure out what's missing, then use that information to figure out how to configure proguard.

Unrelated, you don't need to inject a provider into MyService2's constructor.  You can inject the Context directly.

Cheers,
Mike
Reply all
Reply to author
Forward
0 new messages