[KAPT] Disable JPMS when running annotation processing

If sources contain module-info.java javac tries to validate modules existence/visibility during AP phase and fails, because we don't specify modules-path/patch-module. All these checks will be done in kotlin compiler and in javac for java classes. And it is not necessary to do it in AP too.
So we go for easiest path possible - disable jpms for AP. 

#KT-32202 Fixed
This commit is contained in:
Andrey
2021-03-17 11:10:27 +03:00
committed by GitHub
parent a90a5f6dd4
commit b7dc1e64b1
15 changed files with 238 additions and 10 deletions
@@ -676,4 +676,41 @@ open class Kapt3IT : Kapt3BaseIT() {
assertContains("Javac options: {-source=1.8}")
}
}
}
@Test
fun testJpmsModule() {
//jpms is part of java >= 9
val javaHome = File(System.getProperty("jdk9Home")!!)
Assume.assumeTrue("JDK 9 isn't available", javaHome.isDirectory)
val options = defaultBuildOptions().copy(javaHome = javaHome)
val project = Project("jpms-module", directoryPrefix = "kapt2")
project.build("build", options = options) {
assertSuccessful()
assertKaptSuccessful()
assertTasksExecuted(":compileKotlin", ":compileJava")
assertFileExists("build/generated/source/kapt/main/lab/TestClassGenerated.java")
assertFileExists(kotlinClassesDir() + "lab/TestClass.class")
}
project.build("build", options = options) {
assertSuccessful()
assertTasksUpToDate(":compileKotlin", ":compileJava")
}
project.projectDir.getFileByName("InjectedClass.kt").modify { text ->
text.checkedReplace(
"//placeholder",
"fun someChange() = null"
)
}
project.build("build", options = options) {
assertSuccessful()
assertKaptSuccessful()
assertTasksExecuted(":compileKotlin", ":compileJava")
}
}
}
@@ -0,0 +1,51 @@
buildscript {
repositories {
mavenLocal()
mavenCentral()
gradlePluginPortal()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: "java"
apply plugin: "kotlin"
apply plugin: "kotlin-kapt"
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.kotlin:annotation-processor-example:$kotlin_version"
kapt "org.jetbrains.kotlin:annotation-processor-example:$kotlin_version"
implementation 'com.google.dagger:dagger:2.33'
kapt 'com.google.dagger:dagger-compiler:2.33'
//jpms module provider
implementation "org.apache.logging.log4j:log4j-api:2.14.0"
}
compileKotlin.kotlinOptions.allWarningsAsErrors = true
compileJava {
doFirst {
options.compilerArgs += [
//workaround to make classpath into modules for java compilation so auto modules would work
'--module-path', classpath.asPath,
//provide compiled kotlin classes to javac (needed for java/kotlin mixed sources to work)
'--patch-module', "my.module=${sourceSets.main.output.asPath}"
]
}
}
//starting from gradle 6.4 it has built in jpms support
//still as for now it doesn't work with fully legacy jars (with no module's descriptor)
//so we need workaround above till we get AP packed as module
//java {
// modularity.inferModulePath.set(true)
//}
@@ -0,0 +1,8 @@
package dagger_example;
import dagger.Component;
@Component(modules = {ExampleModule.class})
public interface ApplicationComponent {
void inject(Main main);
}
@@ -0,0 +1,13 @@
package dagger_example;
import dagger.Binds;
import dagger.Module;
@Module
public abstract class ExampleModule {
@Binds
public abstract Injected bindInjected(InjectedImpl impl);
@Binds
public abstract OtherInjected bindOtherInjected(OtherInjectedImpl impl);
}
@@ -0,0 +1,20 @@
package dagger_example;
import javax.inject.Inject;
public class Main {
@Inject
Injected injected;
@Inject
OtherInjected otherInjected;
public static void main(String[] args) {
new Main().example();
}
private void example() {
DaggerApplicationComponent.create().inject(this);
System.out.println(injected.getMessage());
}
}
@@ -0,0 +1,6 @@
package dagger_example;
public interface OtherInjected {
public String getMessage();
}
@@ -0,0 +1,16 @@
package dagger_example;
import javax.inject.Inject;
public class OtherInjectedImpl implements OtherInjected {
@Inject
public OtherInjectedImpl() {
}
@Override
public String getMessage() {
return "zzzz";
}
}
@@ -0,0 +1,10 @@
module my.module {
requires kotlin.stdlib;
requires org.apache.logging.log4j;
requires annotation.processor.example;
requires dagger;
requires javax.inject;
//because dagger generates classes with @javax.annotation.processing.Generated
requires java.compiler;
}
@@ -0,0 +1,14 @@
package dagger_example
import javax.inject.Inject
interface Injected {
val message: String
}
class InjectedImpl @Inject constructor() : Injected {
override val message = "This is injected1: " + SomeOtherClass().callMe()
//placeholder
}
@@ -0,0 +1,7 @@
package dagger_example
class SomeOtherClass {
fun callMe() = "hell1o"
fun changeMe() = null
}
@@ -0,0 +1,15 @@
package lab
@example.ExampleAnnotation
@example.ExampleSourceAnnotation
@example.ExampleBinaryAnnotation
@example.ExampleRuntimeAnnotation
public class TestClass {
@example.ExampleAnnotation
public val testVal: String = "text"
@example.ExampleAnnotation
public fun testFunction(): TestClassGenerated = TestClassGenerated()
}
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package test
import org.apache.logging.log4j.util.Base64Util
import org.apache.logging.log4j.*
@example.ExampleAnnotation
class ModuleUser {
fun useSomethingFromModule(): String = Base64Util.encode("test")
fun haveSomeUsageInSignature(): Logger = TODO("I have nothing")
}
@@ -120,12 +120,10 @@ open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logge
options.compileClasspath + options.compiledSources + options.classesOutputDir
}
putJavacOption("CLASSPATH", "CLASS_PATH",
compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
putJavacOption("CLASSPATH", "CLASS_PATH", compileClasspath.makePathsString())
@Suppress("SpellCheckingInspection")
putJavacOption("PROCESSORPATH", "PROCESSOR_PATH",
options.processingClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
putJavacOption("PROCESSORPATH", "PROCESSOR_PATH", options.processingClasspath.makePathsString())
put(Option.S, options.sourcesOutputDir.canonicalPath)
put(Option.D, options.classesOutputDir.canonicalPath)
@@ -164,4 +162,10 @@ open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logge
compiler.close()
fileManager.close()
}
}
companion object {
const val MODULE_INFO_FILE = "module-info.java"
private fun Iterable<File>.makePathsString(): String = joinToString(File.pathSeparator) { it.canonicalPath }
}
}
@@ -38,9 +38,18 @@ fun KaptContext.doAnnotationProcessing(
val wrappedProcessors = processors.map { ProcessorWrapper(it) }
val javaSourcesToProcess = run {
//module descriptor should be in root package, but here we filter it from everywhere (bc we don't have knowledge about root here)
val filtered = javaSourceFiles.filterNot { it.name == KaptContext.MODULE_INFO_FILE }
if (filtered.size != javaSourceFiles.size) {
logger.info("${KaptContext.MODULE_INFO_FILE} is removed from sources files to disable JPMS")
}
filtered
}
val compilerAfterAP: JavaCompiler
try {
if (javaSourceFiles.isEmpty() && binaryTypesToReprocess.isEmpty() && additionalSources.isEmpty()) {
if (javaSourcesToProcess.isEmpty() && binaryTypesToReprocess.isEmpty() && additionalSources.isEmpty()) {
if (logger.isVerbose) {
logger.info("Skipping annotation processing as all sources are up-to-date.")
}
@@ -55,10 +64,10 @@ fun KaptContext.doAnnotationProcessing(
}
if (logger.isVerbose) {
logger.info("Processing java sources with annotation processors: ${javaSourceFiles.joinToString()}")
logger.info("Processing java sources with annotation processors: ${javaSourcesToProcess.joinToString()}")
logger.info("Processing types with annotation processors: ${binaryTypesToReprocess.joinToString()}")
}
val parsedJavaFiles = parseJavaFiles(javaSourceFiles)
val parsedJavaFiles = parseJavaFiles(javaSourcesToProcess)
val sourcesStructureListener = cacheManager?.let {
if (processors.any { it.isUnableToRunIncrementally() }) return@let null
@@ -231,4 +240,4 @@ private fun KaptContext.initModulesIfNeeded(files: JavacList<JCTree.JCCompilatio
}
return files
}
}