Kotlin Error: Dagger does not support injection into private fields
AndroidDependency InjectionKotlinDagger 2DaggerAndroid Problem Overview
I use in kotlin activity ViewPager and I want in Kotlin Fragment use the dagger injection. I have got Error: Dagger does not support injection into private fields. In Java Fragment the dagger injection work. Why can i not inject dagger in kotlin faragment ?
in my kotlin activity
mPagerAdapter = object : FragmentPagerAdapter(supportFragmentManager) {
private val mFragments = arrayOf(KotlinFragment(), JavaFragment())
private val mFragmentNames = arrayOf(getString(R.string.cashdocuments), getString(R.string.action_absmysql))
override fun getItem(position: Int): Fragment {
return mFragments[position]
}
override fun getCount(): Int {
return mFragments.size
}
override fun getPageTitle(position: Int): CharSequence {
return mFragmentNames[position]
}
}
my kotlin fragment
class KotlinFragment : Fragment() {
@Inject
internal var mSharedPreferences: SharedPreferences? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
(activity.application as SamfantozziApp).dgaeacomponent().inject(this)
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
val rootView = inflater!!.inflate(R.layout.activity_absserver, container, false)
return rootView
}
}
messages gradle build
Android Solutions
Solution 1 - Android
You have mistake here:
@Inject
internal var mSharedPreferences: SharedPreferences? = null
This looks like you added @Inject
annotation to the KotlinFragment
class
Please change it to this and it will work:
var mSharedPreferences: SharedPreferences? = null
@Inject set
Here is the link to the documentation: https://kotlinlang.org/docs/reference/annotations.html
Solution 2 - Android
Accidentally I came across to my own answer and have to confess, that in fact it isn't working (at least for my use-case). Please consider Avilio's answer which worked for me also: substitute internal
with lateinit
.
Old answer
Remove internal
modifier. Dagger needs at least package-private access in order to access annotated field. In Kotlin internal
modifier is not a substitution for Java's package-private access modifier.
For detailed explanation of differences between modifiers in Java and Kotlin refer to Fragmented podcast's episode #101 - "Learning Kotlin – visibility modifiers, internal modifier, modules", as well as the official docs.
Solution 3 - Android
As simple you can do this, change this line
@Inject
internal var mSharedPreferences: SharedPreferences? = null
To
@set:Inject
internal var mSharedPreferences: SharedPreferences? = null
this work like charm in my case.
Solution 4 - Android
I had the same error, even upon removing the internal keyword. So I replaced internal with lateinit and it worked.
Solution 5 - Android
@Inject
lateinit var mSharedPreferences: SharedPreferences
Also, this worked for me as well for late initialization variable
Solution 6 - Android
I followed the above advise of not making the field internal. But, that was not enough. Kapt still converting the var to private during compilation.
I had to add the @JvmField
annotation to make it behave better.
The answer I found was here: https://discuss.kotlinlang.org/t/kapt-converting-public-fields-to-private-during-compilation/11757
Solution 7 - Android
Remove the internal
modifier. And I also had to declare lateinit
and remove the Optional.
Solution 8 - Android
@Inject
internal var mSharedPreferences: SharedPreferences? = null
Just change this to
@Inject
lateinit var mSharedPreferences: SharedPreferences
P.S. You can't use lateinit with nullables.
Solution 9 - Android
Have you defined fun inject(fragment: KotlinFragment)
in your ApplicationComponent
? Because it looks like your error message is saying exactly that.
EDIT: maybe you haven't provided SharedPreferences
in your Module like this:
@Module
public class AndroidModule {
private final TimrApplication application;
public AndroidModule(TimrApplication application) {
this.application = application;
}
@Provides
SharedPreferences provideSharedPreferences(){
return PreferenceManager.getDefaultSharedPreferences(application);
}
}
Solution 10 - Android
In My case, I changed
@Inject
var locationDBWrapper: LocationDBWrapper? = null
to
@Inject
lateinit var locationDBWrapper: LocationDBWrapper
Issue got resolved
Solution 11 - Android
You can't make injected vars private, but you can make them protected, which is effectively the same in a final class (and in Kotlin classes are final by default unless you use the "open" modifier). Also, use lateinit modifier like it has been said already.
@Inject
protected lateinit var mSharedPreferences: SharedPreferences
If your class is not open, this might produce a warning in Android Studio saying "'protected' visibility is effectively 'private' in a final class" - you can just suppress that with:
@Suppress("ProtectedInFinal")
Solution 12 - Android
After updating to Android Studio 3.5, most of the answers don't work. The consolidated solution is :
1. If you want to use lateinit
:
@Inject lateinit var mSharedPreferences: SharedPreferences
2. If you don't want to use lateinit
:
var mSharedPreferences: SharedPreferences? = null
@Inject set(value) {
field = value
}
OR
@Inject
@JvmField
var mSharedPreferences: SharedPreferences
NOTE: These methods don't work anymore. You get the error not a valid name: <set-?>Provide
@set:Inject
var mSharedPreferences: SharedPreferences? = null
var mSharedPreferences: SharedPreferences? = null
@Inject set