2014-01-13 1 views
3

가져 오기하지 않고 컴파일 단위에서 참조 할 수있는 JRE 클래스를 프로그래밍 방식으로 알아야합니다 (정적 코드 분석 용). 우리는 패키지 로컬 클래스를 무시할 수 있습니다. According to the JLS, 패키지 java.lang의 클래스가 암시 적으로 임포트됩니다. 출력은 binary class names의 목록이어야합니다. 이 솔루션은 일반 Java 5 이상 (Guava 없음, Reflections 등)으로 작동하며 벤더에 무관심해야합니다.가져올 필요가없는 JRE 클래스 목록을 프로그래밍 방식으로 결정하십시오.

신뢰할 수있는 Java 기반 솔루션입니다. 여기


내가 지금까지 시도했습니다 무엇에 대한 몇 가지주의 사항은 다음과 같습니다

언뜻 보면, 질문 인 "? 어떻게 패키지의 모든 클래스를로드하기"로 요약 할 것 같다 물론 실질적으로 불가능합니다. 몇 가지 해결 방법이 있습니다 (예 : thisthis 및 여기에 링크 된 블로그 게시물). 하지만 제 경우는 여러 클래스 로더 문제가 존재하지 않기 때문에 훨씬 간단합니다. java.lang stuff는 항상 system/bootstrap 클래스 로더에서로드 할 수 있으며 해당 패키지에 고유 한 클래스를 만들 수 없습니다. 문제는 시스템 클래스 로더가 링크 된 appoaches가 의존하는 클래스 경로를 누설하지 않는다는 것입니다.

지금까지, 나는 핫스팟 VM에 내가 사용하기 때문에 대표단 java.lang.Object을로드 할 수 있습니다, Object.class.getClassLoader() 반환 nullThread.currentThread().getContextClassLoader()을 시스템 클래스 로더의 클래스 경로에 액세스하려면 관리하지 않은,하지만 자체는 포함되지 않습니다 classpath. this one과 같은 솔루션은 저에게 적합하지 않습니다. 또한 list of guaranteed system properties에는 이러한 유형의 클래스 경로 정보 (예 : sun.boot.class.path)가 포함되지 않습니다.

rt.jar이 전혀 없다고 가정하고 시스템 클래스 로더가 사용하는 리소스 목록을 스캔하면 좋을 것입니다. 이러한 접근 방식은 벤더 특정 JRE 구현과 관련하여보다 안전합니다.

+0

귀하가 참조하는 JLS 단락에서 해당 패키지가 "관찰 가능"하지만 암시 적으로 수입된다는 의미는 아닙니다. 7.3 절은 항상 암시적인'import java.lang. *;'이라는 것을 말합니다. – Jesper

+0

@Jesper 감사합니다. 당신 말이 맞습니다. 그것은 내가 경험적으로 관찰 한 것입니다. 그에 따라 질문을 업데이트했습니다. –

+0

패키지 로컬 클래스를 잊어 버리지 않았습니까? –

답변

0

오케이, 질문을 잘못 읽었습니다. 내가 보는 모든 것은 다음과 같습니다.

"미리 컴파일 된 패키지 java.lang에 선언 된 모든 공용 유형 이름을 암시 적으로 가져옵니다. import java.lang. *;이 각 컴파일의 시작 부분에 나타난 것처럼 그 결과 모든 컴파일 단위에서 모든 유형의 이름을 단순한 이름으로 사용할 수 있습니다. "

(http://docs.oracle.com/javase/specs/jls/se7/html/jls-7.html)이 포함하는,이 버전에서 자바의 버전에 따라 다를 것 어떤 종류 알고 싶다면

...

+0

예! 이것은 내 문제보다 나은 설명입니다 :-) –

1

컴파일 된 클래스는 읽을 수 java/lang 텍스트를 포함 할 것으로 보인다. 그래서 이러한 수입을 추출 할 수 있는지 알아보기 위해 약간의 코드를 작성했습니다. 해킹이므로 신뢰할 수는 없지만 jar 파일의 모든 클래스를 추출/나열 할 수 있다고 가정하면 이는 시작점 일 수 있습니다.

import java.io.ByteArrayOutputStream; 
import java.io.InputStream; 
import java.net.URL; 
import java.net.URLClassLoader; 
import java.nio.charset.StandardCharsets; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.HashSet; 

public class Q21102294 { 

public static final String EXTERNAL_JAR = "resources/appboot-1.1.1.jar"; 
public static final String SAMPLE_CLASS_NAME = "com/descartes/appboot/AppBoot.class"; 

public static HashSet<String> usedLangClasses = new HashSet<String>(); 

public static void main(String[] args) { 

    try { 
     Path f = Paths.get(EXTERNAL_JAR); 
     if (!Files.exists(f)) { 
      throw new RuntimeException("Could not find file " + f); 
     } 
     URLClassLoader loader = new URLClassLoader(new URL[] { f.toUri().toURL() }, null); 
     findLangClasses(loader, SAMPLE_CLASS_NAME); 

     ArrayList<String> sortedClasses = new ArrayList<String>(); 
     sortedClasses.addAll(usedLangClasses); 
     Collections.sort(sortedClasses); 
     System.out.println("Loaded classes: "); 
     for (String s : sortedClasses) { 
      System.out.println(s); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

} 

public static void findLangClasses(URLClassLoader loader, String classResource) throws Exception { 

    URL curl = loader.getResource(classResource); 
    if (curl != null) { 
     System.out.println("Got class as resource."); 
    } else { 
     throw new RuntimeException("Can't open resource."); 
    } 
    ByteArrayOutputStream bout = new ByteArrayOutputStream(); 
    InputStream in = curl.openStream(); 
    try { 
     byte[] buf = new byte[8192]; 
     int l = 0; 
     while ((l = in.read(buf)) > -1) { 
      bout.write(buf, 0, l); 
     } 
    } finally { 
     in.close(); 
    } 
    String ctext = new String(bout.toByteArray(), StandardCharsets.UTF_8); 
    int offSet = -1; 
    while ((offSet = ctext.indexOf("java/lang/", offSet)) > -1) { 
     int beginIndex = offSet; 
     offSet += "java/lang/".length(); 
     char cnext = ctext.charAt(offSet); 
     while (cnext != ';' && (cnext == '/' || Character.isAlphabetic(cnext))) { 
      offSet += 1; 
      cnext = ctext.charAt(offSet); 
     } 
     String langClass = ctext.substring(beginIndex, offSet); 
     //System.out.println("adding class " + langClass); 
     usedLangClasses.add(langClass); 
    } 
} 

} 

다음과 같은 출력을 제공합니다 : 사용 된 컴파일 된 클래스의

Got class as resource. 
Loaded classes: 
java/lang/Class 
java/lang/ClassLoader 
java/lang/Exception 
java/lang/Object 
java/lang/RuntimeException 
java/lang/String 
java/lang/StringBuilder 
java/lang/System 
java/lang/Thread 
java/lang/Throwable 
java/lang/reflect/Method 

소스 코드가 here 사용할 수 있습니다.

+0

상자 밖에서 좋은 생각! java.lang 클래스의 전체 목록을 가져 오지는 않습니다 (참조 된 클래스 만 해당). 또한 컴파일 된 클래스 파일에 액세스해야합니다 (이 시점에서는 필자가 아니지만 잘 사용함). 그래도 흥미로운 새로운 접근 방식에 대해 감사드립니다. –

+0

아하, 이제 더 나은 질문을 이해합니다. 바라건대 누군가는 또 다른 창조적 인 불꽃을 피었습니다. – vanOekel

관련 문제