Skip to content

Commit 2c7d58d

Browse files
authored
Enhanced agp 7.4 instrumentation (#1537)
* Splitting resources from classes for local projects * Using custom dependency rule to merge class dirs and resources from local and remote deps * Using the last api's ALL scope * Fixing android descriptor * Removed project references in ByteBuddyLocalClassesEnhancerTask due to https://docs.gradle.org/8.3/userguide/configuration_cache.html#config_cache:requirements:use_project_during_execution * Update working regarding ByteBuddyLocalClassesEnhancerTask's scope * Update working regarding ByteBuddyLocalClassesEnhancerTask's scope * Update wordings and renaming methods in ByteBuddyAndroidPlugin * Renaming bytebuddy 7.4 transform tasks
1 parent cf79ad1 commit 2c7d58d

File tree

5 files changed

+238
-157
lines changed

5 files changed

+238
-157
lines changed

byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/AarGradleTransformAction.java

Lines changed: 0 additions & 91 deletions
This file was deleted.

byte-buddy-gradle-plugin/android-plugin/src/main/java/net/bytebuddy/build/gradle/android/ByteBuddyAndroidPlugin.java

Lines changed: 63 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.concurrent.ConcurrentMap;
3333
import kotlin.Unit;
3434
import kotlin.jvm.functions.Function1;
35+
import net.bytebuddy.utility.nullability.MaybeNull;
3536
import org.gradle.api.Action;
3637
import org.gradle.api.GradleException;
3738
import org.gradle.api.Plugin;
@@ -72,7 +73,8 @@ public class ByteBuddyAndroidPlugin implements Plugin<Project> {
7273
/**
7374
* The name of the Byte Buddy jar type.
7475
*/
75-
private static final String BYTE_BUDDY_JAR_TYPE = "bytebuddy-jar";
76+
public static final String BYTE_BUDDY_CLASSES_TYPE = "bytebuddy-classes";
77+
public static final String BYTE_BUDDY_RESOURCES_TYPE = "bytebuddy-resources";
7678

7779
/*
7880
* Resolves the dispatcher.
@@ -84,7 +86,7 @@ public class ByteBuddyAndroidPlugin implements Plugin<Project> {
8486
Class<?> scopedArtifacts = Class.forName("com.android.build.api.variant.ScopedArtifacts");
8587
Class<?> scopedArtifact = Class.forName("com.android.build.api.artifact.ScopedArtifact");
8688
@SuppressWarnings("unchecked")
87-
Object project = Enum.valueOf((Class) scope, "PROJECT");
89+
Object project = Enum.valueOf((Class) scope, "ALL");
8890
dispatcher = new TransformationDispatcher.ForApk74CompatibleAndroid(
8991
Artifacts.class.getMethod("forScope", scope),
9092
scopedArtifacts.getMethod("use", TaskProvider.class),
@@ -110,7 +112,6 @@ public void apply(Project project) {
110112
if (currentAgpVersion.compareTo(new AndroidPluginVersion(7, 2)) < 0) {
111113
throw new IllegalStateException("Byte Buddy requires at least Gradle Plugin version 7.2+, but found " + currentAgpVersion);
112114
}
113-
project.getDependencies().registerTransform(AarGradleTransformAction.class, new AarGradleTransformAction.ConfigurationAction());
114115
project.getDependencies().getAttributesSchema().attribute(ARTIFACT_TYPE_ATTRIBUTE, new AttributeMatchingStrategyConfigurationAction());
115116
extension.onVariants(extension.selector().all(), new VariantAction(project, project.getConfigurations().create("byteBuddy", new ConfigurationConfigurationAction())));
116117
}
@@ -151,9 +152,26 @@ protected VariantAction(Project project, Configuration configuration) {
151152
* {@inheritDoc}
152153
*/
153154
public void execute(Variant variant) {
155+
Configuration configuration = getByteBuddyConfiguration(variant);
156+
157+
if (TRANSFORMATION_DISPATCHER instanceof TransformationDispatcher.ForApk74CompatibleAndroid) {
158+
TRANSFORMATION_DISPATCHER.accept(project, variant, configuration, null);
159+
return;
160+
}
161+
162+
// Legacy api usage.
154163
Provider<ByteBuddyAndroidService> byteBuddyAndroidServiceProvider = project.getGradle().getSharedServices().registerIfAbsent(variant.getName() + "ByteBuddyAndroidService",
155164
ByteBuddyAndroidService.class,
156165
new ByteBuddyAndroidService.ConfigurationAction(project.getExtensions().getByType(BaseExtension.class)));
166+
FileCollection classPath = RuntimeClassPathResolver.INSTANCE.apply(variant);
167+
variant.getInstrumentation().transformClassesWith(ByteBuddyAsmClassVisitorFactory.class, InstrumentationScope.ALL, new ByteBuddyTransformationConfiguration(project,
168+
configuration,
169+
byteBuddyAndroidServiceProvider,
170+
classPath));
171+
TRANSFORMATION_DISPATCHER.accept(project, variant, configuration, classPath);
172+
}
173+
174+
private Configuration getByteBuddyConfiguration(Variant variant) {
157175
if (variant.getBuildType() == null) {
158176
throw new GradleException("Build type for " + variant + " was null");
159177
}
@@ -167,12 +185,7 @@ public void execute(Variant variant) {
167185
configuration = previous;
168186
}
169187
}
170-
FileCollection classPath = RuntimeClassPathResolver.INSTANCE.apply(variant);
171-
variant.getInstrumentation().transformClassesWith(ByteBuddyAsmClassVisitorFactory.class, InstrumentationScope.ALL, new ByteBuddyTransformationConfiguration(project,
172-
configuration,
173-
byteBuddyAndroidServiceProvider,
174-
classPath));
175-
TRANSFORMATION_DISPATCHER.accept(project, variant, configuration, classPath);
188+
return configuration;
176189
}
177190
}
178191

