2012-06-01 66 views
4

我目前正在创建一个系统,允许用户编译一个或多个项目。我一直在做一些研究,并决定使用JavaCompilerAPI来做到这一点。我一直在玩它,并设法得到单个java文件编译和单个java文件编译列表。使用JavaFileManager编译项目

我无法做的是得到一个单独的java项目编译,更不用说一组了。我读了一些地方,你可以使用JavaFileManager来做到这一点,我已经读了一下,但我无法找到任何这样的例子,所以我卡住了。

这是我迄今所做的:

public List doCompilation(String sourceCode, String locationOfFile) { 
    List<String> compile = new ArrayList<>(); 

    SimpleJavaFileObject fileObject = new DynamicJavaSourceCodeObject(locationOfFile, sourceCode); 
    JavaFileObject javaFileObjects[] = new JavaFileObject[]{fileObject}; 

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 

    StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, Locale.getDefault(), null); 

    Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(javaFileObjects); 

    String[] compileOptions = new String[]{"-d", "C:/projects/Compiler/TempBINfolder/bin"}; 
    Iterable<String> compilationOptions = Arrays.asList(compileOptions); 

    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 

    CompilationTask compilerTask = compiler.getTask(null, stdFileManager, diagnostics, compilationOptions, null, compilationUnits); 

    boolean status = compilerTask.call(); 

    if (!status) {//If compilation error occurs 
     // Iterate through each compilation problem and print it 
     for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { 
      compile.add(diagnostic.getKind().toString()+" on line "+ diagnostic.getLineNumber() +"\nIn file: \n"+ diagnostic.toString()+"\n\n"); 
     } 
    } 
    try { 
     stdFileManager.close();//Close the file manager 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    return compile; 
} 

是否有人知道如何做到这一点?

+0

“java project”是什么意思?它与一组java文件(每个文件可以单独编译)有什么不同?你在编译一个“项目”时遇到了什么问题? – Attila

+0

当我说java项目时,我的意思是一组特定目录内的java文件。我不我可以单独编译它们,但我现在的方式是所有文件都在JList中,用户可以选择他们希望编译的文件,我想要做的就是添加项目文件夹(所有带有文件夹的java文件)到JTree,然后使用项目的根节点编译单个项目,就像在Eclipse中编译完整的项目一样,单击包屏幕中的项目并编译,然后编译所有Java文件文件夹 – newSpringer

+0

我遇到的问题是,我收到一个错误,说'找不到符号',并指出您正在使用的方法,即使在eclipse中执行文件编译找到的类,并为您的类的导入语句使用的方法也存在,它说我找不到类 – newSpringer

回答

3
  • 尝试使用shrinkwrap,这是非常容易使用...
+0

只是在这里阅读关于shrinkwrap,看起来很简单,足以使用好。你是否建议将每个项目的所有文件移动到一个新的ShrinkWrap.create(JavaArchive.class,“archive.jar”)中,然后编译jar文件呢? – newSpringer

1

你可以枚举文件(及子目录,如果需要的话)指定的项目目录下并编译它们一个接一个你现在的做法。

1

您需要将输出目录包含在编译器类路径中。请注意,我如何在以下类路径中包含targetDirectory

/** 
* Compiles Java source-code. 
* <p/> 
* @author Gili Tzabari 
*/ 
public final class JavaCompiler 
{ 
    private List<Path> sourcePath = new ArrayList<>(); 
    private List<Path> classPath = new ArrayList<>(); 
    private final Set<DebugType> debugOptions = new HashSet<>(Arrays.asList(DebugType.LINES, 
     DebugType.SOURCE, DebugType.VARIABLES)); 

    /** 
    * Sets the compiler classpath. 
    * <p/> 
    * @param sourcePath the paths to search for the source format of dependent classes 
    * @throws NullPointerException if sourcePath is null 
    * @throws IllegalArgumentException if sourcePath refers to a non-existent path or a non-directory 
    * @return the JavaCompiler 
    */ 
    public JavaCompiler sourcePath(List<Path> sourcePath) 
    { 
     Preconditions.checkNotNull(sourcePath, "sourcePath may not be null"); 
     for (Path path: sourcePath) 
     { 
      if (!Files.exists(path)) 
      { 
       throw new IllegalArgumentException("sourcePath refers to non-existant path: " + path. 
        toAbsolutePath()); 
      } 
      if (!Files.isDirectory(path)) 
      { 
       throw new IllegalArgumentException("sourcePath refers to a non-directory: " + path. 
        toAbsolutePath()); 
      } 
     } 

     this.sourcePath = ImmutableList.copyOf(sourcePath); 
     return this; 
    } 

