smallseo.info

dagger

A fast dependency injector for Android and Java. Dagger a fast dependency injector for android and java

Delayed Binding to Dagger2 Graph using Annotation Processing

In this question I talk about Dagger2. Dagger2 consists basically of Components and Modules. Here is an example:

Assume I have a interface:

public interface MyCoolService {
  void run();
}

and a possible implementation:

public class MyCoolServiceImpl {
   @Override
   void run() {}
}

I could link the implementation with the interface using Dagger2 generating:

@Component(modules = {MyModule.class})
@Singleton
public interface Component {    
    MyCoolService getMyCoolService();       
}

and

@Module
public class MyModule {

    @Provides @Singleton
    MyCoolService provideMyCoolService() {
        return new MyCoolServiceImpl();
    }
}

This was a brief intro to Dagger2. Now assume I have the following interface:

public interface MySecondCoolService {
  void doCoolStuff();
}

There is no implementation MySecondCoolServiceImpl of MySecondCoolService in code. Instead, I have an Annotations @JustForCoolStuff to mark fields and methods. I created an Annotation processor which collects all these Annotations and generates MySecondCoolServiceImpl which implements MySecondCoolService.

I the compiler knows the new interface MySecondCoolService before the annotation processor is running. So I could change my Component as:

@Component(modules = {MyModule.class})
@Singleton
public interface Component {    
    MyCoolService getMyCoolService();   
    MySecondCoolService getMySecondCoolService();    
}    

The problem is that I do not have an implementation yet in code and I do not know the name of the implementation of MySecondCoolService which will be generated by a annotation processor. Therefore, I cannot wire the interface with the correct implemantation in MyModule. What I can do is changing my annotation processor such that it generates a new module for me. My annotation processor could generate a module (MyGeneratedModule) like this:

@Module
public class MyGeneratedModule {

    @Provides @Singleton
    MySecondCoolService provide MySecondCoolService() {
        return new MySecondCoolServiceImpl();
    }
}  

Again MyGeneratedModule is generated by an annotation processor. I do not have access to it before running the annotation processor also I do not know the name.

Here is the problem: The annotation processor somehow have to tell Dagger2 that there is a new module which Dagger2 should take into account. Since annotation processors cannot change files it cannot extend the @Component(modules = {MyModule.class}) annotation and change it into something like this: @Component(modules = {MyModule.class, MyGeneratedModule.class})

Is there a way to add MyGeneratedModule programmatically to the dagger2 dependency graph? How can my Annotation Processor tell Dagger2 that there should be a new wiring between an interface and an implementation as I have described above?


Foray: I know that something like that can be done in Google Guice and Google Gin. A project which does that is GWTP. There you have a Presenter:

public class StartPagePresenter extends ... {
    @NameToken("start")
    public interface MyProxy extends ProxyPlace<StartPagePresenter> {
    }
    ...
}

which has a @NameToken annotation to a ProxyPlace interface. In your AbstractPresenterModule you wire the view with the presenter and the proxy:

public class ApplicationModule extends AbstractPresenterModule {

        bindPresenter(StartPagePresenter.class,
                StartPagePresenter.MyView.class, StartPageView.class,
                StartPagePresenter.MyProxy.class);
       ...
}

As so can see no implementation of the MyProxy interface is given. The implementation created by a Generator (similar to annotation processor but for GWT). There Generator generates the implementation of StartPagePresenter.MyProxy and add it to the guide/gin system:

public class StartPagePresenterMyProxyImpl extends com.gwtplatform.mvp.client.proxy.ProxyPlaceImpl<StartPagePresenter> implements buddyis.mobile.client.app.start.StartPagePresenter.MyProxy, com.gwtplatform.mvp.client.DelayedBind {

  private com.gwtplatform.mvp.client.ClientGinjector ginjector;
    @Override
    public void delayedBind(Ginjector baseGinjector) {
      ginjector = (com.gwtplatform.mvp.client.ClientGinjector)baseGinjector;
      bind(ginjector.getPlaceManager(),
          ginjector.getEventBus());
      presenter = new CodeSplitProvider<StartPagePresenter>( ginjector.getbuddyismobileclientappstartStartPagePresenter() );
    ...
    }
  }


Source: (StackOverflow)

AndroidAnnotations and Dagger

I'm trying to use Dagger to inject into an android Annotated Activity.

java.lang.IllegalArgumentException: No inject registered for members/com.app.server.AddServerActivity_. You must explicitly add it to the 'injects' option in one of your modules.

If I try and Add the com.app.server.AddServerActivity_ to the module I get a diffrent error

