2011-02-17 2 views
0

런타임시 사용자 지정 텍스트 변환기를로드하는 명령 줄 응용 프로그램 (명령 줄 arg를 통해 제공되는 클래스 파일/jar의 경로)에서 작업 중입니다. 기본적으로 나는 그 인수를 가져 와서 URLClassLoader를 만드는 데 사용하고 있습니다. 그런 다음 Transable 인터페이스를 구현하는 URLClassloader에서 사용할 수있는 모든 클래스를 찾아야합니다.Java, 특정 인터페이스를 구현하는 URLClassLoader에서 모든 클래스 가져 오기

지금은이 명령 줄 인수가 클래스 파일이있는 디렉토리가되도록 허용하고 있습니다. 솔루션을 매우 간단하게 만듭니다 (아래 코드). 하지만 솔직히 jar 파일, jar 파일 디렉토리 등으로 인해 솔루션이 마음에 들지 않습니다. 또한 loadClass에 패키지를 포함한 전체 이름이 필요하기 때문에 정의 된 패키지가있는 모든 클래스에서이 작업이 중단됩니다. 누구든지 더 좋은 방법이 있습니까?

File d = new File(path); 
    if(d.isDirectory()) { 
     URL url = d.toURI().toURL(); 
     ClassLoader cl = new URLClassLoader(new URL[]{url}); 

     FilenameFilter filter = new FilenameFilter() { 
      @Override 
      public boolean accept(File dir, String name) { 
       return name.endsWith(".class"); 
      } 
     }; 

     for(File f : d.listFiles(filter)) { 
      String name = f.getName().substring(0, f.getName().indexOf(".")); 
      String key = ""; 
      if(name.endsWith("Translator")) { 
       key = name.substring(0, name.indexOf("Translator")); 
      } 
      else if(name.endsWith("translator")) { 
       key = name.substring(0, name.indexOf("translator")); 
      } 
      else 
       key = name; 

      Class c = cl.loadClass(name); 
      if(Transable.class.isAssignableFrom(c)) { 
       Transable t = (Transable)c.newInstance(); 
       env.registerTranslator(key, t); 
      } 
      else { 
       System.out.println("[ClassLoader] "+c.getCanonicalName()+" will not be loaded. It is not a translator class"); 
      } 
     } 
    } 
    else { 
     throw new Error("NOT IMPLEMENTED"); 
    } 
+0

그냥 jar 파일로 가서 모든 항목을 확인하십시오. – irreputable

답변

3

이 길을 계속 계속 가려면 단지 강제로해야합니다. 내 지식으로는 기본 클래스 로더가 어떻게 든 참조되지 않는 한 클래스를 JVM에로드하지 않습니다. 즉, 클래스의 일부는 클래스를로드하기 위해 정규화 된 클래스 이름을 알지 못하면 기본적으로 보이지 않습니다.

요구 사항을 다시 생각해 볼 수 있습니다. 클래스 이름이 부여 된 일련의 Translator를로드하는 것이 훨씬 쉽기 때문입니다.

+0

이 중 일부를 명시 적 이름이나 최소한 번역기 클래스가 들어있는 패키지의 이름이 필요한 구성 파일로 옮기는 것을 고려하고 있습니다. 그것의 더 나은 접근법, 나는 단지 다른 옵션이 처음부터 깨끗하게 구현 될 수 없음을 확인하고자합니다. – jdc0589

+0

@ jdc0589 jar 및 로컬 파일에 대한 해결책이 있지만 AFAIK는 모든 종류의 클래스 로더에 대한 일반적인 파일이 아닙니다. – biziclop

+0

정성스럽게 신경 쓰시겠습니까? 로컬 파일과 로컬 jars에만 관심이 있습니다 – jdc0589

3

청구서에 부합 할 수 있습니다. 그렇지 않다면, 당신은 당신을 위해 무엇이 효과가 있을지에 대한 아이디어를 얻기 위해 그들의 출처를 들여다 볼 수 있어야합니다. http://code.google.com/p/reflections/

+0

정말 재미있을 것 같은데 ..하지만 당신은 의존성을 말할 수 있습니까? – jdc0589

+0

나는 그날 그 일찍부터 참고서를 보았고 질문에 비틀 거리며 넘어 갔다. 나는 그것을 사용한 적이 없지만, 다른 무엇이라도 생각했다면, 당신은 근원을 들여다보고 그들이하는 일을 볼 수 있습니다. – digitaljoel

0

도움이 되셨습니까?

클래스 c = cl.loadClass (name) 이후입니다.

클래스 방식의 getInterfaces() 클래스

확인 번역기 클래스 이름에 일치하는 각 클래스 이름을의 배열을 반환합니다.

