diff --git a/compiler/plugin-api/src/org/jetbrains/kotlin/compiler/plugin/CommandLineProcessor.kt b/compiler/plugin-api/src/org/jetbrains/kotlin/compiler/plugin/CommandLineProcessor.kt index c463c3ccea2..96a963e012e 100644 --- a/compiler/plugin-api/src/org/jetbrains/kotlin/compiler/plugin/CommandLineProcessor.kt +++ b/compiler/plugin-api/src/org/jetbrains/kotlin/compiler/plugin/CommandLineProcessor.kt @@ -31,6 +31,12 @@ interface CommandLineProcessor { put(option, paths) } + fun CompilerConfiguration.appendList(option: CompilerConfigurationKey>, values: List) { + val paths = getList(option).toMutableList() + paths.addAll(values) + put(option, paths) + } + fun CompilerConfiguration.applyOptionsFrom(map: Map>, pluginOptions: Collection) { for ((key, values) in map) { val option = pluginOptions.firstOrNull { it.name == key } ?: continue diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt index 73dea124b71..df9877fc85e 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt @@ -69,6 +69,7 @@ open class Kapt3IT : Kapt3BaseIT() { assertContains("example.JavaTest PASSED") assertClassFilesNotContain(File(project.projectDir, "build/classes"), "ExampleSourceAnnotation") assertNotContains("warning: The following options were not recognized by any processor") + assertContains("Need to discovery annotation processors in the AP classpath") } project.build("build") { @@ -135,6 +136,7 @@ open class Kapt3IT : Kapt3BaseIT() { assertFileExists("build/generated/source/kapt/main/example/TestClassCustomized.java") assertFileExists(kotlinClassesDir() + "example/TestClass.class") assertFileExists(javaClassesDir() + "example/TestClassCustomized.class") + assertContains("Annotation processor class names are set, skip AP discovery") } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/arguments/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/arguments/build.gradle index 7ff7739cf42..455654bfba7 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/arguments/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/arguments/build.gradle @@ -44,4 +44,6 @@ kapt { javacOptions { option("-Xlint:all") } + + annotationProcessor("example.ExampleAnnotationProcessor") } \ No newline at end of file diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt index 979f8d7203e..eca65c13235 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt @@ -67,7 +67,7 @@ class ClasspathBasedKapt3Extension( incrementalDataOutputDir: File?, options: Map, javacOptions: Map, - annotationProcessors: String, + annotationProcessorFqNames: List, aptMode: AptMode, val useLightAnalysis: Boolean, correctErrorTypes: Boolean, @@ -76,7 +76,7 @@ class ClasspathBasedKapt3Extension( logger: KaptLogger, compilerConfiguration: CompilerConfiguration ) : AbstractKapt3Extension(compileClasspath, annotationProcessingClasspath, javaSourceRoots, sourcesOutputDir, - classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, options, javacOptions, annotationProcessors, + classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, options, javacOptions, annotationProcessorFqNames, aptMode, pluginInitializedTime, logger, correctErrorTypes, mapDiagnosticLocations, compilerConfiguration) { override val analyzePartially: Boolean get() = useLightAnalysis @@ -103,7 +103,14 @@ class ClasspathBasedKapt3Extension( val classpath = annotationProcessingClasspath + compileClasspath val classLoader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray()) this.annotationProcessingClassLoader = classLoader - val processors = ServiceLoader.load(Processor::class.java, classLoader).toList() + + val processors = if (annotationProcessorFqNames.isNotEmpty()) { + logger.info("Annotation processor class names are set, skip AP discovery") + annotationProcessorFqNames.mapNotNull { tryLoadProcessor(it, classLoader) } + } else { + logger.info("Need to discovery annotation processors in the AP classpath") + ServiceLoader.load(Processor::class.java, classLoader).toList() + } if (processors.isEmpty()) { logger.info("No annotation processors available, aborting") @@ -113,6 +120,28 @@ class ClasspathBasedKapt3Extension( return processors } + + private fun tryLoadProcessor(fqName: String, classLoader: ClassLoader): Processor? { + val annotationProcessorClass = try { + Class.forName(fqName, true, classLoader) + } catch (e: Throwable) { + logger.warn("Can't find annotation processor class $fqName: ${e.message}") + return null + } + + try { + val annotationProcessorInstance = annotationProcessorClass.newInstance() + if (annotationProcessorInstance !is Processor) { + logger.warn("$fqName is not an instance of 'Processor'") + return null + } + + return annotationProcessorInstance + } catch (e: Throwable) { + logger.warn("Can't load annotation processor class $fqName: ${e.message}") + return null + } + } } abstract class AbstractKapt3Extension( @@ -125,7 +154,7 @@ abstract class AbstractKapt3Extension( val incrementalDataOutputDir: File?, val options: Map, val javacOptions: Map, - val annotationProcessors: String, + val annotationProcessorFqNames: List, val aptMode: AptMode, val pluginInitializedTime: Long, val logger: KaptLogger, @@ -224,8 +253,7 @@ abstract class AbstractKapt3Extension( val (annotationProcessingTime) = measureTimeMillis { kaptContext.doAnnotationProcessing( - javaSourceFiles, processors, compileClasspath, annotationProcessingClasspath, - annotationProcessors, sourcesOutputDir, classFilesOutputDir) + javaSourceFiles, processors, compileClasspath, annotationProcessingClasspath, sourcesOutputDir, classFilesOutputDir) } logger.info { "Annotation processing took $annotationProcessingTime ms" } diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt index fd75f5d676c..04b60ffc399 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt @@ -84,8 +84,8 @@ object Kapt3ConfigurationKeys { val JAVAC_CLI_OPTIONS: CompilerConfigurationKey = CompilerConfigurationKey.create(JAVAC_CLI_OPTIONS_OPTION.description) - val ANNOTATION_PROCESSORS: CompilerConfigurationKey = - CompilerConfigurationKey.create(ANNOTATION_PROCESSORS_OPTION.description) + val ANNOTATION_PROCESSORS: CompilerConfigurationKey> = + CompilerConfigurationKey.create>(ANNOTATION_PROCESSORS_OPTION.description) val VERBOSE_MODE: CompilerConfigurationKey = CompilerConfigurationKey.create(VERBOSE_MODE_OPTION.description) @@ -174,7 +174,8 @@ class Kapt3CommandLineProcessor : CommandLineProcessor { override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) { when (option) { ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> configuration.appendList(ANNOTATION_PROCESSOR_CLASSPATH, value) - ANNOTATION_PROCESSORS_OPTION -> configuration.put(Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS, value) + ANNOTATION_PROCESSORS_OPTION -> configuration.appendList( + Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS, value.split(',').map { it.trim() }.filter { it.isNotEmpty() }) APT_OPTIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_OPTIONS, value) JAVAC_CLI_OPTIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.JAVAC_CLI_OPTIONS, value) SOURCE_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.SOURCE_OUTPUT_DIR, value) @@ -237,7 +238,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar { val stubsOutputDir = configuration.get(Kapt3ConfigurationKeys.STUBS_OUTPUT_DIR)?.let(::File) val incrementalDataOutputDir = configuration.get(Kapt3ConfigurationKeys.INCREMENTAL_DATA_OUTPUT_DIR)?.let(::File) - val annotationProcessors = configuration.get(Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS) ?: "" + val annotationProcessors = configuration.get(Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS) ?: emptyList() val apClasspath = configuration.get(ANNOTATION_PROCESSOR_CLASSPATH)?.map(::File) ?: emptyList() @@ -289,7 +290,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar { logger.info("Incremental data output directory: $incrementalDataOutputDir") logger.info("Compile classpath: " + compileClasspath.joinToString()) logger.info("Annotation processing classpath: " + apClasspath.joinToString()) - logger.info("Annotation processors: " + annotationProcessors) + logger.info("Annotation processors: " + annotationProcessors.joinToString()) logger.info("Java source roots: " + javaSourceRoots.joinToString()) logger.info("Options: $apOptions") } diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/annotationProcessing.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/annotationProcessing.kt index 12c444c17dc..4d7641cc5b9 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/annotationProcessing.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/annotationProcessing.kt @@ -39,7 +39,6 @@ fun KaptContext<*>.doAnnotationProcessing( processors: List, compileClasspath: List, annotationProcessingClasspath: List, - annotationProcessors: String, sourcesOutputDir: File, classesOutputDir: File, additionalSources: JavacList = JavacList.nil(), @@ -54,7 +53,6 @@ fun KaptContext<*>.doAnnotationProcessing( putJavacOption("CLASSPATH", "CLASS_PATH", compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath }) putJavacOption("PROCESSORPATH", "PROCESSOR_PATH", annotationProcessingClasspath.joinToString(File.pathSeparator) { it.canonicalPath }) - put(Option.PROCESSOR, annotationProcessors) put(Option.S, sourcesOutputDir.canonicalPath) put(Option.D, classesOutputDir.canonicalPath) put(Option.ENCODING, "UTF-8") diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt index aa89ec198aa..408d81dae00 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt @@ -164,7 +164,7 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() { incrementalDataOutputDir: File ) : AbstractKapt3Extension(PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath, emptyList(), javaSourceRoots, outputDir, outputDir, - stubsOutputDir, incrementalDataOutputDir, options, emptyMap(), "", STUBS_AND_APT, System.currentTimeMillis(), + stubsOutputDir, incrementalDataOutputDir, options, emptyMap(), emptyList(), STUBS_AND_APT, System.currentTimeMillis(), KaptLogger(true), correctErrorTypes = true, mapDiagnosticLocations = true, compilerConfiguration = CompilerConfiguration.EMPTY ) { diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt index b62f743d15c..ba44069f5a1 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt @@ -285,9 +285,10 @@ abstract class AbstractKotlinKaptContextTest : AbstractKotlinKapt3Test() { try { kaptContext.doAnnotationProcessing(emptyList(), listOf(JavaKaptContextTest.simpleProcessor()), compileClasspath = PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath, - annotationProcessingClasspath = emptyList(), annotationProcessors = "", + annotationProcessingClasspath = emptyList(), sourcesOutputDir = sourceOutputDir, classesOutputDir = sourceOutputDir, - additionalSources = compilationUnits, withJdk = true) + additionalSources = compilationUnits, withJdk = true + ) val javaFiles = sourceOutputDir.walkTopDown().filter { it.isFile && it.extension == "java" } val actualRaw = javaFiles.sortedBy { it.name }.joinToString(FILE_SEPARATOR) { it.name + ":\n\n" + it.readText() } diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/JavaKaptContextTest.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/JavaKaptContextTest.kt index 102d39cb1a2..16d17261d4b 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/JavaKaptContextTest.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/JavaKaptContextTest.kt @@ -93,7 +93,6 @@ class JavaKaptContextTest { listOf(processor), emptyList(), // compile classpath emptyList(), // annotation processing classpath - "", // list of annotation processor qualified names outputDir, outputDir, withJdk = true)