Error: java.lang.ClassCastException: com.sun.tools.javac.code.Attribute$Error cannot be cast to com.sun.tools.javac.code.Attribute$Class
java.lang.RuntimeException: java.lang.ClassCastException: com.sun.tools.javac.code.Attribute$Error cannot be cast to com.sun.tools.javac.code.Attribute$Class
    at com.sun.tools.javac.main.Main.compile(Main.java:469)
    at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:132)
    at org.jetbrains.jps.javac.JavacMain.compile(JavacMain.java:167)
    at org.jetbrains.jps.incremental.java.JavaBuilder.compileJava(JavaBuilder.java:364)
    at org.jetbrains.jps.incremental.java.JavaBuilder.compile(JavaBuilder.java:276)
    at org.jetbrains.jps.incremental.java.JavaBuilder.doBuild(JavaBuilder.java:190)
    at org.jetbrains.jps.incremental.java.JavaBuilder.build(JavaBuilder.java:162)
    at org.jetbrains.jps.incremental.IncProjectBuilder.runModuleLevelBuilders(IncProjectBuilder.java:1018)
    at org.jetbrains.jps.incremental.IncProjectBuilder.runBuildersForChunk(IncProjectBuilder.java:742)
    at org.jetbrains.jps.incremental.IncProjectBuilder.buildTargetsChunk(IncProjectBuilder.java:790)
    at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunkIfAffected(IncProjectBuilder.java:705)
    at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunks(IncProjectBuilder.java:526)
    at org.jetbrains.jps.incremental.IncProjectBuilder.runBuild(IncProjectBuilder.java:314)
    at org.jetbrains.jps.incremental.IncProjectBuilder.build(IncProjectBuilder.java:179)
    at org.jetbrains.jps.cmdline.BuildRunner.runBuild(BuildRunner.java:129)
    at org.jetbrains.jps.cmdline.BuildSession.runBuild(BuildSession.java:220)
    at org.jetbrains.jps.cmdline.BuildSession.run(BuildSession.java:112)
    at org.jetbrains.jps.cmdline.BuildMain$MyMessageHandler$1.run(BuildMain.java:132)
    at org.jetbrains.jps.service.impl.SharedThreadPoolImpl$1.run(SharedThreadPoolImpl.java:41)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.ClassCastException: com.sun.tools.javac.code.Attribute$Error cannot be cast to com.sun.tools.javac.code.Attribute$Class
    at com.sun.tools.javac.model.AnnotationProxyMaker$ValueVisitor.visitArray(AnnotationProxyMaker.java:190)
    at com.sun.tools.javac.code.Attribute$Array.accept(Attribute.java:215)
    at com.sun.tools.javac.model.AnnotationProxyMaker$ValueVisitor.getValue(AnnotationProxyMaker.java:165)
    at com.sun.tools.javac.model.AnnotationProxyMaker.generateValue(AnnotationProxyMaker.java:143)
    at com.sun.tools.javac.model.AnnotationProxyMaker.getAllReflectedValues(AnnotationProxyMaker.java:101)
    at com.sun.tools.javac.model.AnnotationProxyMaker.generateAnnotation(AnnotationProxyMaker.java:86)
    at com.sun.tools.javac.model.AnnotationProxyMaker.generateAnnotation(AnnotationProxyMaker.java:78)
    at com.sun.tools.javac.model.JavacElements.getAnnotation(JavacElements.java:108)
    at com.sun.tools.javac.model.JavacElements.getAnnotation(JavacElements.java:121)
    at com.sun.tools.javac.code.Symbol$ClassSymbol.getAnnotation(Symbol.java:888)
    at dagger.internal.codegen.ValidationProcessor.validateProvides(ValidationProcessor.java:75)
    at dagger.internal.codegen.ValidationProcessor.process(ValidationProcessor.java:67)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:793)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:722)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1700(JavacProcessingEnvironment.java:97)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1029)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1163)
    at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1108)
    at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:824)
    at com.sun.tools.javac.main.Main.compile(Main.java:439)
    ... 24 more

Edit: ok, it seems to be a known issue with how dagger deals with classes generated by other processors.

https://github.com/square/dagger/issues/322


Source: (StackOverflow)

getting Dagger to inject mock objects when doing espresso functional testing for Android

I've recently gone whole-hog with Dagger because the concept of DI makes complete sense. One of the nicer "by-products" of DI (as Jake Wharton put in one of his presentations) is easier testability.

So now i'm basically using espresso to do some functional testing, and i want to be able to inject dummy/mock data to the application and have the activity show them up. I'm guessing since, this is one of the biggest advantages of DI, this should be a relatively simple ask. For some reason though, I can't seem to wrap my head around it. Any help would be much appreciated. Here's what i have so far (I've written up an example that reflects my current setup):

public class MyActivity
    extends MyBaseActivity {

    @Inject Navigator _navigator;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyApplication.get(this).inject(this);

        // ...

        setupViews();
    }

    private void setupViews() {
        myTextView.setText(getMyLabel());
    }

    public String getMyLabel() {
        return _navigator.getSpecialText(); // "Special Text"
    }
}