@@ -247,9 +260,9 @@ protected OfModernAgp(Method getRuntimeConfiguration) {
247260
protected FileCollection apply(Variant variant) {
248261
try {
249262
return ((Configuration) getRuntimeConfiguration.invoke(variant)).getIncoming()
250-
.artifactView(this)
251-
.getArtifacts()
252-
.getArtifactFiles();
263+
.artifactView(this)
264+
.getArtifacts()
265+
.getArtifactFiles();
253266
} catch (IllegalAccessException exception) {
254267
throw new IllegalStateException("Failed to access runtime configuration", exception);
255268
} catch (InvocationTargetException exception) {
@@ -314,7 +327,7 @@ protected ByteBuddyTransformationConfiguration(Project project,
314327
* {@inheritDoc}
315328
*/
316329
public Unit invoke(ByteBuddyInstrumentationParameters parameters) {
317-
parameters.getByteBuddyClasspath().from(configuration);
330+
parameters.getByteBuddyClasspath().from(getByteBuddyClasspath(project, configuration));
318331
parameters.getAndroidBootClasspath().from(project.getExtensions().getByType(BaseExtension.class).getBootClasspath());
319332
parameters.getRuntimeClasspath().from(classPath);
320333
parameters.getByteBuddyService().set(byteBuddyAndroidServiceProvider);
@@ -396,11 +409,9 @@ protected AttributeContainerConfigurationAction(Project project, String buildTyp
396409
* {@inheritDoc}
397410
*/
398411
public void execute(AttributeContainer attributes) {
399-
attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, BYTE_BUDDY_JAR_TYPE);
400412
attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.getObjects().named(Category.class, Category.LIBRARY));
401413
attributes.attribute(BuildTypeAttr.ATTRIBUTE, project.getObjects().named(BuildTypeAttr.class, buildType));
402414
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_RUNTIME));
403-
404415
}
405416
}
406417

@@ -413,7 +424,7 @@ protected static class AttributeMatchingStrategyConfigurationAction implements A
413424
* {@inheritDoc}
414425
*/
415426
public void execute(AttributeMatchingStrategy<String> stringAttributeMatchingStrategy) {
416-
stringAttributeMatchingStrategy.getCompatibilityRules().add(ByteBuddyJarRule.class);
427+
stringAttributeMatchingStrategy.getCompatibilityRules().add(ByteBuddyDependencyRule.class);
417428
}
418429
}
419430

