5

Lets say I have a module where I only want to export an instance of A. However this A requires instances of Band C to be passed in the constructor. So we would declare them as well in the module:

public class SampleModule {

    @Provides
    @Singleton
    A provideA(B b, C c){
        return new A(b, c);
    }

    @Provides
    @Singleton
    B provideB(){
        return new B();
    }

    @Provides
    @Singleton
    C provideC(){
        return new C(); 
    }
}

This works, but now B and C are also available elsewhere in the code. I want to keep them private and force client classes to only have access to A.

Is there a way to achieve this?

azizbekian
  • 60,783
  • 13
  • 169
  • 249
Mister Smith
  • 27,417
  • 21
  • 110
  • 193
  • 1
    http://stackoverflow.com/questions/39219257/can-a-dagger-2-dependency-be-non-injectable – Kevin Krumwiede Apr 07 '17 at 16:09
  • 1
    Possible duplicate of [Can a Dagger 2 dependency be non-injectable?](http://stackoverflow.com/questions/39219257/can-a-dagger-2-dependency-be-non-injectable) – David Rawson Apr 09 '17 at 06:15

2 Answers2

7

The easiest way to accomplish that goal is to bind the types that you don't want to be made available (in this case B and C) with a @Qualifier that is not accessible.

Then, while B and C might be be accessible from outside the module, in order to inject them you would need to supply a qualifier, which is not.

@Module
public final class SampleModule {
  @Qualifier
  @Retention(RUNTIME)
  private @interface SampleModuleOnly {}

  @Provides
  @Singleton
  static A provideA(@SampleModuleOnly B b, @SampleModuleOnly C c){
    return new A(b, c);
  }

  @Provides
  @SampleModuleOnly 
  @Singleton
  static B provideB(){
    return new B();
  }

  @Provides
  @SampleModuleOnly 
  @Singleton
  static C provideC(){
    return new C(); 
  }
}
gk5885
  • 3,742
  • 21
  • 16
  • Ok this works but messes with all provided dependencies marked with `@Named` annotation. It happens to also be a qualifier and you cant have two qualifiers in a `provideXXX` method. – Mister Smith Apr 20 '17 at 08:41
  • 1
    Yes, that is one of many reasons to prefer custom qualifiers to `@Named`. – gk5885 Apr 21 '17 at 04:24
1

A simple way to do this is

@Retention(BINARY)
@Qualifier
private annotation class InternalApi

@Module
object NetworkModule {
  @Provides 
  @InternalApi 
  fun provideClient(): OkHttpClient {
    //...
  }

  @Provides
  fun provideRetrofit(
    @InternalApi client: Lazy<OkHttpClient>
  ): Retrofit {
    //...
  }
}

culled from here.

Basically, we create private qualifiers- in this case, @InternalApi that is used to qualify the OkHttpClient dependency thus making it private to our module.

Shayne3000
  • 607
  • 8
  • 5