These are my dagger modules:

// Navigation Module

@Module(library = true)
public class NavigationModule {

    private Navigator _nav;

    @Provides
    @Singleton
    Navigator provideANavigator() {
        if (_nav == null) {
            _nav = new Navigator();
        }
        return _nav;
    }
}

// App level module

@Module(
    includes = { SessionModule.class, NavigationModule.class },
    injects = { MyApplication.class,
                MyActivity.class,
                // ...
})
public class App {
    private final Context _appContext;
    AppModule(Context appContext) {
        _appContext = appContext;
    }
    // ...
}

In my Espresso Test, I'm trying to insert a mock module like so:

public class MyActivityTest
    extends ActivityInstrumentationTestCase2<MyActivity> {

    public MyActivityTest() {
        super(MyActivity.class);
    }

  @Override
  public void setUp() throws Exception {
      super.setUp();
      ObjectGraph og = ((MyApplication) getActivity().getApplication()).getObjectGraph().plus(new TestNavigationModule());
      og.inject(getActivity());
  }

    public void test_SeeSpecialText() {
        onView(withId(R.id.my_text_view)).check(matches(withText(
            "Special Dummy Text)));
    }

    @Module(includes = NavigationModule.class,
            injects = { MyActivityTest.class, MyActivity.class },
            overrides = true,
            library = true)
    static class TestNavigationModule {

        @Provides
        @Singleton
        Navigator provideANavigator() {
            return new DummyNavigator(); // that returns "Special Dummy Text"
        }
    }
}

This is not working at all. My espresso tests run, but the TestNavigationModule is completely ignored... arr... :(

What am i doing wrong? Is there a better approach to mocking modules out with Espresso. I've searched and seen examples of Robolectric, Mockito etc. being used. But I just want pure Espresso tests and need to swap out a module with my mock one. How should i be doing this?

EDIT:

So i went with @user3399328 approach of having a static test module list definition, checking for null and then adding it in my Application class. I'm still not getting my Test injected version of the class though. I have a feeling though, its probably something wrong with dagger test module definition, and not my espresso lifecycle. The reason i'm making the assumption is that i add debug statements and find that the static test module is non-empty at time of injection in the application class. Could you point me to a direction of what i could possibly be doing wrong. Here are code snippets of my definitions:

MyApplication:

@Override
public void onCreate() {
    // ...
    mObjectGraph = ObjectGraph.create(Modules.list(this));
    // ...   
}

Modules:

public class Modules {

    public static List<Object> _testModules = null;

    public static Object[] list(MyApplication app) {
        //        return new Object[]{ new AppModule(app) };
        List<Object> modules = new ArrayList<Object>();
        modules.add(new AppModule(app));

        if (_testModules == null) {
            Log.d("No test modules");
        } else {
            Log.d("Test modules found");
        }

        if (_testModules != null) {
            modules.addAll(_testModules);
        }

        return modules.toArray();
    }
}   

Modified test module within my test class:

@Module(overrides = true, library = true)
public static class TestNavigationModule {

    @Provides
    @Singleton
    Navigator provideANavigator()() {
        Navigator navigator = new Navigator();
        navigator.setSpecialText("Dummy Text");
        return navigator;
    }
}

Source: (StackOverflow)

Dagger on default constructors

I am trying to get Dagger up an working on my project.

However I get the following exception on one of my classes during compilation:

error: No injectable members on Foo. Do you want to add an injectable constructor?

However, the class have no dependencies and as such uses the default no-arg constructor:

public class Foo
{
    ...
}

Do I really have to add an injectable no-arg constructor like below?

public class Foo
{
     @Inject
     public Foo()
     {
     }

     ....
}

Source: (StackOverflow)

NPE when getting Robolectric ShadowApplication with Volley and Dagger

In my Android application I have set up Volley.

Robolectric.application is initialized and all other tests runs smoothly. I get this error when trying to get mocked HTTP response.

This is my test:

@RunWith(MyRobolectricTestRunner.class)
public class ApiTests {

    @Inject
    protected Api api;

    @Before
    public void setUp() {
        ObjectGraph.create(new AndroidModule(Robolectric.application), new TestApplicationModule()).inject(this);
    }

    @Test
    public void shouldGetErrorList() throws Exception {
        Project project = new Project("test", "test", "test", DateTime.now());
        addPendingProjectsErrorsResponse("response.json"); //adding response to FakeHttpLayer

        api.getProjectErrors(project, new Listener<ProjectErrors>() {
                @Override
                public void onResponse(ProjectErrors response) {
                    assertNotNull(response);
                }
            }, new ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    throw new RuntimeException(error);
                }
            }
        );
    }
}

This is error I get:

Exception in thread "Thread-3" java.lang.NullPointerException
    at org.robolectric.shadows.ShadowLooper.getMainLooper(ShadowLooper.java:59)
    at android.os.Looper.getMainLooper(Looper.java)
    at org.robolectric.Robolectric.getUiThreadScheduler(Robolectric.java:1301)
    at org.robolectric.shadows.ShadowSystemClock.now(ShadowSystemClock.java:15)
    at org.robolectric.shadows.ShadowSystemClock.uptimeMillis(ShadowSystemClock.java:25)
    at org.robolectric.shadows.ShadowSystemClock.elapsedRealtime(ShadowSystemClock.java:30)
    at android.os.SystemClock.elapsedRealtime(SystemClock.java)
    at com.android.volley.VolleyLog$MarkerLog.add(VolleyLog.java:114)
    at com.android.volley.Request.addMarker(Request.java:174)
    at com.android.volley.CacheDispatcher.run(CacheDispatcher.java:92)

Source: (StackOverflow)

Square Dagger IllegalStateException: Module adapter for class MyApplicationModule could not be loaded

I am using eclipse and Dagger 1.2.2 for my Android project. I managed to implement a test application with Dagger. But with my "real" application I get:

java.lang.RuntimeException: Unable to create application app.MyApplication: java.lang.IllegalStateException: Module adapter for class app.MyApplicationModule could not be loaded. Please ensure that code generation was run for this module.:

FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to create application app.MyApplication: java.lang.IllegalStateException: Module adapter for class app.MyApplicationModule could not be loaded. Please ensure that code generation was run for this module.
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4687)
    at android.app.ActivityThread.access$1400(ActivityThread.java:159)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1376)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5419)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: Module adapter for class app.MyApplicationModule could not be loaded. Please ensure that code generation was run for this module.
    at dagger.internal.FailoverLoader$1.create(FailoverLoader.java:45)
    at dagger.internal.FailoverLoader$1.create(FailoverLoader.java:40)
    at dagger.internal.Memoizer.get(Memoizer.java:56)
    at dagger.internal.FailoverLoader.getModuleAdapter(FailoverLoader.java:57)
    at dagger.internal.Modules.loadModules(Modules.java:43)
    at dagger.ObjectGraph$DaggerObjectGraph.makeGraph(ObjectGraph.java:174)
    at dagger.ObjectGraph$DaggerObjectGraph.access$000(ObjectGraph.java:138)
    at dagger.ObjectGraph.create(ObjectGraph.java:129)
    at app.MyApplication.onCreate(MyApplication.java:17)
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1024)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4684)
    ... 10 more

