:wave: Hi, I'm trying to understand what is exactl...
# community-support
s
šŸ‘‹ Hi, I'm trying to understand what is exactly happening in the following situation, and why it triggers an error. I'll take the nowinandroid project as a base. It has a
build-logic
directory which contains convention plugins that is add to the main build with
Copy code
pluginManagement {
    includeBuild("build-logic")
}
Everything works great, until I add a settings plugin (
Plugin<Settings>
) that I try to apply on the main build. The plugin is correctly applied since we can see the generated log, but the build fails right after, with a weird message about corrupted cache:
Copy code
* What went wrong:
An exception occurred applying plugin request [id: 'nowinandroid.android.application']
> Failed to apply plugin 'nowinandroid.android.lint'.
   > Type com.android.build.api.dsl.ApplicationExtension not present

....
....
Caused by: java.lang.TypeNotPresentException: Type com.android.build.api.dsl.ApplicationExtension not present
	at org.gradle.api.reflect.TypeOf.captureTypeArgument(TypeOf.java:299)
	at org.gradle.api.reflect.TypeOf.<init>(TypeOf.java:96)
	at AndroidLintConventionPlugin$apply$lambda$0$$inlined$configure$1.<init>(TypeOfExtensions.kt:28)
	at AndroidLintConventionPlugin.apply(AndroidLintConventionPlugin.kt:52)
	at AndroidLintConventionPlugin.apply(AndroidLintConventionPlugin.kt:25)
	at org.gradle.api.internal.plugins.ImperativeOnlyPluginTarget.applyImperative(ImperativeOnlyPluginTarget.java:55)
	at org.gradle.api.internal.plugins.RuleBasedPluginTarget.applyImperative(RuleBasedPluginTarget.java:51)
	at org.gradle.api.internal.plugins.DefaultPluginManager.addPlugin(DefaultPluginManager.java:190)
	at org.gradle.api.internal.plugins.DefaultPluginManager.access$100(DefaultPluginManager.java:54)
....
....
Caused by: java.lang.ClassNotFoundException: com.android.build.api.dsl.ApplicationExtension
	at org.gradle.internal.classloader.VisitableURLClassLoader$InstrumentingVisitableURLClassLoader.findClass(VisitableURLClassLoader.java:187)
(I can share the full stacktrace if needed) Here is the corresponding code: https://github.com/android/nowinandroid/pull/1908/files
šŸ‘€ 1
It seems like creating an entirely new
includeBuild("build-logic-settings")
(nested projects will not work) with only this
Plugin<Settings>
no longer breaks the build, but it makes duplicating a lot of files.
Am I missing something obvious?
This looks a lot like this issue šŸ˜„ : https://github.com/gradle/gradle/issues/31034
v
It is rather simple actually and has nothing to do with cache, but class loaders. Because you now apply a plugin from that artifact to the settings script, the artifact is added to the settings classpath classloader. This classloader is in the ancestry of the project build script classloaders. You only add the AGP to the build script classloader, so the convention plugins do not find the classes anymore. Either add AGP to the settings classpath, or split the settings plugin off into a separate project. A separate sub project in the build logic build would be enough as long as you don't depend on the artifact with the project plugins.
s
Either add AGP to the settings classpath,
Not only AGP but also all the other plugins referenced in the build-logic project then?
or split the settings plugin off into a separate project. A separate sub project in the build logic build would be enough as long as you don't depend on the artifact with the project plugins
I'm not sure what you mean here. When I tried this solution, with 2 distinct projects nested in the build-logic included build, Gradle would complain that it can't find the settings plugin id.
v
Not only AGP but also all the other plugins referenced in the build-logic project then?
Possible, it depends. If you for example have
implementation
dependencies they are pulled in automatically. But AGP you only have as
compileOnly
dependency to react to the plugin being applied but not pull in the plugin to the classpath if the project does not actually apply it. But by having the AGP in a child class loader now, your convention plugin can no longer see it if only added to the build script classloader.
I'm not sure what you mean here. When I tried this solution, with 2 distinct projects nested in the build-logic included build, Gradle would complain that it can't find the settings plugin id.
Then you probably did something wrong and need to show what you did exactly. šŸ™‚ I just tried again to be sure and it works just fine.
s
Oh, you are right, it just worked šŸ¤” https://github.com/SimonMarquis/nowinandroid/pull/54 I might have to re-try on the work project. And also re-do the gradle-profiler with this alternative. But at this point, I had these metrics for these options • 1 included build containing one project with both
Plugin<Project>
Plugin<Settings>
• 1 included build containing one project with
Plugin<Project>
only, and manually copying the
Plugin<Settings>
inside the main
settings.gradle.kts
• 2 included builds containing each
Plugin<Project>
/
Plugin<Settings>
And the last version was always ~15s slower than the others, for a baseline of ~70s clean sync
The alternative with 1 included build containing 2 projects for each kind of plugin does not suffer from the 15s penalty, so that's great. Next step I guess would be to move away from included build altogether and publish the plugins internally and depend on the artifact instead.
šŸ‘Œ 1
Hi again, it seems like this refactor broke the VersionCatalog DSL in a very weird way. I'm not sure why, but I've always had this extension on the build-logic project (at the root package):
Copy code
internal val Project.libs get() = ...
and after the refactor, it seems like the IDE uses this instead of the generated VersionCatalog accessors for the syntax highlighting, even though everything compiles just fine, and the go-to-declaration works fine as well. The autocompletion on the other hand references the values declared by my custom extension.
At first I thought it was because of the root package that was treated in a special way like Gradle DSLs is to avoid specifying long package names, but no. All public/internal/private entities are "visible" to the projects build script (but does not compile in case of internal/private as expected). Although these are all defined in the project that is used for the projects build script, not for the settings of the build. So I'm a bit confused why they were not visible before, but are visible now. Is this just the IDE being too smart, or just broken, or am I missing something? šŸ™ƒ
v
Having stuff in the "default" package is practically always a bad idea in any JVM related project. But regarding the concrete question, at least for me it is hard to follow what you did, you might need to share an MCVE to make clear what you are talking about. šŸ™‚
s
> Having stuff in the "default" package is practically always a bad idea in any JVM related project. I 100% agree šŸ™ˆ this was implemented a while ago, when we tried things until it worked. > you might need to share an MCVE to make clear what you are talking about. I'll try to reproduce this on a small scale project šŸ‘
šŸ‘Œ 1
I might try to reproduce this on the nowinandroid project. Do you prefer a clean/empty project or are you familiar enough with nowinandroid ?
v
I personally do not care, but as there is "android" in the name, I myself would most probably not touch it if I can avoid it. šŸ™‚
šŸ˜† 1
šŸ†— 1
I'm just a user like you
Well, except for me not doing any Android šŸ˜„
And Android is anyway always "special", so just because something does not work in an Android build does not mean too much :-D
s
Hopefully the behavior will be the same on non-AndroidStudio IDE šŸ¤ž
v
Well, AS is mainly a customized IJ, so chances are good šŸ™‚
s
Here is a quick reproducer. Although it does not look 100% like what I had with Android Studio, it still shows things that are not normal for me. Take a look at the
HERE!
comments
v
Yeah, while it is not really a good idea to have it in the default package anyway, I'd say it is either an IJ / AS or probably more a KTIJ problem that those
internal
classes are even considered, even if there were no version catalog. If you remove the version catalog, the compiler complains for both lines that
libs
is internal.