2010-11-29 2 views
1

인 메모리 클래스를 컴파일하는 데 Java 컴파일러 API를 사용하고 있습니다. 즉, 클래스는 바이트 코드 (디스크에 저장된 .classes 파일 없음)로 컴파일 된 다음 바이트 코드를 재구성하여로드됩니다.서로 의존하는 클래스가있는 Java 컴파일러 API

때로는 다른 클래스에 의존하는 클래스를 컴파일해야합니다. 예를 들어 클래스 A를 컴파일 한 다음 클래스 A를 기반으로 클래스 B를 컴파일합니다.

이 문제를 해결하기 위해 컴파일러 API의 getTask 메서드에서 필요한 컴파일 단위로 클래스 A와 클래스 B를 모두 전달합니다.

그러나 이미 컴파일 된 클래스 A를 다시 컴파일하므로이 솔루션이 마음에 들지 않습니다.

이 문제를 해결할 방법이 있습니까?

편집 :이 링크를 통해 해결책을 발견 http://www.ibm.com/developerworks/java/library/j-jcomp/index.html 먼저 별도로 A 급을 컴파일 할 이유 명백한 문제로 연결

+0

죄송합니다. 속도가 느려지지만 게시 된 링크가 어떻게 문제를 해결하는지 알 수 없습니다. 나도 똑같은 문제를 겪었다. 클래스를 따로 컴파일 할 수 있다면 내 API가 훨씬 더 깔끔하고 관리하기 쉬워진다. 당신이 대답으로 해결책을 게시 할 수 있다면 나는 그것을 고맙게 생각할 것이다. :) – stevevls

+1

실제로, 나는 이것을 해결했습니다. 그래서 나는 후손을 위해 대답을 게시했습니다. 큰 질문에 감사드립니다! – stevevls

답변

1

. 한 번에 모든 것을 컴파일하지 않는 이유는 무엇입니까?

+0

나는 그 요점을 놓치고 있다고 생각합니다. 예를 게시했습니다. 솔루션은 실제로 확장 가능하거나 모듈식이 아닙니다. – halfwarp

+0

@halfwarp : 요점을 놓치면 정보가 충분하지 않다는 것을 나타내는 것일 수 있습니다. 당신은 당신이 달성하고자하는 것을 설명하지 않았으며, 당신이 필요한 확장 성이나 모듈성을 설명하지 못했습니다. –

0

파일 및 (메모리 내에서) 컴파일 된 바이트 코드의 수정 된 시간을 어떻게 유지합니까?

0

두 클래스를 모두 컴파일하지 않아도된다고 생각하지 않습니다. 사실, 둘 다 컴파일하지 않으면 바이너리 호환성 문제 또는 잘못된 인라인 상수 문제로 끝날 가능성이 있습니다.

이것은 본질적으로 명령 줄에서 하나의 클래스를 컴파일하고 다른 클래스는 컴파일하지 않은 경우 얻을 수있는 것과 동일한 문제입니다.

솔직히 말해서, 나는 그런 컴파일을 최적화하는 것에 대해 걱정하지 않을 것입니다. (이 필요 응용 프로그램이 동적으로 하나 개의 클래스와 다른되지를 컴파일 할 수 있다면, 그것은 중요한 디자인 문제가 아마도 있습니다.)

2

예,이 같은 당신이 제대로 ForwardingJavaFileManager을 구현할 때 완전히 가능하다. 가장 중요한 두 가지 방법은 inferBinaryName()list()입니다. 이 두 가지를 올바르게 설정하면 컴파일러는 이전에 컴파일 한 클래스를 확인할 수 있습니다.

inferBinaryName() 클래스 'simple name을 반환해야합니다 (예를 들어, com.test.Test에 대한 추정 바이너리 명 그냥 Test 것)을. 내가 끝에서 "된 .java"을 박리하는거야

@Override 
public String inferBinaryName(Location location, JavaFileObject javaFileObject) { 

    if(location == StandardLocation.CLASS_PATH && javaFileObject instanceof InAppJavaFileObject) { 
     return StringUtils.substringBeforeLast(javaFileObject.getName(), ".java"); 
    } 

    return super.inferBinaryName(location, javaFileObject); 
} 

참고 : 여기에 (JavaFileObject 내 서브 클래스가 InAppJavaFileObject라고합니다) 내 구현입니다. JavaFileObject을 만들 때 파일 이름은 ".java"로 끝나야하지만 나중에 접미사를 제거하지 않으면 컴파일러에서 클래스를 찾지 못합니다.

list()은 좀 더 복잡합니다. 위임 파일 관리자와 잘 조심해야하기 때문입니다. 내 구현에서 나는 반복 할 수 JavaFileObject의 내 서브 클래스에 정규화 된 클래스 이름의 맵을 유지 : 당신이 제대로 구현하는 방법이 있으면

@Override 
public Iterable<JavaFileObject> list(Location action, String pkg, Set<JavaFileObject.Kind> kind, boolean recurse) throws IOException { 

    Iterable<JavaFileObject> superFiles = super.list(action, pkg, kind, recurse); 

    // see if there's anything in our cache that matches the criteria. 
    if(action == StandardLocation.CLASS_PATH && (kind.contains(JavaFileObject.Kind.CLASS) || kind.contains(JavaFileObject.Kind.SOURCE))) { 

     List<JavaFileObject> ourFiles = new ArrayList<JavaFileObject>(); 
     for(Map.Entry<String,InAppJavaFileObject> entry : files.entrySet()) { 
      String className = entry.getKey(); 
      if(className.startsWith(pkg) && ("".equals(pkg) || pkg.equals(className.substring(0, className.lastIndexOf('.'))))) { 
       ourFiles.add(entry.getValue()); 
      } 
     } 

     if(ourFiles.size() > 0) { 
      for(JavaFileObject javaFileObject : superFiles) { 
       ourFiles.add(javaFileObject); 
      } 

      return ourFiles; 
     } 
    } 

    // nothing found in our hash map that matches the criteria... return 
    // whatever super came up with. 
    return superFiles; 
} 

, 나머지는 작동합니다. 즐겨!

+0

유일한주의 사항은 여기 (예 : "InAppJavaFileObject"에서 사용하는)의 사용자 정의 JavaFileObject에서 openOutputStream()을 구현 한 경우 openOutputStream()을 구현하여 그 스트림에 저장된 모든 바이트를 반환해야한다는 것입니다. 컴파일 중 클래스 데이터. 그러나 그것은 나를 위해 완벽하게 일했습니다. 감사합니다! – Carrotman42