This is MyApplication.java:

public class MyApplication extends Application implements InjectableApplication {
    private ObjectGraph objectGraph;

    @Override
    public void onCreate() {
        super.onCreate();

        objectGraph = ObjectGraph.create(new MyApplicationModule(this));
        objectGraph.inject(this);
    }

    @Override
    public void inject(Object o) {
        objectGraph.inject(o);
    }

    public ObjectGraph getObjectGraph() {
        return objectGraph;
    }
}

This is my AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="app"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="18"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:name="app.MyApplication" >
        <activity
            android:name="app.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

I also included the Dagger jars to the build path and factory path.


Source: (StackOverflow)

How to configure dagger + gradle

I have a project and migrating to gradle dependency, but I find myself with an issue trying to setup dagger with gradle, the first time I compile it work perfectly (or if I clean) but if I try it twice then it gives me error like:

Error:(13, 14) error: duplicate class: com.myapp.android.application.InjectingApplication$InjectingApplicationModule$$ModuleAdapter

I try using android-apt plugin and configured as in the documentation but I still get the same error (https://bitbucket.org/hvisser/android-apt/overview)

I also try using provided dependency instead like in this tutorial (https://github.com/frankdu/android-gradle-dagger-tutorial) of compile but no luck so far.

Do you have any ideas how to configure dagger and gradle?

EDIT

My build.gradle looks like this

apply plugin: 'android'
apply plugin: 'android-apt'

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.2"

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 19
        packageName "com.myapp.android"

    }

    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}


dependencies {
    compile project(':volley')
    apt 'com.squareup.dagger:dagger-compiler:1.2.0'
    compile 'com.squareup.dagger:dagger:1.2.0'
}

And my top level build.gradle look like this

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.9.+'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.2'
    }
}

allprojects {
    repositories {
        mavenCentral()
    }
}

EDIT#2:

I tried with provided again as @Marco suggested no luck, I don't know if there is a library or a version of gradle that could be causing this problem, I'm currently using 1.10. On the bright side I did find a way to make it work, but I would love to do it by just adding the provided statement. The way I did it is the old way:

Define apt configuration

configurations {
     apt
}

add Dagger compiler lib

apt 'com.squareup.dagger:dagger-compiler:1.2.0'

And implement the this hook to applicationVariant which as far as I know android-apt does something similar. Does this make sense? why?

def getSourceSetName(variant) {
    return new File(variant.dirName).getName();
}

