Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
ayoubdevv opened this issue Aug 12, 2020 · 19 comments · Fixed by #2056
Closed

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

ayoubdevv opened this issue Aug 12, 2020 · 19 comments · Fixed by #2056

Comments

@ayoubdevv
Copy link

ayoubdevv commented Aug 12, 2020

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
Copy link

bcorso commented Aug 12, 2020

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
Copy link
Author

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
Copy link

bcorso commented Aug 12, 2020

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
Copy link
Author

ayoubdevv commented Aug 12, 2020

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
Copy link

bcorso commented Aug 13, 2020

Thinking about this more, I think we need to ban @AndroidEntryPoint for base classes with type parameters -- the workaround in #2042 (comment) 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
Copy link
Author

ayoubdevv commented Aug 13, 2020

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

@AndroidEntryPoint(BaseFragment::class)
class ExampleFragment : BaseFragment<FragmentExampleBinding>()

@bcorso
Copy link

bcorso commented Aug 13, 2020

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
Copy link
Author

ayoubdevv commented Aug 13, 2020

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

netdpb pushed a commit that referenced this issue Aug 19, 2020
…asses with type parameters.

This CL fixes a bug with OriginatingElementProcessor to change this:
  @OrginatingElement(topLevelElement=Foo<T>.class)
To this:
  @OrginatingElement(topLevelElement=Foo.class)

In addition, this CL bans @androidentrypoint usage on classes with type parameters. We're banning classes with type parameters because we can't generate an injector entry point for them (e.g. inject(FooActivity<T> fooActivity)) since the component itself doesn't have type parameters. Instead, our advice will be to use `@AndroidEntryPoint` on the non-parameterized subclasses instead.

RELNOTES=Fix #2042: Fix bug in OriginatingElementProcessor and bans @androidentrypoint classes with type parameters.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=327049118
netdpb pushed a commit that referenced this issue Aug 19, 2020
…asses with type parameters.

This CL fixes a bug with OriginatingElementProcessor to change this:
  @OrginatingElement(topLevelElement=Foo<T>.class)
To this:
  @OrginatingElement(topLevelElement=Foo.class)

In addition, this CL bans @androidentrypoint usage on classes with type parameters. We're banning classes with type parameters because we can't generate an injector entry point for them (e.g. inject(FooActivity<T> fooActivity)) since the component itself doesn't have type parameters. Instead, our advice will be to use `@AndroidEntryPoint` on the non-parameterized subclasses instead.

RELNOTES=Fix #2042: Fix bug in OriginatingElementProcessor and bans @androidentrypoint classes with type parameters.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=327049118
@mbahgojol
Copy link

@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
Copy link

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

@89hnim
Copy link

89hnim commented Sep 20, 2021

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
Copy link

bcorso commented Sep 20, 2021

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.

@89hnim
Copy link

89hnim commented Sep 20, 2021

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
Copy link

89hnim commented Sep 29, 2021

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

@bcorso
Copy link

bcorso commented Sep 29, 2021

@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
Copy link
Member

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
Copy link

89hnim commented Sep 29, 2021

@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
Copy link

@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
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants