2010-01-08 33 views
6

Biên dịch động của tôi trong Java 6 đang hoạt động hoàn hảo. Tuy nhiên, tôi muốn thay đổi đường dẫn đầu ra. Tôi đã thử rất nhiều thứ (tôi sẽ tha cho bạn) vô ích. Dù sao, đây là mã hoạt độngChỉ định Đường dẫn Đầu ra cho Biên dịch Động

String[] filesToCompile = { "testFiles/Something.java" }; 
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); 
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(filesToCompile); 
CompilationTask task = compiler.getTask(null, fileManager, null,null, null, compilationUnits); 
System.out.println("Good? " + task.call()); 

Nhưng đầu ra đi tới thư mục nguồn, không phải là thứ tôi muốn.

Tôi nghi ngờ câu trả lời có thể nằm trong số compiler.getTask nhưng API không rõ ràng về ý nghĩa của một số thông số. Hoặc có lẽ một cái gì đó với fileManager. Tôi đã thử

fileManager.setLocation(StandardLocation.locationFor("testFiles2"), null); 

nhưng một lần nữa, đoán có lẽ không phải là một ý hay.

Cảm ơn!

Edit: tôi đã cố gắng lựa chọn sử dụng, quá, như thế này (xin lỗi nếu có một cách nhỏ gọn hơn):

final List<String> optionsList = new ArrayList<String>(); 
    optionsList.add("-d what"); 
    Iterable<String> options = new Iterable<String>() {   
     public Iterator<String> iterator() { 
      return optionsList.iterator(); 
     } 
    }; 

và sau đó đi qua các tùy chọn để getTask, nhưng thông báo lỗi là "không hợp lệ Gắn cờ. "

+0

+1 để làm cho tôi nhận thức được rằng có một điều như biên soạn động bây giờ! –

+0

Luôn luôn có, bây giờ nó được xây dựng trong! –

+0

Câu trả lời của tôi đã được cập nhật. –

Trả lời

5

Mã trong bài viết đầu tiên sẽ làm việc, nhưng get lỗi của sau ném:

java.lang.IllegalArgumentException: invalid flag: -d folder 

Điều này là do bằng cách đi qua "-d folder" làm cho trình phân tích cú pháp nghĩ rằng nó phân tích cú pháp một tùy chọn. Các tùy chọn phải được tách ra như "-d", "folder".

dụ làm việc sau:

JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 
StandardJavaFileManager sjfm = javaCompiler.getStandardFileManager(null, null, null); 

String[] options = new String[] { "-d", "output" }; 
File[] javaFiles = new File[] { new File("src/gima/apps/flip/TestClass.java") }; 

CompilationTask compilationTask = javaCompiler.getTask(null, null, null, 
     Arrays.asList(options), 
     null, 
     sjfm.getJavaFileObjects(javaFiles) 
); 
compilationTask.call(); 
+0

Còn các đường dẫn như "c: \\ foo bar \\ foo" hoặc "c:/foo bar/foo" thì sao? Các khoảng trống hoặc dấu gạch chéo có thể được phân tích cú pháp chính xác không? – Gobliins

+0

Tôi không biết, nhưng tôi đoán rằng không có thoát là cần thiết vì các đối số hiện đang được truyền chính xác (và vì bản chất của vấn đề ban đầu chính xác là các thông số không được phân tách một cách tách biệt). Hãy thử và báo cáo lại? – Gima

4

Tôi có 0 kinh nghiệm với các công cụ biên dịch động Java 6. Nhưng không ai khác đã trả lời :)

Nhiệm vụ biên dịch nhận đối tượng FileManager. Nếu bạn sử dụng tiêu chuẩn, thì các lớp được tạo trong cây thư mục nguồn. Những gì bạn có thể làm là cung cấp lớp con FileManager của riêng bạn với phương thức getFileForOutput đã ghi đè. Mô tả API của getFileForOutput cho biết rằng điều này sẽ ảnh hưởng đến nơi tệp đầu ra (= lớp) của bạn sẽ đi.

Cập nhật

Làm thế nào để treo lên các nhà quản lý tập tin

ForwardingJavaFileManager, ForwardingFileObject, và ForwardingJavaFileObject subclassing là không có sẵn cho trọng hành vi của một quản lý tập tin tiêu chuẩn vì nó được tạo ra bằng cách gọi một phương thức trên trình biên dịch, không phải bằng cách gọi một hàm tạo. Thay vào đó chuyển tiếp (hoặc ủy quyền) nên được sử dụng. Các lớp này giúp dễ dàng chuyển tiếp hầu hết các cuộc gọi đến một trình quản lý tệp hoặc đối tượng tệp đã cho trong khi cho phép tùy chỉnh hành vi. Ví dụ, hãy xem xét làm thế nào để ghi lại tất cả các cuộc gọi đến JavaFileManager.flush():

