google / dagger

A fast dependency injector for Android and Java.
https://dagger.dev
Apache License 2.0
17.42k stars 2.01k forks source link

error: <identifier> expected topLevelClass = BaseFragment<T, D>.class #2042

Closed ayoubdevv closed 4 years ago

ayoubdevv commented 4 years ago

Hi Everybody, So I mentioned this yesterday on stackoverflow here i Have issues when try to use inject ViewModel to BaseFragment with by viewModels() extension so i used Factory to inject it when i do that my BaseFragment Have tow generic type and it show me that error

error: expected topLevelClass = BaseFragment<T, D>.class ^error: [Hilt]

and the Generated Class is BaseFragment_GeneratedInjector :

@OriginatingElement(
    topLevelClass = BaseFragment<T, D>.class
)

@GeneratedEntryPoint
@InstallIn(FragmentComponent.class)
@Generated("dagger.hilt.android.processor.internal.androidentrypoint.InjectorEntryPointGenerator")
public interface BaseFragment_GeneratedInjector {
  void injectBaseFragment(BaseFragment baseFragment);
}

so i try this workgound in this issues

and it show same error and new Error says :

``` [Hilt] Processing did not complete. See error above for details.error: [Hilt] @AndroidEntryPoint class expected to extend Hilt_ContactUsFragment. Found: BaseFragment**



and my baseFragment is so simple : 

`@AndroidEntryPoint
abstract class BaseFragment<T : ViewModel,D : ViewDataBinding>() : Fragment() {

lateinit var viewModel: T by viewModels()

 }`

thanks in Advanced 
bcorso commented 4 years ago

Hey @ayoubdevv,

Thanks for reporting this issue!

This is definitely a bug on our end. We shouldn't be including the type parameters in @OriginatingElement(topLevelClass = BaseFragment<T, D>.class). I'll send out a fix.

In the mean time, you should be able to work around this issue by putting the @AndroidEntryPoint annotation on the subclass instead. So something like this should work around the issue since the subclass doesn't have type parameters itself.

// Put the annotation here instead of on the base class.
@AndroidEntryPoint
class MyFragment: BaseFragment<MyViewModel, MyViewDataBinding>() {
  ...
}
ayoubdevv commented 4 years ago

thanks @bcorso for reply i'll try it but what about injecting ViewModel when using by viewModels() extension it says : Cannot use 'T' as reified type parameter. Use a class instead. Type 'Lazy' has no method 'setValue(BaseFragment<T, D>, KProperty<*>, T)' and thus it cannot serve as a delegate for var (read-write property).** do i need to inject each ViewModel in subclass also ?

thanks in Advanced @bcorso

bcorso commented 4 years ago

it says : Cannot use 'T' as reified type parameter. Use a class instead.

I think this is just a restriction of Kotlin? Is this a pattern you were using before Hilt?

Edit: I know very little Kotlin, so happy to be proven wrong on this.

ayoubdevv commented 4 years ago

i just used like documentation here but didn't work so i used just ViewModelProvider i think the problem is in extension fuction itself image

bcorso commented 4 years ago

Thinking about this more, I think we need to ban @AndroidEntryPoint for base classes with type parameters -- the workaround in https://github.com/google/dagger/issues/2042#issuecomment-673078030 being the preferred solution.

I'll fix the original bug, and then add a better error message to make it clear this isn't allowed.

Details: The main issue is that @AndroidEntryPoint needs to generate an injector for the annotated class, e.g. void inject(BaseActivity<T> activity), but Dagger can't inject the class with out knowing the explicit type which isn't available until a subclass extends it.

ayoubdevv commented 4 years ago

@bcorso what about this workaround when we can use it ?

@AndroidEntryPoint(BaseFragment::class)
class ExampleFragment : BaseFragment<FragmentExampleBinding>()
bcorso commented 4 years ago

That should work out of the box already, but the usage above is not quite right.

If you're using the Hilt Gradle plugin you would just do this:

@AndroidEntryPoint
class ExampleFragment extends BaseFragment<FragmentExampleBinding>()
ayoubdevv commented 4 years ago

Yes it working when removing @AndroidEntryPoint from BaseFragment and put in subclass but base classes with type parameters we need it will be fixed or ban forever , because i used to use Dagger 2 and was work perfectly realyl thanks @bcorso for you're help it really Appreciated

mbahgojol commented 3 years ago

@ayoubdevv @bcorso Maybe you can do this:

@AndroidEntryPoint abstract class HiltFragment : Fragment() { }

and

abstract class HiltBaseFragment<T : ViewDataBinding, V : BaseViewModel> : HiltFragment() {

thats work for me

CodeK1988 commented 3 years ago

@ghozimahdi not work for me @AndroidEntryPoint abstract class HiltFragment : DialogFragment() abstract class BaseDialogFragment : HiltFragment() ,but still thanks.

89hnim commented 3 years ago

Hey @ayoubdevv,

Thanks for reporting this issue!

This is definitely a bug on our end. We shouldn't be including the type parameters in @OriginatingElement(topLevelClass = BaseFragment<T, D>.class). I'll send out a fix.

In the mean time, you should be able to work around this issue by putting the @AndroidEntryPoint annotation on the subclass instead. So something like this should work around the issue since the subclass doesn't have type parameters itself.

// Put the annotation here instead of on the base class.
@AndroidEntryPoint
class MyFragment: BaseFragment<MyViewModel, MyViewDataBinding>() {
  ...
}

@bcorso I can't use this work around if using multi-modules. I put BaseFragment in :base module. And other features module will implement this :base. And it will throw "failed to analyze: java.lang.reflect.InvocationTargetException" at compile time. Any updates on this?

bcorso commented 3 years ago

Any updates on this?

The update is in https://github.com/google/dagger/issues/2042#issuecomment-673252618

I can't use this work around if using multi-modules. I put BaseFragment in :base module. And other features module will implement this :base. And it will throw "failed to analyze: java.lang.reflect.InvocationTargetException" at compile time.

By "multi-modules" do you mean you are using dynamic feature modules? If so, you're correct that you can't use Hilt in such a way. The guidance is explained in https://developer.android.com/training/dependency-injection/hilt-multi-module#dfm.

If you just mean normal Gradle modules, it shouldn't matter if BaseFragment is in a separate module or not. If this is the case you can provide more details or if you can give a minimal reproducible example I can take a look to see why it might be failing.

89hnim commented 3 years ago

Any updates on this?

The update is in #2042 (comment)

I can't use this work around if using multi-modules. I put BaseFragment in :base module. And other features module will implement this :base. And it will throw "failed to analyze: java.lang.reflect.InvocationTargetException" at compile time.

By "multi-modules" do you mean you are using dynamic feature modules? If so, you're correct that you can't use Hilt in such a way. The guidance is explained in https://developer.android.com/training/dependency-injection/hilt-multi-module#dfm.

If you just mean normal Gradle modules, it shouldn't matter if BaseFragment is in a separate module or not. If this is the case you can provide more details or if you can give a minimal reproducible example I can take a look to see why it might be failing.

I just used normal android library modules. I created a sample that reproduce error: https://github.com/8991hnim/Hilt-Multi-Modules-Sample The project has 3 modules: :app :feature (contains WillErrorFragment - which I'm trying to @AndroidEntryPoint on this fragment) :base (contains BaseFragment and BaseFragment2 - I tried both ways but none worked.)

Module's relation: :app implements :feature :feature implements :base

When run will get compile errors. Please take a look at the repository. Thank you.

89hnim commented 2 years ago

@bcorso it's been 1 week. Please give me some updates. I'm stuck :(

bcorso commented 2 years ago

@8991hnim it's likely that this is due to missing transitive dependencies in the classpath during compilation. Hilt has the aggregating task flag to fix these issues automatically. Can you try enabling the flag by adding the following in your application's build.gradle file:

hilt {
    enableAggregatingTask = true
}
danysantiago commented 2 years ago

Something else must be going on, looking at @8991hnim's repro app, the processor is crashing with the following trace:

Caused by: java.lang.IllegalArgumentException
    at com.google.common.base.Preconditions.checkArgument(Preconditions.java:128)
    at dagger.internal.codegen.validation.InjectBindingRegistryImpl.getOrFindMembersInjectionBinding(InjectBindingRegistryImpl.java:339)
    at dagger.internal.codegen.validation.InjectBindingRegistryImpl.tryRegisterMembersInjectedType(InjectBindingRegistryImpl.java:297)
    at dagger.internal.codegen.validation.InjectBindingRegistryImpl.getOrFindMembersInjectionBinding(InjectBindingRegistryImpl.java:344)
    at dagger.internal.codegen.binding.BindingGraphFactory$Resolver.lookUpMembersInjectionBinding(BindingGraphFactory.java:474)
    at dagger.internal.codegen.binding.BindingGraphFactory$Resolver.resolveMembersInjection(BindingGraphFactory.java:774)
    at dagger.internal.codegen.binding.BindingGraphFactory$Resolver.access$1300(BindingGraphFactory.java:309)
    at dagger.internal.codegen.binding.BindingGraphFactory.lambda$createLegacyBindingGraph$4(BindingGraphFactory.java:216)
    at dagger.internal.codegen.binding.BindingGraphFactory.createLegacyBindingGraph(BindingGraphFactory.java:213)
    at dagger.internal.codegen.binding.BindingGraphFactory.createLegacyBindingGraph(BindingGraphFactory.java:242)
    at dagger.internal.codegen.binding.BindingGraphFactory.createLegacyBindingGraph(BindingGraphFactory.java:242)
    at dagger.internal.codegen.binding.BindingGraphFactory.createLegacyBindingGraph(BindingGraphFactory.java:242)
    at dagger.internal.codegen.binding.BindingGraphFactory.create(BindingGraphFactory.java:119)
    at dagger.internal.codegen.ComponentProcessingStep.processRootComponent(ComponentProcessingStep.java:117)
    at dagger.internal.codegen.ComponentProcessingStep.process(ComponentProcessingStep.java:95)
    at dagger.internal.codegen.ComponentProcessingStep.process(ComponentProcessingStep.java:55)
    at dagger.internal.codegen.validation.XTypeCheckingProcessingStep.lambda$process$0(XTypeCheckingProcessingStep.java:55)
    at com.google.common.collect.RegularImmutableMap.forEach(RegularImmutableMap.java:185)
    at dagger.internal.codegen.validation.XTypeCheckingProcessingStep.process(XTypeCheckingProcessingStep.java:52)
    at dagger.internal.codegen.validation.XTypeCheckingProcessingStep.process(XTypeCheckingProcessingStep.java:39)
    at dagger.shaded.androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor$DelegatingStep.process(JavacBasicAnnotationProcessor.kt:62)
    at dagger.shaded.auto.common.BasicAnnotationProcessor.process(BasicAnnotationProcessor.java:228)
    at dagger.shaded.auto.common.BasicAnnotationProcessor.process(BasicAnnotationProcessor.java:208)
    at org.jetbrains.kotlin.kapt3.base.incremental.IncrementalProcessor.process(incrementalProcessors.kt:90)
    at org.jetbrains.kotlin.kapt3.base.ProcessorWrapper.process(annotationProcessing.kt:175)
    at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:980)
    ... 41 more
89hnim commented 2 years ago

@8991hnim it's likely that this is due to missing transitive dependencies in the classpath during compilation. Hilt has the aggregating task flag to fix these issues automatically. Can you try enabling the flag by adding the following in your application's build.gradle file:

hilt {
    enableAggregatingTask = true
}

Thanks, it works 💯

Peacemaker-Otoo commented 2 years ago

@8991hnim it's likely that this is due to missing transitive dependencies in the classpath during compilation. Hilt has the aggregating task flag to fix these issues automatically. Can you try enabling the flag by adding the following in your application's build.gradle file:

hilt {
    enableAggregatingTask = true
}

Thanks, it works 💯

still its not working........

Peacemaker-Otoo commented 2 years ago

Please, solve the issue of injecting abstract class parameters : abstract class BaseFragment<VM : ViewModel, viewBinding : ViewDataBinding, repository : BaseRepository> : Fragment(){}

Everything was working fine when I was using dagger2 but having issues with using Hilt.