android.applicationVariants.each { variant ->
    def aptOutputDir = project.file("build/source/apt")
    def aptOutput = new File(aptOutputDir, variant.dirName)


    android.sourceSets[getSourceSetName(variant)].java.srcDirs+= aptOutput.getPath()

    variant.javaCompile.options.compilerArgs += [
            '-processorpath', configurations.apt.getAsPath(),
            '-s', aptOutput
    ]

    variant.javaCompile.source = variant.javaCompile.source.filter { p ->
        return !p.getPath().startsWith(aptOutputDir.getPath())
    }

    variant.javaCompile.doFirst {
        aptOutput.mkdirs()
    }
}

Source: (StackOverflow)

Android studio gradle duplicate files dagger compiler

having strange problem after updating android studio to 0.4.0 and gradle plugin to 0.7.1 and gradle version to 1.9 with dagger compiler

build.gradle

android {
packagingOptions {
    exclude 'META-INF/DEPENDENCIES.txt'
    exclude 'META-INF/LICENSE.txt'
    exclude 'META-INF/NOTICE.txt'
}
}
    dependencies {
    compile 'com.android.support:support-v4:+'
    compile 'com.android.support:support-v13:19.0.+'
    compile 'com.google.code.gson:gson:2.2.4'
    compile 'com.squareup.dagger:dagger:1.2.0'
    compile 'com.squareup.dagger:dagger-compiler:1.2.0'
}

on build getting this error

Execution failed for task ':MyApplication:packageDebug'.

Duplicate files copied in APK META-INF/services/javax.annotation.processing.Processor File 1: C:\Users\Mantas.gradle\caches\modules-2\files-2.1\com.squareup.dagger\dagger-compiler\1.2.0\22633bb84433e03d345a83e7b0c08c66768be30\dagger-compiler-1.2.0.jar File 2: C:\Users\Mantas.gradle\caches\modules-2\files-2.1\com.squareup.dagger\dagger-compiler\1.2.0\22633bb84433e03d345a83e7b0c08c66768be30\dagger-compiler-1.2.0.jar

if dagger compiler lines is commented everything works fine

how can i solve this problem? thanks

EDITED fixed problem, check https://plus.google.com/+HugoVisser/posts/7Wr3FcdNVxR


Source: (StackOverflow)

Android functional testing with Dagger

I’m trying to test an Activity with Mockito & Dagger. I have been able to inject dependencies to Activity in my application but when testing the Activity, I have not been able to inject mock to the Activity. Should I inject Activity to test or let getActivity() create it?

public class MainActivityTest extends
    ActivityInstrumentationTestCase2<MainActivity> {

@Inject Engine engineMock;
private MainActivity mActivity;
private Button mLogoutBtn;


public MainActivityTest() {
    super(MainActivity.class);
}

@Override
protected void setUp() throws Exception {
    super.setUp();

    // Inject engineMock to test
    ObjectGraph.create(new TestModule()).inject(this);
}

@Override
protected void tearDown() {
    if (mActivity != null)
        mActivity.finish();
}

 @Module(
 includes = MainModule.class,
 entryPoints = MainActivityTest.class,
 overrides = true
 )

static class TestModule {
    @Provides
    @Singleton
    Engine provideEngine() {
        return mock(Engine.class);
    }
}

@UiThreadTest
public void testLogoutButton() {

    when(engineMock.isLoggedIn()).thenReturn(true);

    mActivity = getActivity();
    mLogoutBtn = (Button) mActivity.findViewById(R.id.logoutButton);

    // how to inject engineMock to Activity under test?
    ObjectGraph.create(new TestModule()).inject(this.mActivity);

    assertTrue(mLogoutBtn.isEnabled() == true);
}
}

Source: (StackOverflow)

Using Dagger for dependency injection on constructors

So, I'm currently redesigning an Android app of mine to use Dagger. My app is large and complicated, and I recently came across the following scenario:

Object A requires a special DebugLogger instance which is a perfect candidate for injection. Instead of passing around the logger I can just inject it through A's constructor. This looks something like this:

class A
{
    private DebugLogger logger;

    @Inject
    public A(DebugLogger logger)
    {
        this.logger = logger;
    }

    // Additional methods of A follow, etc.
}

So far this makes sense. However, A needs to be constructed by another class B. Multiple instances of A must be constructed, so following Dagger's way of doing things, I simple inject a Provider<A> into B:

class B
{
    private Provider<A> aFactory;

    @Inject
    public B(Provider<A> aFactory)
    {
        this.aFactory = aFactory;
    }
}

Ok, good so far. But wait, suddenly A needs additional inputs, such as an integer called "amount" that is vital to its construction. Now, my constructor for A needs to look like this:

@Inject
public A(DebugLogger logger, int amount)
{
...
}

