2013-08-16 1 views
4

Java 클래스를 동적으로로드하려고합니다. 기본 개념은 런타임에 동적으로로드되는 모듈이 jar에 포함되어 있다는 것입니다.

Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class }); 
method.setAccessible(true); 
method.invoke(moduleLoader, new Object[] { file.toURI().toURL() }); 
Class fooClass = moduleLoader.loadClass("com.coderunner.Foo"); 
Object foo = fooClass.newInstance(); 

모든 모듈이 @Module 주석 주석이 : 이것은 내가 (나는 그것이 해키 알고 있지만, 동적으로 항아리를 추가 할 수있는 다른 방법은 AFAIK 이미 존재하는 클래스 로더에 없음) 그것을 할 방법이다. 따라서 모듈에 대한 추가 정보를 얻기 위해 주석을 얻으려고합니다. 내가 여기에 무슨 조금 혼란하다고 말하고 문제는. foo는에 주석이 형이 com.sun의 것을 $ 프록시 $ (27) 대신 com.coderunner.Module이므로 내가 가지고

ClassCastException: Cannot cast com.sun.proxy.$Proxy42 (id=64) to com.coderunner.Module 

를 얻을 수 . 내가하고 싶은 일이 가능한가? 방법?

편집 : 나는 봄/봄 - mvc 및 바람둥이 환경에서 이것을 시도하고 있음을 언급해야 할 수도 있습니다.

답변

0

주석을 사용하여 선언적 접근 방식을 기반으로 코드 생성을위한 앤트 작업을 만들 때도 동일한 문제가있었습니다. 프록시 객체의 설명서에 instanceof가 문제를 해결해야한다고 나와 있는데, 하지만이 문제는 해결되지 않았습니다. 나는 마침내

Annotation[] annotations = classObj.getAnnotations();

for(int i = 0;i < annotations.length;i++) { 
     Class<?>[] interfaces = annotations[i].getClass().getInterfaces(); 

     for(int i2 = 0; i2 < interfaces.length;i2++) { 
      System.out.println("interface:" + interfaces[i2].getName()); 
     } 

는 주석이 당신에게 원하는 결과를 줄 것이다 클래스 이름에 있으므로이 이름을 비교, 원래 주석의 내 이름을주고있는 주위를 얻었다.

1

리플렉션이 프록시 객체를 반환한다는 사실은 사용자가 주석과 해당 값에 대한 정보를 수집하는 것을 방해하지 않습니다.

getclass 방법은 프록시 개체를 반환

log.info("annotation class:" + annotation.getClass()); 

출력 :

[INFO] annotation class:class com.sun.proxy.$Proxy16class 

출력이 예에서와 같은,하지만 그건 문제가되지 않습니다. 메서드 (또는 필드)가 있으면 충분합니다. 추가 부분은 주석 방법을 호출하는 입니다.

public void analyseClass(Class myClass) { for (Method method: myClass.getMethods()) { System.out.println("aanotations :" + Arrays.toString(field.getAnnotations())); for (Annotation annotation : method.getAnnotations()) { log.info("annotation class:" + annotation.getClass()); log.info("annotation class type:" + annotation.annotationType()); Class<Annotation> type = (Class<Annotation>) annotation.annotationType(); /* extract info only for a certain annotation */ if(type.getName().equals(MyAnnotation.class.getName())) { String annotationValue = (String) type.getMethod("MY_ANNOTATION_CERTAIN_METHOD_NAME").invoke(annotation); log.info("annotationValue :" + annotationValue); break; } } } //do the same for the fields of the class for (Field field : myClass.getFields()) { //... } } 

이 솔루션에 와서, 내가 사용 후 다음 How to get annotation class name, attribute values using reflection

+0

완벽하게 작동합니다. 감사합니다. –

1

당신은 문제가되지해야 어노테이션 유형의 앞에 프록시를 얻을 수 있다는 사실을. 이것이 실제로 당신이 겪고있는 문제의 원인이라고 믿게 만들 수도 있습니다. "isAnnotationPresent (..)"와 같은 항목이 실패하면 해당 프록시가 아닌 것입니다. 이는 여러 클래스 로더를 사용하여 주석 클래스를 여러 번로드했기 때문입니다. 예를 들어 Jetty는 기본적으로 WebApp 클래스 로더에 우선 순위를 부여합니다. 따라서 Jetty 서버 인스턴스 (또는 Tomcat 등)가 이미 주석 클래스를로드하고 주석이 웹 애플리케이션의 클래스 경로에있는 경우 "getAnnotation()"이 반환하지 않는 것과 같은 문제가 발생할 수 있습니다. 어노테이션이 들어있는 라이브러리가 두 번로드되지 않았는지 확인하십시오.

Andreas가 제공하는 솔루션은 매우 더러운 해결 방법이며 실제로 클래스 로딩을 제어/적절하게 구성하지 않았 음을 의미합니다.