2010-01-25 2 views
1

내가 다음과 같이 동작 URLClassLoader를 만들려고 노력하고있어 :URLClassLoader가 다음과 같이 동작하도록하려면 어떻게해야합니까?

이름이 흠 주어진 세트에있는 클래스에 대해 묻는다면
  • ,
  • 그렇지 않으면 정상으로로드하는을 반환 더미 클래스

나는 이것을 얻을 수 없다. 아래의 시도에서 나는 을 성공적으로로드 할 것을 SpecialClassLoader이 기대합니다. 이렇게하면 Test$SuperThing을로드하려고 시도하고 더미 클래스 Nothing이 대신로드된다는 사실에 대해 정상적인 것으로 기대됩니다.

그러나 무엇인가가 잘못되어 Test$SuperThing을 찾고 NoClassDefFoundError을 던집니다.

누구든지 해결 방법을 알고 있습니까?

public class Test { 

    private static class SuperThing {} 

    private static class Thing extends SuperThing {} 

    public static void main(String[] args) { 
     Set<String> inclusions = new HashSet<String>(); 
     inclusions.add("Test$Thing"); // note Test$SuperThing is excluded 
     URLClassLoader cl = (URLClassLoader) 
      Thread.currentThread().getContextClassLoader(); 
     SpecialClassLoader cll = 
      new SpecialClassLoader(cl.getURLs(), inclusions); 
     try { 
      cll.loadClass("Test$Thing"); // line 22 (see stacktrace below) 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } 
    } 

    private static class Nothing {} 

    private static final class SpecialClassLoader extends URLClassLoader { 

     private final Set<String> inclusions; 

      public SpecialClassLoader(URL[] urls, Set<String> inclusions) { 
       super(urls); 
       this.inclusions = inclusions; 
      } 

     @Override 
     public Class<?> loadClass(String name) throws ClassNotFoundException { 
      if (inclusions.contains(name)) { 
       return findClass(name); // line 40 (see stacktrace below) 
      } 
      return Nothing.class; 
     } 
    } 
} 

편집 :

 

    Exception in thread "main" java.lang.NoClassDefFoundError: Test$SuperThing 
     at java.lang.ClassLoader.defineClass1(Native Method) 
     at java.lang.ClassLoader.defineClass(ClassLoader.java:620) 
     at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124) 
     at java.net.URLClassLoader.defineClass(URLClassLoader.java:260) 
     at java.net.URLClassLoader.access$000(URLClassLoader.java:56) 
     at java.net.URLClassLoader$1.run(URLClassLoader.java:195) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at java.net.URLClassLoader.findClass(URLClassLoader.java:188) 
     at Test$SpecialClassLoader.loadClass(Test.java:40) 
     at Test.main(Test.java:22) 
+0

오류 StackTrace하시기 바랍니다. findClass() 메소드는 제공된 케이스를 기반으로 호출 될 것입니다. –

+0

stacktrace를 추가했습니다. 나는 findClass()를 재정의하지 않았다. – NellerLess

+0

코드에서 findClass() 라인이 호출되어서는 안되는 것처럼 보이지만, 무엇인가 이유가 있습니다. 디버거 또는 print out 문을 사용하여 오류가 없는지 확인하십시오. 그렇다면 그 이유를 알아 내려고 노력하십시오. –

답변

4

다음과 같은 현상이 발생합니다.

  • Test $ Thing을로드하려고하면 defineClass 메서드가 Test $ Thing의 수퍼 클래스를로드해야한다는 것을 알 수 있습니다. 즉 $ SuperThing 테스트.

  • 시스템 클래스 로더가 Nothing 클래스를 반환하는 클래스 로더를 호출합니다.

  • 시스템 클래스 로더는 "클래스에 올바른 정규화 된 클래스 이름이 없습니다!"라고 말하고 NoClassDefFoundError을 던집니다.

기본적으로이 시스템 클래스 로더는 JVM을 불안정하게 만들지 않도록 보호합니다. 커스텀 클래스 로더가 잘못된 클래스를로드하도록 허용한다면, 불쾌한 일이 발생할 수 있습니다. 예를 들어 클래스 로더를 속여 Nothing 클래스를로드 한 후 Test $ SuperThing 클래스에 정의 된 일부 메서드가 호출 된 경우 발생할 수있는 현상에 대해 생각해보십시오.

일부 클래스의 더미 버전을 대체하는 더러운 트릭을 수행하려면 오른쪽 정규화 된 클래스 이름, 올바른 수퍼 클래스 및 인터페이스 및 올바른 서명이있는 메소드를 사용하여 바이트 코드를 생성해야합니다 . 즉, 바이너리 호환성 규칙을 만족해야합니다. 그렇게하지 않으면, 시스템 클래스 로더는 커스텀 클래스 로더에서하려고하는 것과 상관없이 클래스를로드하는 것을 거부합니다.

솔직히, 당신이하려는 일에 완전히 다른 접근 방식을 취해야합니다.

+0

감사합니다. 이것은 완전한 의미를 갖습니다. – NellerLess

-1

이 테스트 $ Thing.class라는 이름의 클래스의 출력에서 ​​찾을 수있다 : 여기에 내가 얻을 스택 트레이스 (줄 번호 (22)와 40 위 목록에 표시됩니다)입니다 컴파일러? 코드가 여기에 주어지면 결코 직접적으로 참조되지 않을 것이고 아마도 컴파일러가 클래스를 최적화 할 것입니다. 이 경우 반사가 클래스를 찾을 수 없습니다.

이 경우 클래스에 참조 (비 반사)를 추가하여 컴파일 할 수 있습니다.

편집 : 직접 해보신 후 문제의 원인을 찾은 것 같습니다. Thing 선언에서 'extends SuperThing'을 제거하면 java.lang.Object를 찾지 못했다고 불평합니다. 아마도 클래스 로더는 확장 된 클래스를 포함하여 모든 종속 클래스도로드하려고 시도하며 허용 된 클래스가 허용 목록에 없기 때문에로드 할 수 없습니다. 그러나 그것은 이론입니다.

+0

예, 있습니다. – NellerLess