If I understand correctly I am not crossing compilation units. I’m using Gradle with mostly default settings provided when creating a new Android Studio project.
I’ve uploaded a barebones example here:
https://github.com/dpkirchner/dagger-issue-551
Assuming you have AS and the Android SDK installed, when you clone that and run ./gradlew :app:testDebug
and you’ll see:
:app:compileDebugUnitTestKotlin
:app:compileDebugUnitTestJavaWithJavac
Destination for generated sources was modified by kapt. Previous value = /Users/dpk/Documents/git/Demo2/app/build/generated/source/apt/test/debug
error: Dagger does not support injection into private fields
error: Dagger does not support injection into private fields
error: Dagger does not support injection into private fields
error: com.example.demo.FooTest cannot be provided without an @Inject constructor or from an @Provides-annotated method.
com.example.demo.FooTest is injected at
com.example.demo.FooTest.Component.inject(arg0)
If you remove the annotations from the inject statement the dagger component will be generated successfully and the test will run (it will fail because it throws an exception, but eh).
In this extremely contrived example I’m not actually testing any code — the issue appears to be isolated to the test module (hence my guess that I’m not crossing compilation units).
Edited to add: I should probably mention that I’m using that @field:[Named(...)]
notation deliberately. Unfortunately, I don’t remember exactly why I found it necessary; I didn’t comment it in my original code. Regardless, the same issue exists with it or without it.
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.
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
Tags:
Dependency Injection
Android
Kotlin
Dagger
Dagger 2
Related
When this error occurs, Dagger provides the offending element to the compiler who is responsible for rendering it in a way that points to the source. You see this in normal javac errors, but it seems like a bug in the compiler that it doesn’t provide context in the source.
I have seen this come up quite a bit for Dagger’s errors as well as other processors.
Bummer. Not sure who/what to report this to. For now, my «workaround» is to modify a local checkout of dagger to write out useful information to a file.
Does this error cross compilation units? Javac often doesn’t have the right information when that happens
I suspect that this is not an issue with Dagger or javac, but the build tool that is wrapping them. I know at one point Maven had some issues with how it peeled output out of javac and presented it. Which build system are you using? Can you give an example of how exactly it is presented?
If I understand correctly I am not crossing compilation units. I’m using Gradle with mostly default settings provided when creating a new Android Studio project.
I’ve uploaded a barebones example here:
https://github.com/dpkirchner/dagger-issue-551
Assuming you have AS and the Android SDK installed, when you clone that and run ./gradlew :app:testDebug
and you’ll see:
:app:compileDebugUnitTestKotlin
:app:compileDebugUnitTestJavaWithJavac
Destination for generated sources was modified by kapt. Previous value = /Users/dpk/Documents/git/Demo2/app/build/generated/source/apt/test/debug
error: Dagger does not support injection into private fields
error: Dagger does not support injection into private fields
error: Dagger does not support injection into private fields
error: com.example.demo.FooTest cannot be provided without an @Inject constructor or from an @Provides-annotated method.
com.example.demo.FooTest is injected at
com.example.demo.FooTest.Component.inject(arg0)
If you remove the annotations from the inject statement the dagger component will be generated successfully and the test will run (it will fail because it throws an exception, but eh).
In this extremely contrived example I’m not actually testing any code — the issue appears to be isolated to the test module (hence my guess that I’m not crossing compilation units).
Edited to add: I should probably mention that I’m using that @field:[Named(...)]
notation deliberately. Unfortunately, I don’t remember exactly why I found it necessary; I didn’t comment it in my original code. Regardless, the same issue exists with it or without it.
I’m not familiar with actually using Kotlin, but I know kapt
still has some rough edges. I wonder if this is bad coordination with javac somehow?
A java version of the same* test code does include the error’s context using the same configuration. Would seem to point to Kotlin or kapt.
* I had to make someBoolean
explicitly private to trigger the error. I guess the Dagger/Kotlin/kapt is not reading the flags right. In any case, that’s a separate issue.
Yeah, this rings a bell. I think people have had this sort of trouble with kapt in the past. It’s probably worth filing a bug with them about it. Closing this for now as I don’t think there’s much we can do aside from calling the right processing apis with the right values.
Field injection can be done in Android kotlin by below way.
var mSharedPreferences: SharedPreferences? = null
@Inject set
Also need to add below lines of code in app level build.gradle
apply plugin: ‘kotlin-kapt’
kapt {
generateStubs = true
}
implementation ‘com.google.dagger:dagger:2.10’
kapt ‘com.google.dagger:dagger-compiler:2.10’
I use in kotlin activity ViewPager and I want in Kotlin Fragment use the dagger injection. Я использую в kotlin Activity ViewPager и хочу, чтобы в Kotlin Fragment использовалась инъекция кинжала. I have got Error: Dagger does not support injection into private fields. У меня ошибка: Dagger не поддерживает инъекцию в приватные поля. In Java Fragment the dagger injection work. В Java Fragment работает инъекция кинжала. 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 сообщения Gradle построить
en
Ответы
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
. Пожалуйста, рассмотрите ответ Авилио, который также сработал для меня: замените internal
на lateinit
.
Old answer Старый ответ
Remove internal
modifier. Удалите модификатор internal
. 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. В Kotlin модификатор internal
не является заменой модификатора закрытого доступа Java.
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 . Подробное объяснение различий между модификаторами в Java и Kotlin см. в выпуске #101 подкаста Fragmented — «Изучение Kotlin — модификаторы видимости, внутренний модификатор, модули» , а также в официальной документации .
en
You have mistake here: У вас здесь ошибка:
@Inject
internal var mSharedPreferences: SharedPreferences? = null
This looks like you added @Inject
annotation to the KotlinFragment
class Похоже, вы добавили аннотацию $# @Inject
KotlinFragment
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 Вот ссылка на документацию: https://kotlinlang.org/docs/reference/annotations.html
en
I had the same error, even upon removing the internal keyword. У меня была такая же ошибка, даже после удаления внутреннего ключевого слова. So I replaced internal with lateinit and it worked. Поэтому я заменил internal на lateinit, и это сработало.
en
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. эта работа как шарм в моем случае.
en
@Inject
lateinit var mSharedPreferences: SharedPreferences
Кроме того, это сработало и для меня для переменной поздней инициализации
en
Remove the internal
modifier. Удалите модификатор internal
. And I also had to declare lateinit
and remove the Optional. И мне также пришлось объявить lateinit
и удалить необязательный.
en
Have you defined fun inject(fragment: KotlinFragment)
in your ApplicationComponent
? Вы определили fun inject(fragment: KotlinFragment)
в ApplicationComponent
? Because it looks like your error message is saying exactly that. Потому что похоже, что ваше сообщение об ошибке говорит именно об этом.
EDIT: maybe you haven’t provided SharedPreferences
in your Module like this: РЕДАКТИРОВАТЬ: возможно, вы не предоставили SharedPreferences
в своем модуле следующим образом:
@Module
public class AndroidModule {
private final TimrApplication application;
public AndroidModule(TimrApplication application) {
this.application = application;
}
@Provides
SharedPreferences provideSharedPreferences(){
return PreferenceManager.getDefaultSharedPreferences(application);
}
}
en
Posted By: Anonymous
I’m trying to learn Hilt and am getting the error «Dagger does not support injection into private fields». But the field in question isn’t private in the original Kotlin. It’s only private when it’s converted to Java. Why is this? How can I correct it?
Original Kotlin file:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.example.vennwithnav.databinding.FragmentLoginBinding
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class LoginFragment : Fragment() {
@Inject public var profileViewModel: ProfileViewModel? = null
private var binding: FragmentLoginBinding? = null
Java file after conversion (accessed via the error):
package com.example.vennwithnav.ui.profile;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.vennwithnav.databinding.FragmentLoginBinding;
import dagger.hilt.android.AndroidEntryPoint;
import javax.inject.Inject;
@kotlin.Metadata(mv = {1, 4, 1}, bv = {1, 0, 3}, k = 1, d1 = {"u0000:nu0002u0018u0002nu0002u0018u0002nu0002bu0002nu0002u0018u0002nu0000nu0002u0018u0002nu0002bu0005nu0002u0010u0002nu0000nu0002u0018u0002nu0000nu0002u0018u0002nu0000nu0002u0018u0002nu0000nu0002u0018u0002nu0002bu0002bu0007u0018u00002u00020u0001Bu0005u00a2u0006u0002u0010u0002Ju0006u0010u000bu001au00020fJ&u0010ru001au0004u0018u00010u000e2u0006u0010u000fu001au00020u00102bu0010u0011u001au0004u0018u00010u00122bu0010u0013u001au0004u0018u00010u0014Hu0016Jbu0010u0015u001au00020fHu0016Ru0010u0010u0003u001au0004u0018u00010u0004Xu0082u000eu00a2u0006u0002nu0000Ru001au0010u0005u001au00020u0006Xu0086u000eu00a2u0006u000enu0000u001au0004bu0007u0010b"u0004btu0010nu00a8u0006u0016"}, d2 = {"Lcom/example/vennwithnav/ui/profile/LoginFragment;", "Landroidx/fragment/app/Fragment;", "()V", "binding", "Lcom/example/vennwithnav/databinding/FragmentLoginBinding;", "profileViewModel", "Lcom/example/vennwithnav/ui/profile/ProfileViewModel;", "getProfileViewModel", "()Lcom/example/vennwithnav/ui/profile/ProfileViewModel;", "setProfileViewModel", "(Lcom/example/vennwithnav/ui/profile/ProfileViewModel;)V", "login", "", "onCreateView", "Landroid/view/View;", "inflater", "Landroid/view/LayoutInflater;", "container", "Landroid/view/ViewGroup;", "savedInstanceState", "Landroid/os/Bundle;", "onDestroyView", "app_debug"})
@dagger.hilt.android.AndroidEntryPoint()
public final class LoginFragment extends androidx.fragment.app.Fragment {
@org.jetbrains.annotations.NotNull()
private com.example.vennwithnav.ui.profile.ProfileViewModel profileViewModel; // this line is causing the error
private com.example.vennwithnav.databinding.FragmentLoginBinding binding;
@org.jetbrains.annotations.NotNull()
public final com.example.vennwithnav.ui.profile.ProfileViewModel getProfileViewModel() {
return null;
}
public final void setProfileViewModel(@org.jetbrains.annotations.NotNull()
com.example.vennwithnav.ui.profile.ProfileViewModel p0) {
}
Solution
One more google search found the answer. https://kotlinlang.org/docs/java-to-kotlin-interop.html#instance-fields
Adding @JvmField in front of var fixed the problem.
@Inject @JvmField var profileViewModel: ProfileViewModel? = null
per IR42, this works too, and is the used in the developer.android.com tutorials, so it’s probably better.
@Inject lateinit var profileViewModel: ProfileViewModel
Answered By: Anonymous
Related Articles
- Unable to run Robolectric and Espresso with a…
- Jetpack Compose and Hilt Conflict
- Hilt :- Not able to use the @AndroidEntryPoint in the…
- Unable to create call adapter for class java.lang.Object…
- Render problem in Android Studio arctic fox
- Examples of GoF Design Patterns in Java’s core libraries
- Error inflating class android.support.v7.widget.Toolbar?
- TLS 1.3 server socket with Java 11 and self-signed…
- Android || Inject dependencies in classes not supported by…
- Error: container has not been made global — how to solve?
Disclaimer: This content is shared under creative common license cc-by-sa 3.0. It is generated from StackExchange Website Network.