google / dagger

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

[KSP][Android] Non existing type error on class generated from Android Navigation arguments #4061

Open cemore2048 opened 1 year ago

cemore2048 commented 1 year ago

The "non existing" type here is a class that's generated by the navigation library. It used to be picked up with Hilt using Kapt. I've tried looking for any extra setup that I might be missing, but I might have overlooked something.

e: [ksp] AssistedInjectProcessingStep was unable to process 'HallwayTabViewModel(com.clubhouse.android.ui.hallway.HallwayTabViewState,com.clubhouse.session.di.SessionComponentHandler,com.clubhouse.android.shared.auth.UserManager,com.clubhouse.android.error.ErrorMessageFactory)' because 'error.NonExistentClass' could not be resolved.

Dependency trace:
    => element (CLASS): com.clubhouse.android.ui.hallway.HallwayTabViewModel
    => element (METHOD): handleDeeplinkArguments(error.NonExistentClass)
    => element (PARAMETER): args
    => type (ERROR parameter type): error.NonExistentClass

If type 'error.NonExistentClass' is a generated type, check above for compilation errors that may have prevented the type from being generated. Otherwise, ensure that type 'error.NonExistentClass' is on your classpath.

The param is using an assisted inject here

data class HallwayTabViewState(
    internal val args: MainTabFragmentArgs,
    ...
) : MavericksState {

    constructor(arguments: Bundle) : this(
        args = MainTabFragmentArgs.fromBundle(arguments),
    )
}

class HallwayTabViewModel @AssistedInject constructor(
    @Assisted initialState: HallwayTabViewState
    ....
) {

    init {
        handleDeeplinkArguments(initialState.args) <-- the `MainTabFragmentArgs`
    }
}
danysantiago commented 1 year ago

The root cause of this is similar to the one regarding ViewBinding generated classes (https://github.com/google/dagger/issues/4051) or the AGP BuildConfig generated class (https://github.com/google/dagger/issues/4049), which is that the Navigation Safe Args plugins is generating classes that are not being wired as inputs for KSP hence Dagger is unable to resolve them.

ispam commented 11 months ago

In case anyone needs the variant on Kotlin DSL ->

 androidComponents {
        onVariants(selector().all()) { variant ->
            afterEvaluate {
                // This is a workaround for https://issuetracker.google.com/301245705 which depends on internal
                // implementations of the android gradle plugin and the ksp gradle plugin which might change in the future
                // in an unpredictable way.
                val dataBindingTask = this.project.tasks.named ("dataBindingGenBaseClasses" + variant.name.capitalize()).get() as com.android.build.gradle.internal.tasks.databinding.DataBindingGenBaseClassesTask

                if (dataBindingTask != null) {
                    project.tasks.getByName("ksp" + variant.name.capitalize() + "Kotlin") {
                        (this as org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool<*>).setSource(dataBindingTask.sourceOutFolder)
                    }
                }
            }
        }
    }
ansman commented 9 months ago

@danysantiago I'm confused why it's being shown as error.NonExistentClass though, I though that was a KAPT thing?

bcorso commented 9 months ago

Dagger uses XProcessing, which uses error.NonExistentClass for consistency if there's a type it can't resolve:

https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeJavaPoetExt.kt;l=39-42

Note: I think this is mostly needed because KSP is currently missing information in their error types so that we can't even get the simple name of the type used in the code (https://github.com/google/ksp/issues/1232). Once that bug is fixed, I imagine we would start reporting that rather than the generic error.NonExistentClass.

mohammadbahadori99 commented 3 months ago

I am facing the same error. Any update on this issue?

bcorso commented 3 months ago

@mohammadbahadori99, see https://github.com/google/dagger/issues/4061#issuecomment-1710884384 and https://github.com/google/dagger/issues/4061#issuecomment-1780299008 for the workaround for this issue.

mohammadbahadori99 commented 3 months ago

@bcorso I tried to use this in my app module builde.gradle file and still the same error is there

androidComponents {
    onVariants(selector().all(), { variant ->
        afterEvaluate {
            // This is a workaround for https://issuetracker.google.com/301245705 which depends on internal
            // implementations of the android gradle plugin and the ksp gradle plugin which might change in the future
            // in an unpredictable way.
            project.tasks.getByName("ksp" + variant.name.capitalize() + "Kotlin") {
                def dataBindingTask = (DataBindingGenBaseClassesTask) project.tasks.getByName("dataBindingGenBaseClasses" + variant.name.capitalize())

                ((AbstractKotlinCompileTool) it).setSource(
                        dataBindingTask.sourceOutFolder
                )
            }
        }
    })
}

But I tried this instead and it worked:

androidComponents {
    onVariants(selector().all()) { variant ->
        afterEvaluate {
            def variantName = variant.name.capitalize()
            def ksp = "ksp${variantName}Kotlin"
            def safeArgs = "generateSafeArgs${variantName}"

            def kspTask = project.tasks.findByName(ksp) as org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
            def safeArgsTask = project.tasks.findByName(safeArgs) as androidx.navigation.safeargs.gradle.ArgumentsGenerationTask

            if (kspTask && safeArgsTask) {
                kspTask.setSource(safeArgsTask.outputDir)
            }
        }
    }
}