From cc7c5c207cdb1a3e3d9bc4719e071f7f3b1229b8 Mon Sep 17 00:00:00 2001 From: Rafael Winterhalter Date: Tue, 10 Jan 2023 22:57:31 +0100 Subject: [PATCH] Adjust internal type hierarchy. --- .../android/ByteBuddyAndroidPlugin.java | 133 ++++++++++++++---- .../DependenciesClasspathProvider.java | 56 -------- .../DefaultDependenciesClasspathProvider.java | 52 ------- .../LegacyDependenciesClasspathProvider.java | 36 ----- .../build/gradle/ByteBuddyPlugin.java | 2 +- 5 files changed, 107 insertions(+), 172 deletions(-) delete mode 100644 byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/DependenciesClasspathProvider.java delete mode 100644 byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/impl/DefaultDependenciesClasspathProvider.java delete mode 100644 byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/impl/LegacyDependenciesClasspathProvider.java diff --git a/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/ByteBuddyAndroidPlugin.java b/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/ByteBuddyAndroidPlugin.java index 87055f8659..4534a17597 100644 --- a/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/ByteBuddyAndroidPlugin.java +++ b/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/ByteBuddyAndroidPlugin.java @@ -22,25 +22,23 @@ import com.android.build.api.variant.AndroidComponentsExtension; import com.android.build.api.variant.Variant; import com.android.build.gradle.BaseExtension; +import com.android.build.gradle.internal.component.ComponentCreationConfig; +import com.android.build.gradle.internal.publishing.AndroidArtifacts; import kotlin.Unit; import kotlin.jvm.functions.Function1; -import net.bytebuddy.build.gradle.android.classpath.DependenciesClasspathProvider; import org.gradle.api.Action; import org.gradle.api.GradleException; import org.gradle.api.Plugin; import org.gradle.api.Project; +import org.gradle.api.artifacts.ArtifactView; import org.gradle.api.artifacts.Configuration; -import org.gradle.api.attributes.Attribute; -import org.gradle.api.attributes.AttributeCompatibilityRule; -import org.gradle.api.attributes.AttributeContainer; -import org.gradle.api.attributes.AttributeMatchingStrategy; -import org.gradle.api.attributes.Category; -import org.gradle.api.attributes.CompatibilityCheckDetails; -import org.gradle.api.attributes.Usage; +import org.gradle.api.attributes.*; import org.gradle.api.file.FileCollection; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.TaskProvider; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -52,7 +50,7 @@ public class ByteBuddyAndroidPlugin implements Plugin { /** * The name of the artifact type attribute. */ - public static final Attribute ARTIFACT_TYPE_ATTRIBUTE = Attribute.of("artifactType", String.class); + protected static final Attribute ARTIFACT_TYPE_ATTRIBUTE = Attribute.of("artifactType", String.class); /** * The name of the Byte Buddy jar type. @@ -71,8 +69,7 @@ public void apply(Project project) { } project.getDependencies().registerTransform(AarGradleTransformAction.class, new AarGradleTransformAction.ConfigurationAction()); project.getDependencies().getAttributesSchema().attribute(ARTIFACT_TYPE_ATTRIBUTE, new AttributeMatchingStrategyConfigurationAction()); - extension.onVariants(extension.selector().all(), new VariantAction(project, project.getConfigurations().create("byteBuddy", new ConfigurationConfigurationAction()), - DependenciesClasspathProvider.getInstance(currentAgpVersion))); + extension.onVariants(extension.selector().all(), new VariantAction(project, project.getConfigurations().create("byteBuddy", new ConfigurationConfigurationAction()))); } /** @@ -90,11 +87,6 @@ protected static class VariantAction implements Action { */ private final Configuration configuration; - /** - * The runtime classpath provider. - */ - private final DependenciesClasspathProvider classpathProvider; - /** * A cache of configurations by built type name. */ @@ -103,14 +95,12 @@ protected static class VariantAction implements Action { /** * Creates a new variant action. * - * @param project The current Gradle project. - * @param configuration The general Byte Buddy configuration. - * @param classpathProvider The runtime classpath provider. + * @param project The current Gradle project. + * @param configuration The general Byte Buddy configuration. */ - protected VariantAction(Project project, Configuration configuration, DependenciesClasspathProvider classpathProvider) { + protected VariantAction(Project project, Configuration configuration) { this.project = project; this.configuration = configuration; - this.classpathProvider = classpathProvider; configurations = new ConcurrentHashMap(); } @@ -134,22 +124,111 @@ public void execute(Variant variant) { configuration = previous; } } - FileCollection classPath = classpathProvider.getRuntimeClasspath(variant); + FileCollection classPath = RuntimeClassPathResolver.INSTANCE.apply(variant); variant.getInstrumentation().transformClassesWith(ByteBuddyAsmClassVisitorFactory.class, InstrumentationScope.ALL, new ByteBuddyTransformationConfiguration(project, configuration, byteBuddyAndroidServiceProvider, classPath)); - TaskProvider localClassesTransformation = project.getTasks().register(variant.getName() + "BytebuddyLocalTransform", ByteBuddyLocalClassesEnhancerTask.class, - new ByteBuddyLocalClassesEnhancerTask.ConfigurationAction( - configuration, - project.getExtensions().getByType(BaseExtension.class), - classPath)); + TaskProvider localClassesTransformation = project.getTasks().register(variant.getName() + "BytebuddyLocalTransform", + ByteBuddyLocalClassesEnhancerTask.class, + new ByteBuddyLocalClassesEnhancerTask.ConfigurationAction(configuration, project.getExtensions().getByType(BaseExtension.class), classPath)); variant.getArtifacts().use(localClassesTransformation) .wiredWith(ByteBuddyLocalClassesEnhancerTask::getLocalClassesDirs, ByteBuddyLocalClassesEnhancerTask::getOutputDir) .toTransform(MultipleArtifact.ALL_CLASSES_DIRS.INSTANCE); } } + /** + * A dispatcher for resolving the runtime class path. + */ + protected abstract static class RuntimeClassPathResolver { + + /** + * The runtime class path resolver to use. + */ + protected static final RuntimeClassPathResolver INSTANCE; + + /* + * Creates the runtime class path resolver to use. + */ + static { + RuntimeClassPathResolver instance; + try { + instance = new OfModernAgp(Variant.class.getMethod("getRuntimeConfiguration")); + } catch (Throwable ignored) { + instance = new OfLegacyAgp(); + } + INSTANCE = instance; + } + + /** + * Resolves the runtime class path. + * + * @param variant The variant for which to resolve the runtime class path. + * @return The runtime class path. + */ + protected abstract FileCollection apply(Variant variant); + + /** + * Before AGP 7.3, the {@code com.android.build.api.variant.Variant#getRuntimeConfiguration()} method is not available and an + * internal cast must be used to resolve the runtime class path. + */ + protected static class OfLegacyAgp extends RuntimeClassPathResolver { + + @Override + protected FileCollection apply(Variant variant) { + if (!(variant instanceof ComponentCreationConfig)) { + throw new GradleException("Cannot resolve runtime class path for " + variant); + } + return ((ComponentCreationConfig) variant).getVariantDependencies().getArtifactFileCollection(AndroidArtifacts.ConsumedConfigType.RUNTIME_CLASSPATH, + AndroidArtifacts.ArtifactScope.ALL, + AndroidArtifacts.ArtifactType.CLASSES_JAR); + } + } + + /** + * From AGP 7.3, the runtime configuration can be queried from the {@link Variant}. + */ + protected static class OfModernAgp extends RuntimeClassPathResolver implements Action { + + /** + * The {@code com.android.build.api.variant.Variant#getRuntimeConfiguration()} method. + */ + private final Method getRuntimeConfiguration; + + /** + * Creates a new resolver. + * + * @param getRuntimeConfiguration The {@code com.android.build.api.variant.Variant#getRuntimeConfiguration()} method. + */ + protected OfModernAgp(Method getRuntimeConfiguration) { + this.getRuntimeConfiguration = getRuntimeConfiguration; + } + + @Override + protected FileCollection apply(Variant variant) { + try { + return ((Configuration) getRuntimeConfiguration.invoke(variant)).getIncoming() + .artifactView(this) + .getArtifacts() + .getArtifactFiles(); + } catch (IllegalAccessException exception) { + throw new IllegalStateException("Failed to access runtime configuration", exception); + } catch (InvocationTargetException exception) { + throw new IllegalStateException("Failed to resolve runtime configuration", exception.getCause()); + } + } + + /** + * {@inheritDoc} + */ + public void execute(ArtifactView.ViewConfiguration configuration) { + configuration.setLenient(false); + configuration.getAttributes().attribute(ARTIFACT_TYPE_ATTRIBUTE, "android-classes-jar"); + } + } + } + /** * A function to register Byte Buddy instrumentation parameters into the current execution. */ diff --git a/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/DependenciesClasspathProvider.java b/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/DependenciesClasspathProvider.java deleted file mode 100644 index b9bb8c7b78..0000000000 --- a/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/DependenciesClasspathProvider.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014 - Present Rafael Winterhalter - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.bytebuddy.build.gradle.android.classpath; - -import com.android.build.api.AndroidPluginVersion; -import com.android.build.api.variant.Variant; -import org.gradle.api.file.FileCollection; -import org.gradle.api.logging.Logger; -import org.gradle.api.logging.Logging; - -import java.lang.reflect.InvocationTargetException; - -/** - * Needed to query the runtime classpath for an Android project, which process has changed in recent versions of the - * AGP plugin, so each method gets its own implementation. - */ -public interface DependenciesClasspathProvider { - - /** - * Returns the appropriate {@link DependenciesClasspathProvider} implementation based on the AGP version that the host - * project is running. - * - * @param currentVersion The current AGP version used in the host project. - */ - static DependenciesClasspathProvider getInstance(AndroidPluginVersion currentVersion) { - boolean isLowerThan73 = currentVersion.compareTo(new AndroidPluginVersion(7, 3)) < 0; - Logger logger = Logging.getLogger(DependenciesClasspathProvider.class); - try { - if (isLowerThan73) { - logger.debug("Using legacy classpath provider implementation"); - return (DependenciesClasspathProvider) Class.forName("net.bytebuddy.build.gradle.android.classpath.impl.LegacyDependenciesClasspathProvider").getDeclaredConstructor().newInstance(); - } else { - logger.debug("Using default classpath provider implementation"); - return (DependenciesClasspathProvider) Class.forName("net.bytebuddy.build.gradle.android.classpath.impl.DefaultDependenciesClasspathProvider").getDeclaredConstructor().newInstance(); - } - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | - NoSuchMethodException | ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - - FileCollection getRuntimeClasspath(Variant variant); -} diff --git a/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/impl/DefaultDependenciesClasspathProvider.java b/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/impl/DefaultDependenciesClasspathProvider.java deleted file mode 100644 index 54413752b9..0000000000 --- a/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/impl/DefaultDependenciesClasspathProvider.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2014 - Present Rafael Winterhalter - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.bytebuddy.build.gradle.android.classpath.impl; - -import com.android.build.api.variant.Variant; -import net.bytebuddy.build.gradle.android.classpath.DependenciesClasspathProvider; -import org.gradle.api.Action; -import org.gradle.api.artifacts.ArtifactView; -import org.gradle.api.file.FileCollection; - -import static net.bytebuddy.build.gradle.android.ByteBuddyAndroidPlugin.ARTIFACT_TYPE_ATTRIBUTE; - -/** - * This implementation uses the method {@link Variant#getRuntimeConfiguration()} which was added in AGP version 7.3.0. - */ -public class DefaultDependenciesClasspathProvider implements DependenciesClasspathProvider { - - @Override - public FileCollection getRuntimeClasspath(Variant variant) { - return variant.getRuntimeConfiguration().getIncoming() - .artifactView(new JarsViewAction()) - .getArtifacts() - .getArtifactFiles(); - } - - /** - * Needed to query ".jar" files from both, plain Java libraries and Android libraries too. Android libraries - * are files of type ".aar" which contain a ".jar" file inside, without this filter, we'd get Android libraries - * as raw ".aar" files, which cannot be used for Java classpath purposes. - */ - protected static class JarsViewAction implements Action { - - @Override - public void execute(ArtifactView.ViewConfiguration configuration) { - configuration.setLenient(false); - configuration.getAttributes().attribute(ARTIFACT_TYPE_ATTRIBUTE, "android-classes-jar"); - } - } -} \ No newline at end of file diff --git a/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/impl/LegacyDependenciesClasspathProvider.java b/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/impl/LegacyDependenciesClasspathProvider.java deleted file mode 100644 index f38192aece..0000000000 --- a/byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/classpath/impl/LegacyDependenciesClasspathProvider.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 - Present Rafael Winterhalter - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.bytebuddy.build.gradle.android.classpath.impl; - -import com.android.build.api.component.impl.ComponentImpl; -import com.android.build.api.variant.Variant; -import com.android.build.gradle.internal.publishing.AndroidArtifacts; -import net.bytebuddy.build.gradle.android.classpath.DependenciesClasspathProvider; -import org.gradle.api.file.FileCollection; - -/** - * This implementation is needed for projects running AGP version < 7.3, since the method {@link Variant#getRuntimeConfiguration()} - * was added in AGP 7.3.0. So this legacy implementation uses a workaround due to the missing "getRuntimeConfiguration" method. - */ -public class LegacyDependenciesClasspathProvider implements DependenciesClasspathProvider { - - @Override - public FileCollection getRuntimeClasspath(Variant variant) { - return ((ComponentImpl) variant).getVariantDependencies().getArtifactFileCollection(AndroidArtifacts.ConsumedConfigType.RUNTIME_CLASSPATH, - AndroidArtifacts.ArtifactScope.ALL, - AndroidArtifacts.ArtifactType.CLASSES_JAR); - } -} diff --git a/byte-buddy-gradle-plugin/src/main/java/net/bytebuddy/build/gradle/ByteBuddyPlugin.java b/byte-buddy-gradle-plugin/src/main/java/net/bytebuddy/build/gradle/ByteBuddyPlugin.java index 2c13034fbc..eb1a1b195e 100644 --- a/byte-buddy-gradle-plugin/src/main/java/net/bytebuddy/build/gradle/ByteBuddyPlugin.java +++ b/byte-buddy-gradle-plugin/src/main/java/net/bytebuddy/build/gradle/ByteBuddyPlugin.java @@ -48,7 +48,7 @@ public class ByteBuddyPlugin implements Plugin { Class.forName("org.gradle.work.InputChanges"); // Make sure that at least Gradle 6 is available. dispatcher = new Dispatcher.ForApi6CapableGradle(SourceDirectorySet.class.getMethod("getDestinationDirectory"), AbstractCompile.class.getMethod("setDestinationDir", Class.forName("org.gradle.api.provider.Provider"))); - } catch (Exception ignored) { + } catch (Throwable ignored) { dispatcher = Dispatcher.ForLegacyGradle.INSTANCE; } DISPATCHER = dispatcher;