Search code examples
androidmavenkotlingradledependencies

Cannot access 'java.lang.Object' which is a supertype of... Check your module classpath for missing or conflicting dependencies


I thought it would be fun and informative to learn more about static code analysis by implementing my own custom linter. I've been trying to declare the below dependencies:

dependencies {
    compileOnly "com.android.tools.lint:lint-api:30.1.2"
    compileOnly "com.android.tools.lint:lint-checks:30.1.2"
}

But Gradle is giving an error that these dependencies cannot be resolved. After digging some, I found that MavenCentral and Google have seemingly different versioning for these libraries, with Google being the version described in the code snippet above and MavenCentral having version 25.3.0 as the latest version. If I swap out the version numbers for those described on MavenCentral, the dependencies can be resolved by Gradle but my custom linter code is completely highlighted in red and gives an error

Cannot access 'java.lang.Object' which is a supertype of my_custom_linter. Check your module classpath for missing or conflicting dependencies

There are many SO posts regarding this error, and the few that have been resolved were resolved by using the most recent version of an available dependency, which in my case circles back to the first error described in this post.


Project level build.gradle:

buildscript {
    repositories {
        google()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.4"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
    }
}

plugins {
    id 'com.android.application' version '7.1.2' apply false
    id 'com.android.library' version '7.1.2' apply false
    id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
    id 'org.jetbrains.kotlin.jvm' version '1.6.10' apply false
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Lint module build.gradle:

plugins {
    id 'java-library'
    id 'org.jetbrains.kotlin.jvm'
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_7
    targetCompatibility = JavaVersion.VERSION_1_7
}

dependencies {
    compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10"
    compileOnly "com.android.tools.lint:lint-api:25.3.0"
    compileOnly "com.android.tools.lint:lint-checks:25.3.0"
}

jar {
    manifest {
        attributes("Lint-Registry": "com.example.lint_checks.LintRegistry")
    }
}

App module build.gradle:

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk 32

    defaultConfig {
        ...
    }

    buildTypes {
        ...
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
    kotlinOptions {
        jvmTarget = '1.7'
    }
    buildFeatures {
        viewBinding true
    }
}

dependencies {
    lintChecks project(path: ":lint-checks")
    ...
}

settings.gradle

pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name = "Custom Linter"
include ':app'
include ':lint-checks'

InputTypeDetector.kt (custom lint class):

/* Entire class highlighted by IDE with error message: 
Cannot access 'java.lang.Object' which is a supertype of 'com.example.lint_checks.InputTypeDetector'. Check your module classpath for missing or conflicting dependencies */ 

class InputTypeDetector: LayoutDetector() {
    companion object {
        @JvmStatic
        internal val ISSUE_MISSING_INPUT_TYPE = Issue.create(
            id = "MissingInputType",
            briefDescription = "Specify inputType attribute to get proper keyboard shown by system.",
            explanation = "You should specify an inputType for each EditText so that you can get the proper keyboard to be shown by system.",
            category = Category.USABILITY,
            priority = 8,
            severity = Severity.ERROR,
            implementation = Implementation(
                InputTypeDetector::class.java,
                Scope.ALL_RESOURCES_SCOPE
            )
        ).addMoreInfo("https://developer.android.com/training/keyboard-input/style")
    }

    override fun getApplicableElements(): Collection<String>? {
        return listOf(
            SdkConstants.EDIT_TEXT,
            "androidx.appcompat.widget.AppCompatEditText",
            "android.support.v7.widget.AppCompatEditText"
        )
    }

    override fun visitElement(context: XmlContext, element: CoroutineContext.Element) {
        if (!element.hasAttribute(SdkConstants.ATTR_INPUT_TYPE)) { // Check if the element has the `android:inputType` attribute
            context.report(
                issue = ISSUE_MISSING_INPUT_TYPE, // The issue that we defined above
                location = context.getLocation(element),
                message = ISSUE_MISSING_INPUT_TYPE.getExplanation(TextFormat.TEXT)
            )
        }
    }
}

UPDATE: I've verified the lint-api and lint-checks jar files are in the external libraries directory of my project. Gradle has resolved and downloaded these dependencies when requesting version 25.3.0. Why am I getting the error about accessing java.lang.Object and checking my classpath?

I have been following this tutorial


Solution

  • It’s not clear to me, which dependency resolution repositories you have configured as you don’t provide your settings.gradle file. So I’ll assume that you have configured the following there:

    dependencyResolutionManagement {
        repositories {
            google()
            mavenCentral()
        }
    }
    

    Now, while version 25.3.0 of lint-api and lint-checks exists, it has dependency declarations that make it unsuitable for being used as a compile-time dependency. So I’ve upgraded the version to 26.6.4:

        compileOnly "com.android.tools.lint:lint-api:26.6.4"
        compileOnly "com.android.tools.lint:lint-checks:26.6.4"
    

    That brings in all required dependencies. But there was still one issue with your InputTypeDetector implementation: the visitElement method signature is wrong in that it uses CoroutineContext.Element as the type of element. It should be org.w3c.dom.Element, though:

        override fun visitElement(context: XmlContext, element: org.w3c.dom.Element) {
            // …
        }
    

    With these changes, I could successfully build your lint-checks project (tested with Gradle 7.4.2).


    Responding to your comment: I’m afraid, I can’t reproduce the error with your code. Note, however, that I made a few modifications that might make a difference:

    • I had to add a missing import in LintRegistry.kt:
      import com.android.tools.lint.detector.api.CURRENT_API
    • I have removed .idea/ before importing your project into Android Studio.
    • For security reasons, I have removed the gradle/, gradlew and gradlew.bat files. Then I added a fresh Gradle Wrapper of the same version (7.4.2).

    Could you maybe try to do the same and import the project afresh to see if that maybe fixes it? Another thing worth trying to rule out issues with Android Studio: see if building from the command line works, e.g., with ./gradlew lint-checks:build.