    /** 
    * Sets the compiler classpath. 
    * <p/> 
    * @param classPath the paths to search for the compiled format of dependent classes 
    * @throws NullPointerException if classPath is null 
    * @throws IllegalArgumentException if classPath refers to a non-existent path 
    * @return the JavaCompiler 
    */ 
    public JavaCompiler classPath(List<Path> classPath) 
    { 
     Preconditions.checkNotNull(classPath, "classPath may not be null"); 
     for (Path path: classPath) 
     { 
      if (!Files.exists(path)) 
      { 
       throw new IllegalArgumentException("classPath refers to non-existant path: " + path. 
        toAbsolutePath()); 
      } 
     } 

     this.classPath = ImmutableList.copyOf(classPath); 
     return this; 
    } 

    /** 
    * Indicates the kind of debugging information the generated files should contain. 
    * <p/> 
    * @param debugOptions the kind of debugging information the generated files should contain. By 
    * default all debugging information is generated. 
    * @return the JavaCompiler object 
    */ 
    public JavaCompiler debug(DebugType... debugOptions) 
    { 
     this.debugOptions.clear(); 
     this.debugOptions.addAll(Arrays.asList(debugOptions)); 
     return this; 
    } 

    /** 
    * Compiles the source code. 
    * <p/> 
    * @param sourceFiles the source files to compile 
    * @param targetDirectory the directory to compile into. This path included in the compiler 
    * classpath. 
    * @throws IllegalArgumentException if sourceFiles, targetDirectory are null; or if sourceFiles 
    * refers to a non-existent file or a non-file; or if targetDirectory is not a directory 
    * @throws CompilationException if the operation fails 
    */ 
    public void run(final Collection<Path> sourceFiles, final Path targetDirectory) 
     throws IllegalArgumentException, CompilationException 
    { 
     if (sourceFiles == null) 
      throw new IllegalArgumentException("sourceFiles may not be null"); 
     if (sourceFiles.isEmpty()) 
      return; 
     for (Path file: sourceFiles) 
     { 
      if (!Files.exists(file)) 
      { 
       throw new IllegalArgumentException("sourceFiles refers to a non-existant file: " 
        + file.toAbsolutePath()); 
      } 
      if (!Files.isRegularFile(file)) 
      { 
       throw new IllegalArgumentException("sourceFiles refers to a non-file: " 
        + file.toAbsolutePath()); 
      } 
     } 
     if (targetDirectory == null) 
      throw new IllegalArgumentException("targetDirectory may not be null"); 
     if (!Files.exists(targetDirectory)) 
     { 
      throw new IllegalArgumentException("targetDirectory must exist: " + targetDirectory. 
       toAbsolutePath()); 
     } 
     if (!Files.isDirectory(targetDirectory)) 
     { 
      throw new IllegalArgumentException("targetDirectory must be a directory: " + targetDirectory. 
       toAbsolutePath()); 
     } 
     Set<Path> uniqueSourceFiles = ImmutableSet.copyOf(sourceFiles); 
     Set<Path> uniqueSourcePath = ImmutableSet.copyOf(sourcePath); 
     final javax.tools.JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
     if (compiler == null) 
     { 
      throw new AssertionError("javax.tools.JavaCompiler is not available. Is tools.jar missing " 
       + "from the classpath?"); 
     } 
     final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); 
     final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, 
      null); 

     Iterable<? extends JavaFileObject> compilationUnits; 
     try 
     { 
      Set<File> modifiedFiles = getModifiedFiles(uniqueSourceFiles, uniqueSourcePath, 
       targetDirectory, new HashSet<Path>()); 
      if (modifiedFiles.isEmpty()) 
       return; 
      compilationUnits = fileManager.getJavaFileObjectsFromFiles(modifiedFiles); 
     } 
     catch (IOException e) 
     { 
      throw new CompilationException(e); 
     } 
     final List<Path> effectiveClasspath = new ArrayList<>(); 
     effectiveClasspath.add(targetDirectory); 
     effectiveClasspath.addAll(classPath); 
     final List<String> options = new ArrayList<>(); 
     options.add("-cp"); 
     options.add(Joiner.on(File.pathSeparatorChar).join(effectiveClasspath)); 

     final StringBuilder debugLine = new StringBuilder("-g:"); 
     for (DebugType type: debugOptions) 
     { 
      switch (type) 
      { 
       case LINES: 
       { 
        debugLine.append("lines,"); 
        break; 
       } 
       case SOURCE: 
       { 
        debugLine.append("source,"); 
        break; 
       } 
       case VARIABLES: 
       { 
        debugLine.append("vars,"); 
        break; 
       } 
       default: 
        throw new AssertionError(type); 
      } 
     } 
     if (!debugOptions.isEmpty()) 
     { 
      debugLine.deleteCharAt(debugLine.length() - ",".length()); 
      options.add(debugLine.toString()); 
     } 

     if (!uniqueSourcePath.isEmpty()) 
     { 
      options.add("-sourcepath"); 
      options.add(Joiner.on(File.pathSeparatorChar).join(uniqueSourcePath)); 
     } 
     options.add("-s"); 
     options.add(targetDirectory.toString()); 
     options.add("-d"); 
     options.add(targetDirectory.toString()); 
     final Writer output = null; 
     final CompilationTask task = compiler.getTask(output, fileManager, diagnostics, options, null, 
      compilationUnits); 
     final boolean result = task.call(); 
     try 
     { 
      printDiagnostics(diagnostics, options, sourceFiles); 
     } 
     catch (IOException e) 
     { 
      throw new BuildException(e); 
     } 
     if (!result) 
      throw new CompilationException(); 
     try 
     { 
      fileManager.close(); 
     } 
     catch (IOException e) 
     { 
      throw new BuildException(e); 
     } 
    } 

    /** 
    * Returns the java source-code file corresponding to a class name. 
    * <p/> 
    * @param className the fully-qualified class name to look up 
    * @param sourcePath the source-code search path 
    * @return null if no match was found 
    */ 
    private static File getJavaSource(String className, Set<File> sourcePath) 
    { 
     // TODO: check for class files instead of source 
     for (File path: sourcePath) 
     { 
      File result = classNameToFile(path, className); 
      if (!result.exists()) 
       continue; 
      return result; 
     } 
     return null; 
    } 

    /** 
    * Converts a class name to its source-code file. 
    * <p/> 
    * @param sourcePath the source-code search path 
    * @param className the fully-qualified class name 
    * @return the source-code file 
    */ 
    private static File classNameToFile(File sourcePath, String className) 
    { 
     return new File(sourcePath, className.replace(".", "/") + ".java"); 
    } 

    /** 
    * Displays any compilation errors. 
    * <p/> 
    * @param diagnostics the compiler diagnostics 
    * @param options the command-line options passed to the compiler 
    * @param sourceFiles the source files to compile 
    * @throws IOException if an I/O error occurs 
    */ 
    private void printDiagnostics(final DiagnosticCollector<JavaFileObject> diagnostics, 
     final List<String> options, final Collection<Path> sourceFiles) throws IOException 
    { 
     Logger log = LoggerFactory.getLogger(JavaCompiler.class.getName() + ".stderr"); 
     int errors = 0; 
     int warnings = 0; 
     boolean firstTime = true; 
     for (Diagnostic<? extends JavaFileObject> diagnostic: diagnostics.getDiagnostics()) 
     { 
      if (firstTime) 
      { 
       firstTime = false; 
       StringBuilder message = new StringBuilder(); 
       message.append("Invoking: javac "); 
       for (String token: options) 
        message.append(token).append(" "); 
       message.append(Joiner.on(" ").join(sourceFiles)); 
       log.debug(message.toString()); 
      } 
      JavaFileObject source = diagnostic.getSource(); 
      if (source == null) 
       log.error(diagnostic.getMessage(null)); 
      else 
      { 
       StringBuilder message = new StringBuilder(); 
       message.append(source.getName()); 
       if (diagnostic.getLineNumber() != Diagnostic.NOPOS) 
        message.append(":").append(diagnostic.getLineNumber()); 
       message.append(": ").append(diagnostic.getMessage(null)); 
       log.error(message.toString()); 
       try (BufferedReader reader = 
         new BufferedReader(new InputStreamReader(source.openInputStream()))) 
       { 
        String line = null; 
        for (long lineNumber = 0, size = diagnostic.getLineNumber(); lineNumber < size; 
         ++lineNumber) 
        { 
         line = reader.readLine(); 
         if (line == null) 
          break; 
        } 
        if (line != null) 
        { 
         log.error(line); 
         message = new StringBuilder(); 
         for (long i = 1, size = diagnostic.getColumnNumber(); i < size; ++i) 
          message.append(" "); 
         message.append("^"); 
         log.error(message.toString()); 
        } 
       } 
      } 
      switch (diagnostic.getKind()) 
      { 
       case ERROR: 
       { 
        ++errors; 
        break; 
       } 
       case NOTE: 
       case OTHER: 
       case WARNING: 
       case MANDATORY_WARNING: 
       { 
        ++warnings; 
        break; 
       } 
       default: 
        throw new AssertionError(diagnostic.getKind()); 
      } 
     } 
     if (errors > 0) 
     { 
      StringBuilder message = new StringBuilder(); 
      message.append(errors).append(" error"); 
      if (errors > 1) 
       message.append("s"); 
      log.error(message.toString()); 
     } 
     if (warnings > 0) 
     { 
      StringBuilder message = new StringBuilder(); 
      message.append(warnings).append(" warning"); 
      if (warnings > 1) 
       message.append("s"); 
      log.warn(message.toString()); 
     } 
    } 

    /** 
    * Returns the source-code files that have been modified. 
    * <p/> 
    * @param sourceFiles the source files to process 
    * @param sourcePath the source file search path 
    * @param targetDirectory the directory to compile into 
    * @param unmodifiedFiles files that are known not to have been modified 
    * @return all changed source-code files that are accepted by the filter 
    * @throws IOException if an I/O error occurs 
    */ 
    private Set<File> getModifiedFiles(final Set<Path> sourceFiles, 
     final Set<Path> sourcePath, final Path targetDirectory, final Set<Path> unmodifiedFiles) 
     throws IOException 
    { 
     // TODO: Right now all files are assumed to have been modified 
     Set<File> result = new HashSet<>(); 
     for (Path path: sourceFiles) 
      result.add(path.toFile()); 
     return result; 
    } 

    /** 
    * Returns the command-line representation of the object. 
    * <p/> 
    * @param sourceFiles the source files to compile 
    * @param targetDirectory the directory to compile into 
    * @param sourcePath the source file search path 
    * @return the command-line representation of the object 
    * @throws IllegalArgumentException if the classpath contains non-file components 
    * @throws IOException if an I/O error occurs 
    */ 
    private List<String> toCommandLine(final Collection<Path> sourceFiles, final Path targetDirectory, 
     final Collection<Path> sourcePath) 
     throws IOException 
    { 
     final List<String> result = Lists.newArrayList("javac"); 
     if (!classPath.isEmpty()) 
     { 
      result.add("-cp"); 
      try 
      { 
       final StringBuilder line = new StringBuilder(); 
       for (final Iterator<Path> i = classPath.iterator(); i.hasNext();) 
       { 
        line.append(i.next().getParent().toString()); 
        if (i.hasNext()) 
         line.append(File.pathSeparatorChar); 
       } 
       result.add(line.toString()); 
      } 
      catch (IllegalArgumentException e) 
      { 
       // Occurs if URL does not refer to a file 
       throw new IllegalStateException(e); 
      } 
     } 
     for (File javaFile: getModifiedFiles(ImmutableSet.copyOf(sourceFiles), 
      ImmutableSet.copyOf(sourcePath), targetDirectory, new HashSet<Path>())) 
     { 
      result.add(javaFile.getPath()); 
     } 
     result.add("-d"); 
     result.add(targetDirectory.getParent().toString()); 
     return result; 
    } 

    @Override 
    public String toString() 
    { 
     return getClass().getName() + "[classPath=" + classPath + "]"; 
    } 

    /** 
    * The type of debugging information that generated files may contain. 
    * <p/> 
    * @author Gili Tzabari 
    */ 
    @SuppressWarnings("PublicInnerClass") 
    public enum DebugType 
    { 
     /** 
     * No debugging information. 
     */ 
     NONE, 
     /** 
     * Line number information. 
     */ 
     LINES, 
     /** 
     * Local variable information. 
     */ 
     VARIABLES, 
     /** 
     * Source file information. 
     */ 
     SOURCE 
    } 
} 
+0

你可以帮我在这里的类路径:https://stackoverflow.com/questions/32945379/programmatically-compile-java-files-and-include-other-jars-to-classpath – Gobliins