Suddenly this new parameter interferes with injection. Moreover, even if this did work, there would be no way for me to pass in "amount" when retrieving a new instance from the provider, unless I am mistaken. There's several things I could do here, and my question is which one is the best?

I could refactor A by adding a setAmount() method that is expected to be called after the constructor. This is ugly, however, because it forces me to delay construction of A until "amount" has been filled in. If I had two such parameters, "amount" and "frequency", then I would have two setters, which would mean either complicated checking to ensure that construction of A resumes after both setters are called, or I would have to add yet a third method into the mix, like so:

(Somewhere in B):

A inst = aFactory.get();
inst.setAmount(5);
inst.setFrequency(7);
inst.doConstructionThatRequiresAmountAndFrequency();

The other alternative is that I don't use constructor-based injection and go with field-based injection. But now, I have to make my fields public. This doesn't sit well with me, because now I am obligated to reveal internal data of my classes to other classes.

So far, the only somewhat elegant solution I can think of is to use field-based injection for providers, like so:

class A
{
    @Inject
    public Provider<DebugLogger> loggerProvider;
    private DebugLogger logger;

    public A(int amount, int frequency)
    {
        logger = loggerProvider.get();
        // Do fancy things with amount and frequency here
        ...
    }
}

Even still, I'm unsure about the timing, since I'm not sure if Dagger will inject the provider before my constructor is called.

Is there a better way? Am I just missing something about how Dagger works?


Source: (StackOverflow)

Dagger can't find injectable members on a module

I'm using Dagger for dependency injection in an Android project, and can compile and build the app fine. The object graph appears to be correct and working, but when I add dagger-compiler as a dependency to get errors at compile time, it reports some bizarre errors:

[ERROR] error: No binding for com.squareup.tape.TaskQueue<com.atami \
    .mgodroid.io.NodeIndexTask> required by com.atami \
    .mgodroid.ui.NodeIndexListFragment for com.atami.mgodroid \
    .modules.OttoModule
[ERROR] error: No binding for com.squareup.tape.TaskQueue<com.atami \
    .mgodroid.io.NodeTask> required by com.atami \
    .mgodroid.ui.NodeFragment for com.atami.mgodroid.modules.OttoModule
[ERROR] error: No injectable members on com.squareup.otto.Bus. Do you want 
     to add an injectable constructor? required by com.atami. \
     mgodroid.io.NodeIndexTaskService for 
     com.atami.mgodroid.modules.TaskQueueModule

The Otto error looks like the one Eric Burke mentions in his Android App Anatomy presentation about not having a @Provides annotation, but as you can see below I do.

My Otto and TaskQueue modules are as follows:

@Module(
        entryPoints = {
                MGoBlogActivity.class,
                NodeIndexListFragment.class,
                NodeFragment.class,
                NodeActivity.class,
                NodeCommentFragment.class,
                NodeIndexTaskService.class,
                NodeTaskService.class
        }
)
public class OttoModule {

    @Provides
    @Singleton
    Bus provideBus() {
        return new AsyncBus();
    }

    /**
     * Otto EventBus that posts all events on the Android main thread
     */
    private class AsyncBus extends Bus {
        private final Handler mainThread = new Handler(Looper.getMainLooper());

        @Override
        public void post(final Object event) {
            mainThread.post(new Runnable() {
                @Override
                public void run() {
                    AsyncBus.super.post(event);
                }
            });
        }
    }
}

...

@Module(
    entryPoints = {
        NodeIndexListFragment.class,
        NodeFragment.class,
        NodeIndexTaskService.class,
        NodeTaskService.class
    }
)
public class TaskQueueModule {

    private final Context appContext;

    public TaskQueueModule(Context appContext) {
        this.appContext = appContext;
    }

    public static class IOTaskInjector<T extends Task> 
        implements TaskInjector<T> {

        Context context;

        /**
         * Injects Dagger dependencies into Tasks added to TaskQueues
         *
         * @param context the application Context
         */
        public IOTaskInjector(Context context) {
            this.context = context;
        }

        @Override
        public void injectMembers(T task) {
            ((MGoBlogApplication) context.getApplicationContext())
                .objectGraph().inject(task);
        }
    }

    public static class ServiceStarter<T extends Task> 
        implements ObjectQueue.Listener<T> {

        Context context;
        Class<? extends Service> service;

        /**
         * Starts the provided service when a Task is added to the queue
         *
         * @param context the application Context
         * @param service the Service to start
         */
        public ServiceStarter(Context context, 
                              Class<? extends Service> service) {
            this.context = context;
            this.service = service;
        }

        @Override
        public void onAdd(ObjectQueue<T> queue, T entry) {
            context.startService(new Intent(context, service));

        }

        @Override
        public void onRemove(ObjectQueue<T> queue) {
        }
    }


