Dagger: @Qualifier causes: [Dagger/MissingBinding] @JvmStatic solves ONLY constructor injection

Created on 4 Sep 2019  路  9Comments  路  Source: google/dagger

I'm having this issue:

ApplicationComponent.java:8: error: [Dagger/MissingBinding] @... java.text.SimpleDateFormat cannot be provided without an @Provides-annotated method.

Module

@Module
abstract class ApplicationModule {

    @Binds
    @AppContext
    abstract fun application(app: App): Context

    @Module
    companion object {
        ...

        @Provides
        @Singleton
        @CalendarPickerDateFormat
        fun provideCalendarPickerDateFormat(): SimpleDateFormat {
            return SimpleDateFormat("dd/MMM/yyyy", Locale.getDefault())
        }
    }
}

Qualifier

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class CalendarPickerDateFormat

Class

@ActivityScope
class MyClass
@Inject constructor(
   ...,
    @CalendarPickerDateFormat private val calendarDateFormat: SimpleDateFormat
) {...}

Even if I add @Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY) to the Qualifier and change the class constructor to @param:CalendarPickerDateFormat, I get the same error.

What's missing?

Possible solution

Adding @JvmStatic like:

@Provides
@Singleton
@JvmStatic
@CalendarPickerDateFormat
fun provideCalendarPickerDateFormat(): SimpleDateFormat {
      return SimpleDateFormat("dd/MMM/yyyy", Locale.getDefault())
}

Solves constructor injection but not field injection:
@Inject @CalendarPickerDateFormat lateinit var date : SimpleDateFormat

Why?

NOTE: I've tried also the @Module object class approach but I have the same outcome.

Most helpful comment

How about @field:CalendarPickerDateFormat? https://github.com/google/dagger/issues/900#issuecomment-337038961

All 9 comments

How about @field:CalendarPickerDateFormat? https://github.com/google/dagger/issues/900#issuecomment-337038961

How about @field:CalendarPickerDateFormat? #900 (comment)

It worked! But why do Qualifiers as field injection need @field but @param can be omitted from constructor?

From the official Kotlin docs:

If you don't specify a use-site target, the target is chosen according to the @Target annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following list is used:

  • param;
  • property;
  • field.

So basically, it's because param is the default target when it's not specified.

Thank you so much guys! So, as a good practice, do you always specify the target?

Since precedence sorts it out for ctor params, I wouldn't specify it there. Makes the code easier to read for others, too, as they don't really have to know about use site targets in order to understand it.

I don't use Dagger with Kotlin so can't really tell, but what if you annotate the qualifier with @Target(VALUE_PARAMETER, FUNCTION, FIELD)? (same as you tried, except FIELD instead of PROPERTY) Then the precedence rule above would apply the qualifier to the field and you wouldn't have to specify it explicitly.

See also https://github.com/google/dagger/issues/900#issuecomment-404382056

For me it doesn't work with @Named field injection

Hello @PaulWoitaschek,
Have you checked the lastest release?

What's new
    Kotlin support
        Qualifier annotations on fields can now be understood without
        The need for @field:MyQualifier (646e033)
        @Module object classes no longer need @JvmStatic on the
        provides methods. (0da2180)

Was this page helpful?
0 / 5 - 0 ratings