JSR-199 Compiler API loses runtime annotations when run under grails-run app
I have a project in which I am sending source code to a grails server to be compiled using the Java Compiler API, JSR-199. I am having problems implementing it, and have boiled the problem down to the following: When compiling a file under "normal circumstances" (running a java program with java, or running JUnit tests, for instance), the JSR-199 compiler preserves runtime annotations, but executing the exact same code when running grails run-app, the runtime annotations are not preserved by compilation. I have no idea what could account for the difference, or if this is a Grails issue, or a JSR-199 issue, or a bit of both. To reproduce the effect, do the following (using JDK 6, since JSR-199 was introduced in version 6):
1) Create a grails project by executing "grails create-app Test"
2) Download JUnit 4 and place the file junit-4.4.jar in Test/lib/
3) Create a package clientpackage under Test/src/java/, and in that package, create a file ExampleTest with the following code:
ExampleTest.java begin:
------------------------------------------------------------------------------------
package clientpackage;
import org.junit.Before;
public class ExampleTest {
@Before
public void setUp() {}
}
------------------------------------------------------------------------------------
ExampleTest.java end
4) Edit conf/BootStrap.groovy to contain the following code:
Bootstrap.groovy begin:
------------------------------------------------------------------------------------
import javax.tools.*
import javax.tools.JavaCompiler.CompilationTask
class BootStrap {
def destroy = {}
def init = {servletContext ->
testCompiling()
}
def testCompiling() {
println '\n*****************************************\n'
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler()
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects('src/java/clientpackage/ExampleTest.java')
StringWriter errorLog = new StringWriter()
File outputDir = new File("bin/")
outputDir.mkdir()
List<String> options = Arrays.asList("-cp", "lib/junit-4.4.jar", "-d", outputDir.toString())
CompilationTask task = compiler.getTask(errorLog, fileManager, null, options, null, compilationUnits)
if (task.call()) {
println 'compilation succeeded'
URL[] urls = [outputDir.toURL()]
URLClassLoader classLoader = new URLClassLoader(urls);
Class<?> compiledClass;
try {
compiledClass = classLoader.loadClass('clientpackage.ExampleTest')
} catch (ClassNotFoundException e) {
throw new AssertionError("should not reach here if compilation succeeded")
}
println compiledClass.getMethod('setUp').getDeclaredAnnotations()
} else {
println "compilation failed:\n\n${errorLog.toString()}"
}
println '\n*****************************************\n'
}
}
------------------------------------------------------------------------------------
Bootstrap.groovy end
5) Create a Groovy script (for instance, in the root directory of the project) named CompileExampleTest.groovy, that contains the same code between the println '\n*****************************************\n' statements above, and the same two import statements.
6) Run the script CompileExampleTest.groovy (with working directory set to the Test project root directory) and you should see the following output:
compilation succeeded
{@org.junit.Before()}
indicating that the method setUp() is annotated, at runtime, with the org.junit.Before annotation. Now run grails run-app, and you should see the following output when BootStrap.groovy runs:
compilation succeeded
{}
indicating that the org.junit.Before annotation was lost during compilation (or during class loading).
I have no idea what could explain the difference in behavior between these two seemingly identical pieces of code.
Thank you in advance,
Dave