final Logger logger = ...; 
    Iterable<? extends JavaFileObject> compilationUnits = ...; 
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
    StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, null, null); 
    JavaFileManager fileManager = new ForwardingJavaFileManager(stdFileManager) { 
     public void flush() { 
      logger.entering(StandardJavaFileManager.class.getName(), "flush"); 
      super.flush(); 
      logger.exiting(StandardJavaFileManager.class.getName(), "flush"); 
     } 
    }; 
    compiler.getTask(null, fileManager, null, null, null, compilationUnits).call(); 

Cập nhật 2

Tôi đọc lên về việc lập năng động và xây dựng ứng dụng của riêng tôi để làm điều này. Mã này chứa một chút quá nhiều lễ (nghĩa là nó có thể được đơn giản hóa) nhưng nó hoạt động!

package yar; 

import javax.tools.JavaCompiler; 
import javax.tools.ToolProvider; 

public class DynamicCompiler { 

    JavaCompiler compiler; 

    public DynamicCompiler() { 
     this.compiler = ToolProvider.getSystemJavaCompiler(); 
     if (this.compiler == null) { 
     throw new NullPointerException("Cannot provide system compiler."); 
     } 
    } 

    public void compile() { 
     this.compiler.run(null, System.out, System.err, 
      "-d", "testFiles2", 
      "testFiles/Hello1.java", "testFiles/Hello2.java"); 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     try { 
     DynamicCompiler dc = new DynamicCompiler(); 
     dc.compile(); 
     } catch (Exception e) { 
     System.err.println(e.getMessage()); 
     } 
    } 

} 

Tôi không chắc chắn làm cách nào để mã này hoạt động với danh sách tệp Java được tạo động; Tôi có thể chỉ cần làm compiler.run riêng cho từng tệp nguồn.

+0

Điều này có thể đúng, nhưng tiếc là getJavaFileObjects chỉ trên StandardJavaFileManager .... Tôi sẽ xem những gì có thể được thực hiện anyway. Nếu đây là Ruby, câu trả lời của bạn sẽ đủ để khỉ vá và được thực hiện :) –

+0

Trong Java, cách thức để đi là subclassing ... 'ForwardingJavaFileManager' thực hiện' StandardJavaFileManager' và đó là cái bạn muốn sử dụng. –

+0

Trong thực tế, nó có một hàm tạo, bạn có thể quấn quanh FileManager mà bạn nhận được từ 'trình biên dịch'. Bạn sẽ muốn làm cho constructor đó công khai trong lớp dẫn xuất của bạn, tất nhiên. –

8

Tôi đã đối mặt với cùng một vấn đề này ngay hôm nay.

Câu trả lời (bằng cách sử dụng getTask phương pháp thông thường thay vì `chạy) là để xác định thư mục đầu ra trong FileManager:

fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(outputDir)); 

Và đó là nó !! :)

Tài liệu có chút sai lệch, ý tôi là, một mẫu có thể rất tiện dụng. Nhưng cuối cùng nó đã đưa tôi đến đó.

EDIT

Đây là một mẫu chạy:

// write the test class 
    File sourceFile = new File("First.java"); 
    FileWriter writer = new FileWriter(sourceFile); 

    writer.write(
      "package load.test;\n" + 
      "public class First{}" 
    ); 
    writer.close(); 

    // Get the java compiler for this platform 
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(
      null, 
      null, 
      null); 

    //--   H E R E --// 
    // Specify where to put the genereted .class files 
    fileManager.setLocation(StandardLocation.CLASS_OUTPUT, 
          Arrays.asList(new File("/tmp"))); 
    // Compile the file 
    compiler 
     .getTask(null, 
       fileManager, 
       null, 
       null, 
       null, 
       fileManager.getJavaFileObjectsFromFiles(Arrays.asList(sourceFile))) 
     .call(); 
    fileManager.close(); 

    // delete the file 
    sourceFile.deleteOnExit(); 
+0

Đã lâu rồi tôi mới xem xét vấn đề này. Vì vậy, bạn đang nói rằng câu trả lời của bạn thực sự giải quyết toàn bộ vấn đề? –

+0

Yeap !!!, khá nhiều. Tôi sẽ cập nhật câu trả lời với một mẫu – OscarRyz

+0

Hoạt động tốt - giống như sử dụng "-d" trong tham số tùy chọn getTask(), nhưng sạch hơn. – Atorian

Các vấn đề liên quan