diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt index e3d6d07aa71..98fa696fba8 100644 --- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt +++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt @@ -32,6 +32,7 @@ import dagger.hilt.android.plugin.util.CopyTransform import dagger.hilt.android.plugin.util.SimpleAGPVersion import dagger.hilt.android.plugin.util.capitalize import dagger.hilt.android.plugin.util.getAndroidComponentsExtension +import dagger.hilt.android.plugin.util.getKaptConfigName import dagger.hilt.android.plugin.util.getSdkPath import java.io.File import javax.inject.Inject @@ -397,7 +398,16 @@ class HiltGradlePlugin @Inject constructor( annotationProcessorPath = project.configurations.create( "hiltAnnotationProcessor${variant.name.capitalize()}" ).also { config -> - // TODO: Consider finding the hilt-compiler dep from the user config and using it here. + config.isCanBeConsumed = false + config.isCanBeResolved = true + // Add user annotation processor configuration, so that SPI plugins and other processors + // are discoverable. + val apConfigurations: List = mutableListOf().apply { + add(variant.annotationProcessorConfiguration) + project.configurations.findByName(getKaptConfigName(variant))?.let { add(it) } + } + config.extendsFrom(*apConfigurations.toTypedArray()) + // Add hilt-compiler even though it might be in the AP configurations already. project.dependencies.add(config.name, "com.google.dagger:hilt-compiler:$HILT_VERSION") } generatedSourceOutputDirectory.set( diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Configurations.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Configurations.kt new file mode 100644 index 00000000000..0fe2f8324e4 --- /dev/null +++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Configurations.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 The Dagger Authors. + * + * 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 dagger.hilt.android.plugin.util + +@Suppress("DEPRECATION") // Older variant API is deprecated +internal fun getKaptConfigName(variant: com.android.build.gradle.api.BaseVariant): String { + // KAPT config names don't follow the usual convention: + // -> + // debug -> kaptDebug + // debugAndroidTest -> kaptAndroidTestDebug + // debugUnitTest -> kaptTestDebug + // release -> kaptRelease + // releaseUnitTest -> kaptTestRelease + return when (variant) { + is com.android.build.gradle.api.TestVariant -> + "kaptAndroidTest${variant.name.substringBeforeLast("AndroidTest").capitalize()}" + is com.android.build.gradle.api.UnitTestVariant -> + "kaptTest${variant.name.substringBeforeLast("UnitTest").capitalize()}" + else -> + "kapt${variant.name}" + } +} \ No newline at end of file diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/build.gradle b/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/build.gradle new file mode 100644 index 00000000000..6bcd9ac1db5 --- /dev/null +++ b/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/build.gradle @@ -0,0 +1,12 @@ +plugins { + id 'java-library' +} + +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +dependencies { + implementation "com.google.dagger:dagger-spi:LOCAL-SNAPSHOT" +} \ No newline at end of file diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/java/spi/TestPlugin.java b/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/java/spi/TestPlugin.java new file mode 100644 index 00000000000..1104ba0e272 --- /dev/null +++ b/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/java/spi/TestPlugin.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 The Dagger Authors. + * + * 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 spi; + +import dagger.model.BindingGraph; +import dagger.model.BindingGraph.ComponentNode; +import dagger.spi.BindingGraphPlugin; +import dagger.spi.DiagnosticReporter; +import javax.tools.Diagnostic; + +/** + * A SPI plugin that reports an error when visiting a root component. + */ +public class TestPlugin implements BindingGraphPlugin { + @Override + public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) { + ComponentNode componentNode = bindingGraph.rootComponentNode(); + if (componentNode.isRealComponent()) { + diagnosticReporter.reportComponent( + Diagnostic.Kind.ERROR, + componentNode, + "Found component: " + componentNode.componentPath() + ); + } + } +} \ No newline at end of file diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/resources/META-INF/services/dagger.spi.BindingGraphPlugin b/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/resources/META-INF/services/dagger.spi.BindingGraphPlugin new file mode 100644 index 00000000000..36b9be07f09 --- /dev/null +++ b/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/resources/META-INF/services/dagger.spi.BindingGraphPlugin @@ -0,0 +1 @@ +spi.TestPlugin \ No newline at end of file diff --git a/java/dagger/hilt/android/plugin/main/src/test/kotlin/SPIPluginTest.kt b/java/dagger/hilt/android/plugin/main/src/test/kotlin/SPIPluginTest.kt new file mode 100644 index 00000000000..ffe6dc0fa22 --- /dev/null +++ b/java/dagger/hilt/android/plugin/main/src/test/kotlin/SPIPluginTest.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2022 The Dagger Authors. + * + * 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. + */ + +import com.google.common.truth.Truth.assertThat +import java.io.File +import org.gradle.testkit.runner.TaskOutcome +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder + +class SPIPluginTest { + @get:Rule + val testProjectDir = TemporaryFolder() + + lateinit var gradleRunner: GradleTestRunner + + @Before + fun setup() { + gradleRunner = GradleTestRunner(testProjectDir) + File("src/test/data/spi-plugin") + .copyRecursively(File(testProjectDir.root, "spi-plugin")) + testProjectDir.newFile("settings.gradle").apply { + writeText( + """ + include ':spi-plugin' + """.trimIndent() + ) + } + gradleRunner.addHiltOption("enableAggregatingTask = true") + gradleRunner.addDependencies( + "implementation 'androidx.appcompat:appcompat:1.1.0'", + "implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'", + "annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'", + "annotationProcessor project(':spi-plugin')", + ) + gradleRunner.addSrc( + srcPath = "minimal/MyApp.java", + srcContent = + """ + package minimal; + + import android.app.Application; + + @dagger.hilt.android.HiltAndroidApp + public class MyApp extends Application { + } + """.trimIndent() + ) + gradleRunner.setAppClassName(".MyApp") + } + + @Test + fun verifyPluginWithHiltAggregation() { + // Run the build expecting it to fail because the TestPlugin will report an error if it finds + // the root component, the build not failing is an indication that the plugin is not being + // discovered in Hilt's aggregation JavaCompileTask. + val result = gradleRunner.buildAndFail() + assertThat(result.getTask(":hiltJavaCompileDebug").outcome).isEqualTo(TaskOutcome.FAILED) + assertThat(result.getOutput()).contains( + "[spi.TestPlugin] Found component: minimal.MyApp_HiltComponents.SingletonC" + ) + } +} \ No newline at end of file