Closed bryceatmoderne closed 2 weeks ago
For the OSS build plugins, the plugin classloader part wouldn't be necessary. However, when testing via the tooling API or loading the plugin via the initscript, it results in a different location as to where to find plugins. To illustrate this a bit more, consider the typical classloader hierarchy below for a Gradle project:
JVM
Gradle
Initscript
Settings
Root Project
Subproject A
Subprojects A.1
...
Subprojects A.2
...
Subproject B
Subproject B.1
...
Subproject B.2
...
...
For a moment, let's just focus in on where we would find RewriteClassLoader
and Android Gradle Plugin's BaseAppModuleExtension
to make things simplier.
When running via the OSS build plugins applied to the root project, then both classes would appear in the "Root Project" classloader above. When they are both in "Subproject A", they would both appear within the "Subproject A" classloader. Now if the OSS build plugin is at the root, but AGP is in "Subproject A", the plugin classloader logic here is necessary because the class is in a child classloader rather than a parent classloader. When the OSS build plugin is applied via an Initscript, it's now a 4th generational parent from the AGP class.
As a result of the placement of the various jars into each of their classloaders for the necessary classpath isolation, this is what is resulting in the differing behavior and ultimately the necessity of loading the AGP classes from a particular classloader. This actually compounds with each additional plugin and is probably one case where Kotlin Multiplatform may not be working fully as an example.
For the OSS build plugins, the plugin classloader part wouldn't be necessary. However, when testing via the tooling API or loading the plugin via the initscript, it results in a different location as to where to find plugins. To illustrate this a bit more, consider the typical classloader hierarchy below for a Gradle project:
JVM Gradle Initscript Settings Root Project Subproject A Subprojects A.1 ... Subprojects A.2 ... Subproject B Subproject B.1 ... Subproject B.2 ... ...
For a moment, let's just focus in on where we would find
RewriteClassLoader
and Android Gradle Plugin'sBaseAppModuleExtension
to make things simplier.When running via the OSS build plugins applied to the root project, then both classes would appear in the "Root Project" classloader above. When they are both in "Subproject A", they would both appear within the "Subproject A" classloader. Now if the OSS build plugin is at the root, but AGP is in "Subproject A", the plugin classloader logic here is necessary because the class is in a child classloader rather than a parent classloader. When the OSS build plugin is applied via an Initscript, it's now a 4th generational parent from the AGP class.
As a result of the placement of the various jars into each of their classloaders for the necessary classpath isolation, this is what is resulting in the differing behavior and ultimately the necessity of loading the AGP classes from a particular classloader. This actually compounds with each additional plugin and is probably one case where Kotlin Multiplatform may not be working fully as an example.
Thank you for these insights @shanman190. Much appreciated!
What's changed?
rewrite-gradle-plugin
to readandroid
project source sets using the Android Gradle Plugin.ClassCastException
s when loading AGP classes usingRewriteClassLoader
the class loader of the AGP plugin instance is now passed in theRewriteClassLoader
constructor and allcom.android...
classes are loaded using itAndroidProjectParser
which is lazily allocated to ensurerewrite-gradle-plugin
tasks do not attempt to load AGP classes for non-android projectsAndroidProjectCompileOptions
compileOnly
dependency of AGP v 7.0.4 was choses as it was the last version to support JDK 8 whichrewrite-gradle-plugin
targetsWhat's your motivation?
These changes will allow
rewrite-gradle-plugin
to run recipes on android project repositories.Anything in particular you'd like reviewers to focus on?
Anyone you would like to review specifically?
Have you considered any alternatives or workarounds?
I tried several approaches include adding AGP jars to
RewriteClassLoader
but could not avoidClassCastExceptions
s when assigned gradle decorated AGP classes to ones loaded byRewriteClassLoader
Any additional context
Checklist