+0

그건별로 문제가되지 않습니다. 고마워요. – jdc0589

3

원칙적으로 클래스를 실제로로드하고 상상할 수있는 방법을 사용하여 "디렉토리 수신"기능이 전혀 없으므로 임의의 클래스 로더에서는 작동하지 않습니다.

loadClass이 올 때마다 클래스 로더가 즉석에서 클래스 (클래스의 바이트 코드)를 생성 할 수 있으며 이러한 자동 정의 클래스가 사용자 인터페이스를 구현하는 TransableClassloader를 상상해보십시오. 프로그램이 절대 종료되지 않습니다.


URLClassloader 당신이 getURLs()를 사용할 수 있으며, jar:file: URL에 대해 당신이 시도하는 (따라서 및 클래스 이름) 파일 이름의 목록을 가져올 수 JarFile 또는 File API를 사용할 수 말했다. URL에 주어진 패키지 계층 구조의 루트가 있으므로 올바른 패키지 이름을 찾는 것이 어렵지 않습니다.

은 (당신이 더 많은 정보가 필요한 경우를 말한다.)


편집 : 패키지 이름을, 그들은 당신의 계층 구조의 내부의 디렉토리 이름에 해당합니다. 예를 들어 dir/classes에 해당하는 기본 URL이 있고 dir/classes/com/company/gui/SimpleTranslator.class이라는 클래스 파일을 찾으면 클래스 com.company.gui.SimpleTranslator에 해당합니다.

따라서 기본 접두사를 제거하고 을 . (및 .class 자르면)으로 바꿉니다. (JarFile에서는 접두어를 잘라야 할 필요가 없습니다.)

사실 재귀 적 방법을 사용하여 파일 계층을 트래버스하면 동일한 방법으로 패키지 이름을 추가 할 수 있습니다. 문자열 (다음 재귀 호출에 매개 변수로 제공) :

대신 명시 적으로 구현 검색의
public void searchClassesInDir(File dir, String packagePrefix) { 
    if(dir.isDirectory()) { 
     String prefix = packagePrefix + dir.getName() + "."; 
     for(File f : dir.listFiles()) { 
      searchClasses(f, prefix); 
     } 
    } 
    else { 
     String fileName = dir.getName(); 
     if(! fileName.endsWith(".class")) 
      return; 
     String className = packagePrefix + fileName.substring(0, fileName.length()-".class".length()); 
     // now do the rest of your processing 
    } 
} 

searchClasses(new File(url.toURI()), ""); 
+0

이것이 제가 취할 수있는 길이라고 생각합니다. 나는 패키지 이름을 결정하는 것 이외에 모든 것을하는 방법을 안다. 내가 생각할 수있는 유일한 방법은 jar 파일에서 클래스 항목의 경로를 가져 와서 파일 구분자를 '.'로 바꾸는 것입니다. 끝에서 '.class'를 잘라냅니다. 다른 방법이 있습니까? – jdc0589

+0

여기에 예제를 추가했습니다. 그러나 '.class'를 잘라 내고 '/'를 '.'로 변환하십시오. 너무 일합니다. –

+0

또한'listFiles()'호출에 필터를 추가 할 수도 있지만 서브 디렉토리도 잡을 수 있습니다 (또는 두 번째 루프에서). jar 파일의 경우이 작업은 비슷하게 작동합니다. JarEntry를 트래버스해야합니다 (재귀가 필요하지 않고 대체가 필요함). –

4

, 당신이해야 USS 자바의 서비스 프로 바이더 인터페이스 (SPI)와 (자바 6에 도입)을 ServiceLoader 클래스입니다. SPI는 Java에서 설명하는 것을 수행하는 표준 방법입니다.

서비스 공급자를 만드는 방법과 ServiceLoader를 사용하여 런타임에 서비스 공급자를 사용하는 방법은 official Java tutorial을 참조하십시오.

+0

굉장한 소리가 날아간다. 감사합니다 – jdc0589

+0

조금 혼란스러워 여기. 아마 나는 아직 그것을 발견하지 못했을 것이다. 그러나 이것은 META-INF/services/org.jextend.Transable 파일에 정의 된 기본 구현만을 리턴하는 것처럼 보인다. 적어도 다른 구현에 액세스 할 수있는 클래스 로더 인수를 사용하여 ServiceLoader를 구성 했더라도 이제는 할 수 있습니다. – jdc0589

+0

게시 한 링크에이 텍스트가 있습니다. "또한 현재 ServiceLoader 클래스는 런타임에 새 공급자를 사용할 수 있는지 여부를 응용 프로그램에 알릴 수 없습니다." 거래는 뭐니? – jdc0589

관련 문제