    @Provides
    @Singleton
    TaskQueue<NodeIndexTask> provideNodeIndexTaskQueue() {
        ObjectQueue<NodeIndexTask> delegate = 
            new InMemoryObjectQueue<NodeIndexTask>();
        TaskQueue<NodeIndexTask> queue = new TaskQueue<NodeIndexTask>(
            delegate, new IOTaskInjector<NodeIndexTask>(appContext));
        queue.setListener(new ServiceStarter<NodeIndexTask>(
            appContext, NodeIndexTaskService.class));
        return queue;
    }

    @Provides
    @Singleton
    TaskQueue<NodeTask> provideNodeTaskQueue() {
        ObjectQueue<NodeTask> delegate = 
            new InMemoryObjectQueue<NodeTask>();
        TaskQueue<NodeTask> queue = new TaskQueue<NodeTask>(
            delegate, new IOTaskInjector<NodeTask>(appContext));
        queue.setListener(new ServiceStarter<NodeTask>(
            appContext, NodeTaskService.class));
        return queue;
    }
}

...

/**
 * Module that includes all of the app's modules. Used by Dagger
 * for compile time validation of injections and modules.
 */
@Module(
        includes = {
                MGoBlogAPIModule.class,
                OttoModule.class,
                TaskQueueModule.class
        }
)
public class MGoBlogAppModule {
}

Source: (StackOverflow)

Dagger code giving NoClassDefFoundError when Espresso Tests are run, normal run works fine

Started exploring Espresso 2.0, but seem to have run into a hiccup. I cannot get the tests to successfully run against any project which includes Dagger. When I run the tests I get the following Exception (entire stacktrace at the end):

java.lang.NoClassDefFoundError: com/pdt/daggerexample/model/DaggerExampleAppModule$$ModuleAdapter$ProvideMySingletonProvidesAdapter

The application runs when not running from the AndroidInstrumentationTest.

Here are some of the relevant files, I've also uploaded the project to github to allow for a quicker checkout/reproduction https://github.com/paul-turner/espressoDaggerExample.

build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.pdt.daggerexample"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        minSdkVersion 16
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            minifyEnabled false
        }


    }

    packagingOptions {
        exclude 'LICENSE.txt'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.jakewharton:butterknife:5.1.1'
    compile 'com.squareup.dagger:dagger:1.2.2'
    provided 'com.squareup.dagger:dagger-compiler:1.2.2'
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
    androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
}

Test:

public class SampleEspressoTest extends ActivityInstrumentationTestCase2<MainActivity> {

    public SampleEspressoTest() {
        super(MainActivity.class);
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();
        // Espresso will not launch our activity for us, we must launch it via getActivity().
        getActivity();
    }

    public void testCheckText() {
        onView(ViewMatchers.withId(com.pdt.daggerexample.R.id.espresso_test))
                .check(matches(withText("Espresso Test")));
    }
}

Module:

package com.pdt.daggerexample.model;

import com.pdt.daggerexample.inject.DaggerExampleApplication;
import com.pdt.daggerexample.MainActivity;
import com.pdt.daggerexample.SecondActivity;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module(injects = {
        MainActivity.class,
        SecondActivity.class,
}, complete = true)

public class DaggerExampleAppModule {

    private final DaggerExampleApplication mDaggerExampleApplication;

    public DaggerExampleAppModule(DaggerExampleApplication daggerExampleApplication) {
        mDaggerExampleApplication = daggerExampleApplication;
    }

    @Provides
    @Singleton
    public MySingleton provideMySingleton() {
        return new MySingleton(mDaggerExampleApplication.getApplicationContext(), "FOOBAR!");
    }

    @Provides
    public MyRegularOldClassInstance provideMyRegularOldClassInstance() {
        return new MyRegularOldClassInstance();
    }

}

