JavacTask.generate bug?

Joshua Maurice joshuamaurice at gmail.com
Tue Jun 15 17:52:17 PDT 2010


On Tue, Jun 15, 2010 at 3:18 PM, Jonathan Gibbons <
jonathan.gibbons at oracle.com> wrote:

>
>
> 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> 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
>

Excellent. Thank you. (Which of course begs the question I'm sure you've
been asked numerous times, so I'll just hint at it instead of asking
directly.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20100615/4d62dbfd/attachment.html 


More information about the compiler-dev mailing list