런타임시 Java 주석 스캔 [닫기]

주석이 달린 클래스의 전체 클래스 경로를 검색하는 가장 좋은 방법은 무엇입니까?

라이브러리를 만들고 있는데 사용자가 클래스에 주석을 달 수 있도록 웹 응용 프로그램이 시작될 때 특정 주석에 대해 전체 클래스 경로를 스캔해야합니다.

이 작업을 수행 할 라이브러리 또는 Java 기능을 알고 있습니까?

편집 : Java EE 5 웹 서비스 또는 EJB의 새로운 기능과 같은 것을 생각하고 있습니다. 당신은 당신의 클래스에 주석 @WebService또는 @EJB그들이 원격으로 액세스 할 수있는 로딩 그렇게하는 동안 시스템은 이러한 클래스를 찾습니다.



답변

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider를 사용하십시오.

API

기본 패키지에서 클래스 경로를 스캔하는 구성 요소 제공자. 그런 다음 후보를 찾기 위해 결과 클래스에 제외 및 포함 필터를 적용합니다.

ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(<DO_YOU_WANT_TO_USE_DEFALT_FILTER>);

scanner.addIncludeFilter(new AnnotationTypeFilter(<TYPE_YOUR_ANNOTATION_HERE>.class));

for (BeanDefinition bd : scanner.findCandidateComponents(<TYPE_YOUR_BASE_PACKAGE_HERE>))
    System.out.println(bd.getBeanClassName());

답변

또 다른 해결책은 Google 반영입니다. 입니다.

빠른 검토:

  • Spring 솔루션은 Spring을 사용하는 경우 갈 수있는 방법입니다. 그렇지 않으면 큰 의존성입니다.
  • ASM을 직접 사용하는 것은 다소 번거 롭습니다.
  • Java Assist를 직접 사용하는 것도 복잡합니다.
  • Annovention은 매우 가볍고 편리합니다. 아직 maven 통합이 없습니다.
  • Google 리플렉션은 Google 컬렉션을 끌어냅니다. 모든 것을 색인화 한 다음 매우 빠릅니다.

답변

ClassGraph를 사용하여 주어진 주석이있는 클래스를 찾을 수있을 뿐만 아니라 다른 관심있는 기준 (예 : 주어진 인터페이스를 구현하는 클래스)을 검색 할 수 있습니다. (면책 조항, ClassGraph의 저자입니다.) ClassGraph는 전체 클래스 그래프 (모든 클래스, 주석, 메소드, 메소드 매개 변수 및 필드)를 메모리, 클래스 경로의 모든 클래스 또는 클래스의 추상 표현을 작성할 수 있습니다 허용 된 패키지를 사용하면 원하는 클래스 그래프를 쿼리 할 수 ​​있습니다. ClassGraph는 다른 스캐너보다 더 많은 클래스 경로 지정 메커니즘 및 클래스 로더를 지원 하며 새로운 JPMS 모듈 시스템과도 원활하게 작동하므로 ClassGraph를 기반으로 코드를 작성하면 코드를 최대한 이식 할 수 있습니다. 여기 API를 참조하십시오.


답변

매우 가볍고 (종속성, 간단한 API, 15kb jar 파일) 매우 빠른 솔루션 을 원한다면 https://github.com/rmuller/infomas-asl 에서 annotation-detector찾아 보십시오.

면책 조항 : 나는 저자입니다.


답변

Java Pluggable Annotation Processing API를 사용하여 컴파일 프로세스 중에 실행될 주석 프로세서를 작성할 수 있으며 주석이 달린 모든 클래스를 수집하고 런타임에 사용할 색인 파일을 빌드합니다.

런타임에 클래스 경로를 스캔 할 필요가 없기 때문에 어노테이션이있는 클래스 발견을 수행 할 수있는 가장 빠른 방법입니다. 이는 일반적으로 매우 느린 조작입니다. 또한이 방법은 모든 클래스 로더에서 작동하며 일반적으로 런타임 스캐너에서 지원되는 URLClassLoader와 함께 작동합니다.

위의 메커니즘은 이미 ClassIndex 라이브러리 에서 구현되었습니다 .

이를 사용하려면 @IndexAnnotated 메타 주석으로 사용자 정의 주석에 주석을 달 수 있습니다 . 이렇게하면 컴파일시 색인 파일 인 META-INF / annotations / com / test / YourCustomAnnotation이 주석이 달린 모든 클래스를 나열합니다. 다음을 실행하여 런타임시 인덱스에 액세스 할 수 있습니다.

ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)

답변

대답하기에 너무 늦었습니까? 나는 도서관에가는 것이 더 낫습니다.ClassPathScanningCandidateComponentProvider 또는 Scannotations 와 같은 좋습니다.

그러나 누군가 누군가 classLoader를 사용 해보고 싶더라도 패키지의 클래스에서 주석을 인쇄하기 위해 직접 작성했습니다.

public class ElementScanner {

public void scanElements(){
    try {
    //Get the package name from configuration file
    String packageName = readConfig();

    //Load the classLoader which loads this class.
    ClassLoader classLoader = getClass().getClassLoader();

    //Change the package structure to directory structure
    String packagePath  = packageName.replace('.', '/');
    URL urls = classLoader.getResource(packagePath);

    //Get all the class files in the specified URL Path.
    File folder = new File(urls.getPath());
    File[] classes = folder.listFiles();

    int size = classes.length;
    List<Class<?>> classList = new ArrayList<Class<?>>();

    for(int i=0;i<size;i++){
        int index = classes[i].getName().indexOf(".");
        String className = classes[i].getName().substring(0, index);
        String classNamePath = packageName+"."+className;
        Class<?> repoClass;
        repoClass = Class.forName(classNamePath);
        Annotation[] annotations = repoClass.getAnnotations();
        for(int j =0;j<annotations.length;j++){
            System.out.println("Annotation in class "+repoClass.getName()+ " is "+annotations[j].annotationType().getName());
        }
        classList.add(repoClass);
    }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

/**
 * Unmarshall the configuration file
 * @return
 */
public String readConfig(){
    try{
        URL url = getClass().getClassLoader().getResource("WEB-INF/config.xml");
        JAXBContext jContext = JAXBContext.newInstance(RepositoryConfig.class);
         Unmarshaller um =  jContext.createUnmarshaller();
         RepositoryConfig rc = (RepositoryConfig) um.unmarshal(new File(url.getFile()));
         return rc.getRepository().getPackageName();
        }catch(Exception e){
            e.printStackTrace();
        }
    return null;

}
}

그리고 설정 파일에서 패키지 이름을 넣고 클래스에 정렬 해제하십시오.


답변

Spring에서는 AnnotationUtils 클래스를 사용하여 다음을 작성할 수도 있습니다. 즉 :

Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);

자세한 내용과 다른 모든 방법은 공식 문서를 확인하십시오 :
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html