Problem using JavaCompile compiler arg Xstdout

Task: Using the Gradle Java Plugin I want to redirect all java compiler warnings to a file for further analysis (Jenkins static code analysis tools).

Environment: Windows 7 x64 JDK 1.7.0_51 64-Bit Gradle 1.4 (tried 1.12 -> same result) STS (Eclipse) Gradle IDE multiple projects

Problem: I expected the best result when using the javac compiler option -Xstdout:

tasks.withType(JavaCompile){
 def myLogPath = file("$project.buildDir/reports/compile")
 doFirst {
  myLogPath.getParentFile().mkdir()
  myLogPath.mkdir()
 }
 options.compilerArgs = ["-Xlint","-Xlint:-serial","-Xmaxwarns","-1","-Xstdout",myLogPath.getPath() + "/" + name + ".log"]
}

This resulted in an error message “invalid flag: -Xstdout” with a stack trace:

FAILURE: Build failed with an exception.
  * What went wrong:
Execution failed for task ':share:compileJava'.
> invalid flag: -Xstdout
  * Try:
Run with --info or --debug option to get more log output.
  * Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':share:compileJava'.
 at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:72)
 at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:49)
 (...)
Caused by: java.lang.IllegalArgumentException: invalid flag: -Xstdout
 at com.sun.tools.javac.api.JavacTool.processOptions(JavacTool.java:231)
 at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:199)
 at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:68)
 at org.gradle.api.internal.tasks.compile.jdk6.Jdk6JavaCompiler.createCompileTask(Jdk6JavaCompiler.java:57)
 at org.gradle.api.internal.tasks.compile.jdk6.Jdk6JavaCompiler.execute(Jdk6JavaCompiler.java:39)
 at org.gradle.api.internal.tasks.compile.jdk6.Jdk6JavaCompiler.execute(Jdk6JavaCompiler.java:33)
 at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:95)
 at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:48)
 at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:34)
 at org.gradle.api.internal.tasks.compile.DelegatingJavaCompiler.execute(DelegatingJavaCompiler.java:29)
 at org.gradle.api.internal.tasks.compile.DelegatingJavaCompiler.execute(DelegatingJavaCompiler.java:20)
 at org.gradle.api.internal.tasks.compile.IncrementalJavaCompilerSupport.execute(IncrementalJavaCompilerSupport.java:33)
 at org.gradle.api.internal.tasks.compile.IncrementalJavaCompilerSupport.execute(IncrementalJavaCompilerSupport.java:23)
 at org.gradle.api.tasks.compile.Compile.compile(Compile.java:68)
 at org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:216)
 at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:122)
 at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:147)
 at org.gradle.api.tasks.compile.JavaCompile_Decorated.invokeMethod(Unknown Source)
 at org.gradle.util.ReflectionUtil.invoke(ReflectionUtil.groovy:23)
 at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$4.execute(AnnotationProcessingTaskFactory.java:161)
 at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$4.execute(AnnotationProcessingTaskFactory.java:156)
 at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:510)
 at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:499)
 at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:64)
 ... 80 more

Since the javac executable supports the -Xstdout parameter at command line I wonder whether this might be a gradle issue. Javac had similar problems in JDK6 (https://bugs.openjdk.java.net/browse/JDK-6265137 , https://bugs.openjdk.java.net/browse/JDK-6265400) and according to the stack trace the gradle Java Plugin seems to use jdk6 internally.

As a workaround I tried adding a StandardOutputListener

tasks.withType(JavaCompile){
 def myLogPath = file("$project.buildDir/reports/compile")
 // unfortunately -Xstdout does not work in this context so we have to log the console output manually
// options.compilerArgs = ["-Xlint","-Xlint:-serial","-Xmaxwarns","-1","-Xstdout",myLogPath.getPath() + "/" + name + ".log"]
 def myCompilerlog = file(myLogPath.getPath() + "/" + name + ".log")
 def myListener = new StandardOutputListener(){
  void onOutput(CharSequence output) {
   myCompilerlog << output
  }
 }
 doFirst {
  myLogPath.getParentFile().mkdir()
  myLogPath.mkdir()
  myCompilerlog.delete()
  logging.addStandardErrorListener(myListener)
 }
 options.compilerArgs = ["-Xlint","-Xlint:-serial","-Xmaxwarns","-1"]
}

Basically this works, but has drawbacks: * the warnings are still printed to the console, which is not very nice especially in Eclipse * all gradle (non-javac) errors of these tasks are written to the log too * may have cases (nested compile tasks) with duplicate log lines due to multiple Listeners with the same log file

I had a similar use case a while ago and solved it with this snippet: https://gist.github.com/breskeby/11282169

Gradle uses the Java compiler API introduced in JDK6. The compiler API doesn’t support all options that the command line compiler supports, although I have been unable to find any docs on this.