Kapt3: Handle exceptions while annotation processing gracefully
This commit is contained in:
committed by
Yan Zhulanow
parent
aae80fa4ab
commit
65a9d9e8d2
+61
-8
@@ -20,7 +20,9 @@ import com.sun.tools.javac.comp.CompileStates
|
||||
import com.sun.tools.javac.file.JavacFileManager
|
||||
import com.sun.tools.javac.main.JavaCompiler
|
||||
import com.sun.tools.javac.main.Option
|
||||
import com.sun.tools.javac.processing.AnnotationProcessingError
|
||||
import com.sun.tools.javac.processing.JavacProcessingEnvironment
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import com.sun.tools.javac.util.Context
|
||||
import com.sun.tools.javac.util.Log
|
||||
import com.sun.tools.javac.util.Options
|
||||
@@ -28,21 +30,65 @@ import java.io.File
|
||||
import java.io.PrintWriter
|
||||
import javax.annotation.processing.Processor
|
||||
import javax.tools.JavaFileManager
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
class KaptError : RuntimeException {
|
||||
constructor(message: String) : super(message)
|
||||
constructor(message: String, cause: Throwable) : super(message, cause)
|
||||
val kind: Kind
|
||||
|
||||
enum class Kind(val message: String) {
|
||||
JAVA_FILE_PARSING_ERROR("Java file parsing error"),
|
||||
EXCEPTION("Exception while annotation processing"),
|
||||
UNKNOWN("Unknown error while annotation processing")
|
||||
}
|
||||
|
||||
constructor(kind: Kind) : super(kind.message) {
|
||||
this.kind = kind
|
||||
}
|
||||
|
||||
constructor(kind: Kind, cause: Throwable) : super(kind.message, cause) {
|
||||
this.kind = kind
|
||||
}
|
||||
}
|
||||
|
||||
class KaptRunner {
|
||||
fun doAnnotationProcessing(javaSourceFiles: List<File>, processors: List<Processor>, sourceOutputDir: File, classOutputDir: File) {
|
||||
val context = Context()
|
||||
private val context = Context()
|
||||
private val options: Options
|
||||
|
||||
init {
|
||||
JavacFileManager.preRegister(context)
|
||||
KaptJavaCompiler.preRegister(context)
|
||||
|
||||
val options = Options.instance(context)
|
||||
options = Options.instance(context)
|
||||
context.put(Log.outKey, PrintWriter(System.err, true))
|
||||
}
|
||||
|
||||
fun parseJavaFiles(
|
||||
javaSourceFiles: List<File>,
|
||||
classpath: List<File>
|
||||
): JavacList<JCTree.JCCompilationUnit> {
|
||||
classpath.forEach { options.put(Option.CLASSPATH, it.canonicalPath) }
|
||||
|
||||
val fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
|
||||
val compiler = JavaCompiler.instance(context) as KaptJavaCompiler
|
||||
|
||||
try {
|
||||
val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
|
||||
return compiler.parseFiles(javaFileObjects)
|
||||
} finally {
|
||||
fileManager.close()
|
||||
compiler.close()
|
||||
}
|
||||
}
|
||||
|
||||
fun doAnnotationProcessing(
|
||||
javaSourceFiles: List<File>,
|
||||
processors: List<Processor>,
|
||||
classpath: List<File>,
|
||||
sourceOutputDir: File,
|
||||
classOutputDir: File
|
||||
) {
|
||||
options.put(Option.PROC, "only") // Only process annotations
|
||||
classpath.forEach { options.put(Option.CLASSPATH, it.canonicalPath) }
|
||||
options.put(Option.S, sourceOutputDir.canonicalPath)
|
||||
options.put(Option.D, classOutputDir.canonicalPath)
|
||||
|
||||
@@ -56,13 +102,20 @@ class KaptRunner {
|
||||
val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
|
||||
val parsedJavaFiles = compiler.parseFiles(javaFileObjects)
|
||||
if (compiler.shouldStop(CompileStates.CompileState.PARSE)) {
|
||||
throw KaptError("Error while parsing Java files.")
|
||||
throw KaptError(KaptError.Kind.JAVA_FILE_PARSING_ERROR)
|
||||
}
|
||||
|
||||
val compilerAfterAnnotationProcessing = compiler.processAnnotations(compiler.enterTrees(parsedJavaFiles))
|
||||
compilerAfterAnnotationProcessing.close()
|
||||
val compilerAfterAnnotationProcessing: JavaCompiler? = null
|
||||
try {
|
||||
compiler.processAnnotations(compiler.enterTrees(parsedJavaFiles))
|
||||
} catch (e: AnnotationProcessingError) {
|
||||
throw KaptError(KaptError.Kind.EXCEPTION, e.cause ?: e)
|
||||
}
|
||||
|
||||
compilerAfterAnnotationProcessing?.close()
|
||||
} finally {
|
||||
processingEnvironment.close()
|
||||
compiler.close()
|
||||
fileManager.close()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import org.jetbrains.kotlin.kapt3.KaptError
|
||||
import org.jetbrains.kotlin.kapt3.KaptRunner
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.*
|
||||
@@ -27,11 +28,8 @@ import javax.lang.model.element.TypeElement
|
||||
class KaptRunnerTest {
|
||||
private companion object {
|
||||
val TEST_DATA_DIR = File("plugins/kapt3/testData/runner")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSimple() {
|
||||
val processor = object : AbstractProcessor() {
|
||||
val SIMPLE_PROCESSOR = object : AbstractProcessor() {
|
||||
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
|
||||
for (annotation in annotations) {
|
||||
val annotationName = annotation.simpleName.toString()
|
||||
@@ -54,12 +52,16 @@ class KaptRunnerTest {
|
||||
|
||||
override fun getSupportedAnnotationTypes() = setOf("test.MyAnnotation")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSimple() {
|
||||
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
|
||||
try {
|
||||
KaptRunner().doAnnotationProcessing(
|
||||
listOf(File(TEST_DATA_DIR, "Simple.java")),
|
||||
listOf(processor),
|
||||
listOf(SIMPLE_PROCESSOR),
|
||||
emptyList(), // classpath
|
||||
sourceOutputDir,
|
||||
sourceOutputDir)
|
||||
val myMethodFile = File(sourceOutputDir, "generated/MyMethodMyAnnotation.java")
|
||||
@@ -68,4 +70,43 @@ class KaptRunnerTest {
|
||||
sourceOutputDir.deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testException() {
|
||||
val exceptionMessage = "Here we are!"
|
||||
|
||||
val processor = object : AbstractProcessor() {
|
||||
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
|
||||
throw RuntimeException(exceptionMessage)
|
||||
}
|
||||
|
||||
override fun getSupportedAnnotationTypes() = setOf("test.MyAnnotation")
|
||||
}
|
||||
|
||||
try {
|
||||
KaptRunner().doAnnotationProcessing(
|
||||
listOf(File(TEST_DATA_DIR, "Simple.java")),
|
||||
listOf(processor),
|
||||
emptyList(),
|
||||
TEST_DATA_DIR,
|
||||
TEST_DATA_DIR)
|
||||
} catch (e: KaptError) {
|
||||
assertEquals(KaptError.Kind.EXCEPTION, e.kind)
|
||||
assertEquals("Here we are!", e.cause!!.message)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParsingError() {
|
||||
try {
|
||||
KaptRunner().doAnnotationProcessing(
|
||||
listOf(File(TEST_DATA_DIR, "ParseError.java")),
|
||||
listOf(SIMPLE_PROCESSOR),
|
||||
emptyList(),
|
||||
TEST_DATA_DIR,
|
||||
TEST_DATA_DIR)
|
||||
} catch (e: KaptError) {
|
||||
assertEquals(KaptError.Kind.JAVA_FILE_PARSING_ERROR, e.kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
BLAHBLAH
|
||||
Reference in New Issue
Block a user