JavacTask.generate bug?
Jonathan Gibbons
jonathan.gibbons at oracle.com
Tue Jun 15 15:18:32 PDT 2010
On 05/27/2010 04:56 PM, Jonathan Gibbons wrote:
> On 05/27/2010 04:49 PM, Joshua Maurice wrote:
>> On Thu, May 27, 2010 at 4:44 PM, Jonathan Gibbons
>> <jonathan.gibbons at oracle.com <mailto:jonathan.gibbons at oracle.com>> wrote:
>>
>> I don't know of any bugs in this area. You could try setting
>> -XDverboseCompilePolicy which is an undocumented option to trace
>> the compiler's operation.
>>
>> javac will stop generating files if an error is detected, but I
>> don't see any error output coming from your test.
>>
>> I'll not be able to look at this further until next week at the
>> earliest. Sorry.
>>
>> -- Jon
>>
>>
>>
>>
>> On 05/27/2010 03:48 PM, Joshua Maurice wrote:
>>
>> Silly question: is there a known bug in JavacTask.generate? I
>> did a quick google search of the bug archives, and it did not
>> come up. It seems that depending on the order of
>> JavaFileObjects used to create the JavacTask, the fifth
>> argument to javax.tools.JavaCompiler.getTask, it skips or
>> does not skip generating files. Here's my stand alone example:
>>
>>
>> import java.io.BufferedWriter;
>> import java.io.File;
>> import java.io.FileWriter;
>> import java.io.IOException;
>> import java.io.StringWriter;
>> import java.util.Arrays;
>> import java.util.Iterator;
>> import java.util.List;
>>
>> import javax.lang.model.element.Element;
>> import javax.tools.DiagnosticCollector;
>> import javax.tools.JavaCompiler;
>> import javax.tools.JavaFileObject;
>> import javax.tools.StandardJavaFileManager;
>> import javax.tools.ToolProvider;
>>
>> import com.sun.source.tree.CompilationUnitTree;
>> import com.sun.source.util.JavacTask;
>>
>> public class Foo {
>> public static void main(String[] args) throws IOException {
>> final File srcRoot = new File("C:/foo/src");
>> final File tgtRoot = new File("C:/foo/tgt");
>> writeToFile(new File(srcRoot + "/T3.java"), "public
>> class T3 { public static final int C = 1; }\n");
>> writeToFile(new File(srcRoot + "/T2.java"), "public
>> class T2 extends T3 {}\n");
>> writeToFile(new File(srcRoot + "/T1.java"), "public
>> class T1 extends T2 {}\n");
>> writeToFile(new File(srcRoot + "/Test.java"), "public
>> class Test { public static final int D = T1.C; }\n");
>>
>> final List<File> sourceFiles = Arrays.asList(new File[]{
>> new File(srcRoot, "/T2.java"),
>> new File(srcRoot, "/T1.java"),
>> new File(srcRoot, "/T3.java"),
>> new File(srcRoot, "/Test.java"),
>> });
>>
>> final StringWriter compilerOutputStream = new
>> StringWriter();
>>
>> final List<String> compileOptions = Arrays.asList(new
>> String[]{"-g", "-source", "1.6", "-Xlint:unchecked", "-d",
>> tgtRoot.toString()});
>> final JavaCompiler compiler =
>> ToolProvider.getSystemJavaCompiler();
>> DiagnosticCollector<JavaFileObject>
>> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
>> final StandardJavaFileManager fileManager =
>> compiler.getStandardFileManager(diagnosticCollector, null, null);
>> final Iterable<? extends JavaFileObject>
>> sourceFileObjects =
>> fileManager.getJavaFileObjectsFromFiles(sourceFiles);
>> System.out.println("1- javac given java source
>> JavaFileObjects " + sourceFileObjects);
>> final JavaCompiler.CompilationTask task =
>> compiler.getTask(compilerOutputStream, fileManager, null,
>> compileOptions, null, sourceFileObjects);
>> JavacTask javacTask = (JavacTask)task;
>>
>> if (false) { //TOGGLE THIS
>>
>> final Iterable<? extends CompilationUnitTree>
>> parsedTrees = javacTask.parse();
>> final Iterable<? extends Element> analyzedTrees =
>> javacTask.analyze();
>> final Iterable<? extends JavaFileObject>
>> generatedFiles = javacTask.generate();
>>
>> System.out.println("2- " + size(parsedTrees) + " "
>> + size(analyzedTrees) + " " + size(generatedFiles));
>>
>> System.out.print("3-");
>> for (JavaFileObject f : generatedFiles)
>> System.out.print(" " + f);
>> System.out.println("");
>> } else {
>> final boolean javacCallReturn = javacTask.call();
>> System.out.println("4- " + javacCallReturn);
>> }
>>
>> System.out.print("5-");
>> for (File f : tgtRoot.listFiles())
>> System.out.print(" " + f);
>> System.out.println("");
>>
>> System.out.println("----");
>> System.out.println(compilerOutputStream.toString());
>> }
>>
>> private static <E> int size(Iterable<E> x) {
>> int n = 0;
>> for (Iterator<E> iter = x.iterator(); iter.hasNext(); ++n)
>> iter.next();
>> return n;
>> }
>>
>> private static void writeToFile(File f, String str) throws
>> IOException {
>> f.getParentFile().mkdirs();
>> BufferedWriter fout = new BufferedWriter(new
>> FileWriter(f));
>> try {
>> fout.write(str);
>> fout.flush();
>> } finally {
>> fout.close();
>> }
>> }
>> }
>>
>>
>> When TOGGLE THIS is true, it calls "generate" on the
>> JavacTask. The output on some execution on my computer is:
>> 1- javac given java source JavaFileObjects
>> [C:\foo\src\T2.java, C:\foo\src\T1.java, C:\foo\src\T3.java,
>> C:\foo\src\Test.java]
>> 2- 4 4 2
>> 3- C:\foo\tgt\T3.class C:\foo\tgt\Test.class
>> 5- C:\foo\tgt\T1.class C:\foo\tgt\T2.class
>> C:\foo\tgt\T3.class C:\foo\tgt\Test.class
>> ----
>>
>> When TOGGLE THIS is false, it calls "call" on the JavacTask.
>> The output on some execution on my computer is:
>> 1- javac given java source JavaFileObjects
>> [C:\foo\src\T2.java, C:\foo\src\T1.java, C:\foo\src\T3.java,
>> C:\foo\src\Test.java]
>> 4- true
>> 5- C:\foo\tgt\T1.class C:\foo\tgt\T2.class
>> C:\foo\tgt\T3.class C:\foo\tgt\Test.class
>> ----
>>
>> When the order of file objects given to the JavacTask is
>> altered, it starts to work. Ex:
>> final List<File> sourceFiles = Arrays.asList(new File[]{
>> new File(srcRoot, "/Test.java"),
>> new File(srcRoot, "/T3.java"),
>> new File(srcRoot, "/T2.java"),
>> new File(srcRoot, "/T1.java"),
>> });
>> gives output:
>> 1- javac given java source JavaFileObjects
>> [C:\foo\src\Test.java, C:\foo\src\T3.java,
>> C:\foo\src\T2.java, C:\foo\src\T1.java]
>> 2- 4 4 4
>> 3- C:\foo\tgt\Test.class C:\foo\tgt\T3.class
>> C:\foo\tgt\T2.class C:\foo\tgt\T1.class
>> 5- C:\foo\tgt\T1.class C:\foo\tgt\T2.class
>> C:\foo\tgt\T3.class C:\foo\tgt\Test.class
>> ----
>>
>> So, it appears as though I can work around this bug. I just
>> have to create two different JavacTasks for each "javac task"
>> aka "pom.xml", one to do the actual class file generation,
>> done with the member function "call", and a second JavacTask
>> invocation to get the analyzed parse trees to get the used
>> types during compile (which I'm still working on figuring out
>> how to do).
>>
>> Finally:
>> C:\Documents and Settings\jmaurice>javac -version
>> javac 1.6.0_20
>>
>>
>> Using this new undocumented option, under the original code, except
>> with TOGGLE THIS to true, after cleaning out the output folder,
>> execution of the program prints:
>>
>> 1- javac given java source JavaFileObjects [C:\foo\src\T2.java,
>> C:\foo\src\T1.java, C:\foo\src\T3.java, C:\foo\src\Test.java]
>> 2- 4 4 2
>> 3- C:\foo\tgt\T3.class C:\foo\tgt\Test.class
>> 5- C:\foo\tgt\T3.class C:\foo\tgt\Test.class
>> ----
>> [attribute T2]
>> [attribute T3]
>> [attribute T1]
>> [attribute Test]
>> [flow T2]
>> [flow T3]
>> [flow T1]
>> [flow Test]
>> [defer T2]
>> [desugar T3]
>> [defer T1]
>> [desugar Test]
>> [generate code T3]
>> [generate code Test]
>
>
> OK, you got my attention. This needs to be investigated. It looks
> significant that T1 and T2 get deferred, then not generated.
>
> -- Jon
Joshua,
FWIW, I've recreated your issue using JDK 1.6, but your program works
for me, using JDK7, using all 24 orderings of the 4 test files. So it
looks like the bug you encountered has already been fixed in JDK 7.
-- Jon
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20100615/8fcf62a9/attachment.html
More information about the compiler-dev
mailing list