Issue
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
andgradlew.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
.
Answered By - Chriki
Answer Checked By - Marilyn (JavaFixing Volunteer)