FULL PRODUCT VERSION : java version "1.6.0_20" Java(TM) SE Runtime Environment (build 1.6.0_20-b02) Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode) ADDITIONAL OS VERSION INFORMATION : Linux <hostname> 2.6.24-gg804011-generic #1 SMP Tue Mar 30 18:11:30 UTC 2010 x86_64 GNU/Linux A DESCRIPTION OF THE PROBLEM : JCCompilationUnit.getImports does not report all imports if there is an extra semicolon after one of the import statements. getImports stops after the first non-import statement. Empty statement makes it think there would be no other import statements to follow. $ cat A.java import java.util.List;; // note an extra semicolon here import java.util.ArrayList; public class A {} $ cat Driver.java import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.ImportTree; import com.sun.source.util.JavacTask; import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; public class Driver { public static void main(String[] args) throws Exception { if (args.length < 1) return; JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); JavacTask task = (JavacTask) compiler.getTask(null, fileManager, null, null, null, fileManager.getJavaFileObjects(args[0])); CompilationUnitTree tree = task.parse().iterator().next(); for (ImportTree importTree : tree.getImports()) { System.out.println(importTree); } } } $ javac A.java accepts the source file as valid $ javac -cp /java/lib/tools.jar Driver.java $ java -cp /java/lib/tools.jar:. Driver A.java produces only the first import statement STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : $ javac -cp /java/lib/tools.jar Driver.java $ java -cp /java/lib/tools.jar:. Driver A.java EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - import java.util.List; import java.util.ArrayList; ACTUAL - import java.util.List; REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- $ cat A.java import java.util.List;; // note an extra semicolon here import java.util.ArrayList; public class A {} $ cat Driver.java import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.ImportTree; import com.sun.source.util.JavacTask; import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; public class Driver { public static void main(String[] args) throws Exception { if (args.length < 1) return; JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); JavacTask task = (JavacTask) compiler.getTask(null, fileManager, null, null, null, fileManager.getJavaFileObjects(args[0])); CompilationUnitTree tree = task.parse().iterator().next(); for (ImportTree importTree : tree.getImports()) { System.out.println(importTree); } } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : My current workaround is to cast CompilationUnitTree to JCTree.JCCompilationUnit and filter the defs myself. The getImports could be fixed for example by adding if (tree.getTag() == SKIP) continue; public List<JCImport> getImports() { ListBuffer<JCImport> imports = new ListBuffer<JCImport>(); for (JCTree tree : defs) { if (tree.getTag() == SKIP) continue; else if (tree.getTag() == IMPORT) imports.append((JCImport)tree); else break; } return imports.toList(); }
|