Stacktrace:

    12-24 15:18:17.986    1282-1282/? E/MonitoringInstrumentation﹕ Dying now...
    12-24 15:18:17.986    1282-1282/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
        java.lang.NoClassDefFoundError: com/pdt/daggerexample/model/DaggerExampleAppModule$$ModuleAdapter$ProvideMySingletonProvidesAdapter
                at com.pdt.daggerexample.model.DaggerExampleAppModule$$ModuleAdapter.getBindings(DaggerExampleAppModule$$ModuleAdapter.java:28)
                at com.pdt.daggerexample.model.DaggerExampleAppModule$$ModuleAdapter.getBindings(DaggerExampleAppModule$$ModuleAdapter.java:13)
                at dagger.ObjectGraph$DaggerObjectGraph.makeGraph(ObjectGraph.java:185)
                at dagger.ObjectGraph$DaggerObjectGraph.access$000(ObjectGraph.java:138)
                at dagger.ObjectGraph.create(ObjectGraph.java:129)
                at com.pdt.daggerexample.inject.DaggerExampleApplication.onCreate(DaggerExampleApplication.java:16)
                at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:999)
                at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4151)
                at android.app.ActivityThread.access$1300(ActivityThread.java:130)
                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1255)
                at android.os.Handler.dispatchMessage(Handler.java:99)
                at android.os.Looper.loop(Looper.java:137)
                at android.app.ActivityThread.main(ActivityThread.java:4745)
                at java.lang.reflect.Method.invokeNative(Native Method)
                at java.lang.reflect.Method.invoke(Method.java:511)
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
                at dalvik.system.NativeStart.main(Native Method)
         Caused by: java.lang.ClassNotFoundException: com.pdt.daggerexample.model.DaggerExampleAppModule$$ModuleAdapter$ProvideMySingletonProvidesAdapter
                at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)
                at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
                at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
                at com.pdt.daggerexample.model.DaggerExampleAppModule$$ModuleAdapter.getBindings(DaggerExampleAppModule$$ModuleAdapter.java:28)
                at com.pdt.daggerexample.model.DaggerExampleAppModule$$ModuleAdapter.getBindings(DaggerExampleAppModule$$ModuleAdapter.java:13)
                at dagger.ObjectGraph$DaggerObjectGraph.makeGraph(ObjectGraph.java:185)
                at dagger.ObjectGraph$DaggerObjectGraph.access$000(ObjectGraph.java:138)
                at dagger.ObjectGraph.create(ObjectGraph.java:129)
                at com.pdt.daggerexample.inject.DaggerExampleApplication.onCreate(DaggerExampleApplication.java:16)
                at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:999)
                at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4151)
                at android.app.ActivityThread.access$1300(ActivityThread.java:130)
                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1255)
                at android.os.Handler.dispatchMessage(Handler.java:99)
                at android.os.Looper.loop(Looper.java:137)
                at android.app.ActivityThread.main(ActivityThread.java:4745)
                at java.lang.reflect.Method.invokeNative(Native Method)
                at java.lang.reflect.Method.invoke(Method.java:511)
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
                at dalvik.system.NativeStart.main(Native Method)

Source: (StackOverflow)

How to use dagger in a android library project

I'm currently trying to add Dagger to my android projects. For the apps projects its easy and clear to me, how to build the ObjectGraph. But I dont quite know whats the best way to do this in my android library projects.

Should I keep building the ObjectGraph in the Application class of the apps and pass the OG over to a LibraryModule - plussing the OG of library to the Apps OG? Or should i build the whole ObjectGraph in the library?

What if I need to inject a class in the library by ObjectGraph.inject(this)? In my Apps projects I can get the OG from the Application class. But how to handle this in the library? Should I add a @Provides method for the ObjectGraph?

Big thanks for your help.

Edit: In short: How can I call ObjectGraph.inject(this) in my library project where I don't have access to the OG because it is being builded in the Application Class?


Source: (StackOverflow)

Dagger example built through eclipse fails with 'Please ensure that code generation was run for this module.'

I'm using Dagger for dependency injection in Android, using Eclipse to build. I've cloned android-activity-graphs to use as an example.

I've set up my environment according to staxgr from https://github.com/square/dagger/issues/126
These are my libs: dagger-1.1.0.jar, dagger-compiler-1.1.0.jar, and javax.inject.jar

And lastly, I've changed the source folders in Eclipse to point to src/main/java (instead of just src/) so that Eclipse detects the related files through the package keyword.

The project builds, but fails immediately when it's run with this exception:

Caused by: java.lang.IllegalStateException: 
    Module adapter for class 
    com.example.dagger.activitygraphs.AndroidModule could not be loaded. 
    Please ensure that code generation was run for this module.

at dagger.internal.FailoverLoader.getModuleAdapter(FailoverLoader.java:41)
at dagger.internal.Modules.getAllModuleAdapters(Modules.java:43)
at dagger.ObjectGraph$DaggerObjectGraph.makeGraph(ObjectGraph.java:167)
at dagger.ObjectGraph$DaggerObjectGraph.access$000(ObjectGraph.java:134)
at dagger.ObjectGraph.create(ObjectGraph.java:126)
at com.example.dagger.activitygraphs.DemoApplication.onCreate(DemoApplication.java:29)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1000)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4391)

How do I get Dagger examples to work through eclipse?


Source: (StackOverflow)

Singletons in Dagger 1.x

When using Dagger, I found that I'm getting multiple instances of a singleton when I inject it wherever I need it. I've annotated the class and the provides method with @Singleton. Can anyone think of why this is happening?

Edit:

If it helps, I have followed the same structure for my app as the sample application in Dagger's GitHub (https://github.com/square/dagger/tree/master/examples/android-activity-graphs). I'm trying to get the Singleton in the base activity and a couple of third party classes provided using @Provides at the custom Application class. Is it because I'm plus-ing modules at each activity to the original object graph?

(PS : I'm new to Dagger and DI in general, so I'll be grateful if you could provide an explanation so that I may learn. Thanks.)


Source: (StackOverflow)