We are using Tomcat 8.5 with Jersey 2 in a Web Application that compiles Java Code using an InMemoryCompiler that is similar to the one posted here: https://stackoverflow.com/a/33963977/2556413
I created a minimal example:
public static void main(String[] a) throws Exception {
new TemporaryCodexExerciseCreatorWebService().test();
}
@GET
@Path("test")
public String test() throws Exception {
final String source = "package minimal_example;" +
"import org.junit.Test;" +
"import static org.junit.Assert.*;" +
"import java.lang.annotation.*;" +
"@Documented\n" +
"@Retention(value=RetentionPolicy.RUNTIME)\n" +
"@Target(value=ElementType.METHOD)\n" +
"@interface MinimalAnnotation { }\n" +
"public class MinimalExample {" +
" @Test\n" +
" @MinimalAnnotation\n" +
" public void testTrivial() {" +
" assertTrue(true);" +
" }" +
"}";
List<JavaClass> sourceCodeList = Collections.singletonList(new JavaClass("minimal_example.MinimalExample", source));
InMemoryCompiler compiler = InMemoryCompiler.compile(sourceCodeList);
CompilerFeedback compile = compiler.getCompilerFeedback();
if (!compile.isSuccess()) {
throw new RuntimeException("Compilation failed: " + compile.getMessages());
}
Class<?> compiledClass = compiler.getCompiledClass("minimal_example.MinimalExample");
Method[] methods = compiledClass.getMethods();
for (Method m : methods) {
Annotation[] annotations = m.getAnnotations();
System.err.println(m.getName() + ": " + Arrays.toString(annotations));
}
return null;
}
If I invoke the program using the java interpreter on my command line I correctly receive an output like testTrivial: [@org.junit.Test(timeout=0, expected=class org.junit.Test$None), @minimal_example.MinimalAnnotation()]
.
But if I execute the method using the web endpoint ("/test") I only get my MinimalAnnotation and not the Test annotation from JUnit returned.
Why is this happening? I need this to work to be able to execute Unit tests programmatically after compiling them in-memory (I have seen java.lang.Exception: No runnable methods exception in running JUnits, but don't think my issue is related to that since everything works fine if the code is not running in the Servlet).
Update: Effectively, I have the same issue as the thread starter here: field.getAnnotations() returns empty array when run on a tomcat server, but returns correct annotation when run as a standalone but no one had a clue how to fix it
Update: I modified the InMemoryCompiler slightly by adding JUnit as dependency using the classpath:
List<String> options = Arrays.asList("-cp", "C:\\libraries\\junit-4.12.jar;C:\\libraries\\hamcrest-core-1.3.jar");
// this is where I pass the previously created options List
final JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, diagnostics, options, null, files);
Update: I have created a GitHub repository as showcase: https://github.com/dhardtke/tomcat-8-5-annotation-issue Just deploy it via Tomcat (after resolving the dependencies via Gradle) and you'll see when calling "/compile" that the output is incorrect.