@@ -434,14 +445,22 @@ public void execute(Configuration configuration) {
434445
/**
435446
* A rule to check for jar compatibility.
436447
*/
437-
public abstract static class ByteBuddyJarRule implements AttributeCompatibilityRule<String> {
448+
public abstract static class ByteBuddyDependencyRule implements AttributeCompatibilityRule<String> {
438449

439450
/**
440451
* {@inheritDoc}
441452
*/
442453
public void execute(CompatibilityCheckDetails<String> details) {
443-
if (BYTE_BUDDY_JAR_TYPE.equals(details.getConsumerValue()) && "jar".equals(details.getProducerValue())) {
444-
details.compatible();
454+
if (BYTE_BUDDY_CLASSES_TYPE.equals(details.getConsumerValue())) {
455+
String producerValue = details.getProducerValue();
456+
if ("java-classes-directory".equals(producerValue) || "android-classes-directory".equals(producerValue)) {
457+
details.compatible();
458+
}
459+
} else if (BYTE_BUDDY_RESOURCES_TYPE.equals(details.getConsumerValue())) {
460+
String producerValue = details.getProducerValue();
461+
if ("java-resources-directory".equals(producerValue) || "android-java-res".equals(producerValue)) {
462+
details.compatible();
463+
}
445464
}
446465
}
447466
}
@@ -467,7 +486,7 @@ enum ForLegacyAndroid implements TransformationDispatcher {
467486
public void accept(Project project, Variant variant, Configuration configuration, FileCollection classPath) {
468487
TaskProvider<LegacyByteBuddyLocalClassesEnhancerTask> provider = project.getTasks().register(variant.getName() + "BytebuddyLocalTransform",
469488
LegacyByteBuddyLocalClassesEnhancerTask.class,
470-
new LegacyByteBuddyLocalClassesEnhancerTask.ConfigurationAction(configuration, project.getExtensions().getByType(BaseExtension.class), classPath));
489+
new LegacyByteBuddyLocalClassesEnhancerTask.ConfigurationAction(getByteBuddyClasspath(project, configuration), project.getExtensions().getByType(BaseExtension.class), classPath));
471490
variant.getArtifacts()
472491
.use(provider)
473492
.wiredWith(GetLocalClassesFunction.INSTANCE, GetOutputDirFunction.INSTANCE)
@@ -562,13 +581,13 @@ protected ForApk74CompatibleAndroid(Method forScope, Method use, Method toTransf
562581
* {@inheritDoc}
563582
*/
564583
public void accept(Project project, Variant variant, Configuration configuration, FileCollection classPath) {
565-
TaskProvider<ByteBuddyLocalClassesEnhancerTask> provider = project.getTasks().register(variant.getName() + "BytebuddyLocalTransform",
584+
TaskProvider<ByteBuddyLocalClassesEnhancerTask> provider = project.getTasks().register(variant.getName() + "BytebuddyTransform",
566585
ByteBuddyLocalClassesEnhancerTask.class,
567-
new ByteBuddyLocalClassesEnhancerTask.ConfigurationAction(configuration, project.getExtensions().getByType(BaseExtension.class), classPath));
586+
new ByteBuddyLocalClassesEnhancerTask.ConfigurationAction(getByteBuddyClasspath(project, configuration), project.getExtensions().getByType(BaseExtension.class)));
568587
try {
569588
toTransform.invoke(use.invoke(forScope.invoke(variant.getArtifacts(), scope), provider),
570589
artifact,
571-
GetLocalJarsFunction.INSTANCE,
590+
GetProjectJarsFunction.INSTANCE,
572591
GetLocalClassesDirsFunction.INSTANCE,
573592
GetOutputFileFunction.INSTANCE);
574593
} catch (IllegalAccessException exception) {
@@ -579,9 +598,9 @@ public void accept(Project project, Variant variant, Configuration configuration
579598
}
580599

581600
/**
582-
* A function representation of resolving local jars.
601+
* A function representation of resolving local and dependencies jars.
583602
*/
584-
protected enum GetLocalJarsFunction implements Function1<ByteBuddyLocalClassesEnhancerTask, ListProperty<RegularFile>> {
603+
protected enum GetProjectJarsFunction implements Function1<ByteBuddyLocalClassesEnhancerTask, ListProperty<RegularFile>> {
585604

586605
/**
587606
* The singleton instance.
@@ -592,7 +611,7 @@ protected enum GetLocalJarsFunction implements Function1<ByteBuddyLocalClassesEn
592611
* {@inheritDoc}
593612
*/
594613
public ListProperty<RegularFile> invoke(ByteBuddyLocalClassesEnhancerTask task) {
595-
return task.getLocalJars();
614+
return task.getInputJars();
596615
}
597616
}
598617

@@ -641,6 +660,23 @@ public RegularFileProperty invoke(ByteBuddyLocalClassesEnhancerTask task) {
641660
* @param configuration The configuration to use.
642661
* @param classPath The class path to use.
643662
*/
644-
void accept(Project project, Variant variant, Configuration configuration, FileCollection classPath);
663+
void accept(Project project, Variant variant, Configuration configuration, @MaybeNull FileCollection classPath);
664+
}
665+
666+
/**
667+
* For external dependencies, it provides their JAR files. For local project's dependencies, it provides their local
668+
* build dirs for both classes and resources. The latter allows for faster and more reliable (up-to-date) compilation processes
669+
* when using local plugins.
670+
*/
671+
private static FileCollection getByteBuddyClasspath(Project project, Configuration byteBuddyConfiguration) {
672+
FileCollection resources = byteBuddyConfiguration.getIncoming().artifactView(viewConfiguration -> {
673+
viewConfiguration.lenient(false);
674+
viewConfiguration.getAttributes().attribute(ARTIFACT_TYPE_ATTRIBUTE, BYTE_BUDDY_RESOURCES_TYPE);
675+
}).getFiles();
676+
FileCollection classes = byteBuddyConfiguration.getIncoming().artifactView(viewConfiguration -> {
677+
viewConfiguration.lenient(false);
678+
viewConfiguration.getAttributes().attribute(ARTIFACT_TYPE_ATTRIBUTE, BYTE_BUDDY_CLASSES_TYPE);
679+
}).getFiles();
680+
return project.files(classes, resources);
645681
}
646682
}

0 commit comments

Comments
 (0)