2016-11-23 6 views
2

Java 주석 프로세서를 사용하여 수행되는 여러 검사가 있지만 주석이없는 유형에 대한 검사도하고 싶습니다.주석이없는 java 유형 처리

예를 들어 @Responsible(name="xyz")과 같은 특수 효과가있는 경우 컴파일 프로세스에 연결하여 모든 최상위 유형에 대한 특수 효과가 적용되도록하는 것이 가장 좋습니다.

현재 구현에서는 기대되는 것 (Responsible)과 패키지 레벨 1이라는 두 가지 주석을 사용합니다. 나중에 주석 처리가없는 경우에도 주석 처리기를 '실행'하는 데 사용됩니다. 해고 된 주석 처리기에서 나는 디스크 상에있는 & 필터 자바 파일 (컴파일러에 전달 된 인수 사용)을 검색하여 처리하고자하는 모든 파일을 수집하고 자바 파일이 프로세서가 주석 처리 된 유형에 해당 할 때 필터링합니다 손질. 이렇게하면 주석을 지정하지 않고 누군가가 새 파일을 커밋하면 빌드가 실패합니다.

'주석이없는'유형을 찾는 더 깨끗한 방법이 없습니까?

답변

2

모든 요소를 ​​처리하려면 RoundEnvironment#getRootElements()은 프로세서가 모든 것을 처리하도록 선언 된 경우 *을 사용하여 찾고 있던 요소 목록이었습니다.

그래서 모든 종류의 내가

@AutoService(Processor.class) 
public class ResponsibleAnnotationProcessor extends AbstractProcessor { 
    @Override 
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { 
      List<ElementKind> typeKinds = Arrays.asList(ElementKind.ENUM, ElementKind.INTERFACE, ElementKind.CLASS); 
      // let's gather all types we are interrested in 
      Set<String> allElements = env.getRootElements() 
        .stream() 
        .filter(e -> typeKinds.contains(e.getKind())) // keep only interesting elements 
        .map(e -> e.asType().toString())    // get their full name 
        .collect(Collectors.toCollection(() -> new HashSet<>())); 
      Set<String> typesWithResponsible = new HashSet<>(); 

      annotations.forEach(te -> { 
       if (Responsible.class.getName().equals(te.asType().toString())) { 
        // We collect elements with an already declared ownership 
        env.getElementsAnnotatedWith(te).forEach(e -> typesWithResponsible.add(e.asType().toString())); 
       } 
      }); 

      allElements.removeAll(typesWithResponsible); 
      allElements.forEach(cname -> processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, cname + " must be annotated with @" + Responsible.class.getName() + " to declare a ownership")); 
      return false; 
    } 

    @Override 
    public SourceVersion getSupportedSourceVersion() { 
     return SourceVersion.latestSupported(); 
    } 

    @Override 
    public Set<String> getSupportedAnnotationTypes() { 
     // We want to process all elements 
     return Collections.singleton("*"); 
    } 
} 
3

프로세서를 실행하기 위해 주석에 의존 할 필요는 없습니다. the documentation 설명과 같이 본에는 주석 형이없는

경우 주석 처리는 여전히 "*"주석 타입의 (빈) 세트를 요구할 수 처리를 지원하지만 범용 프로세서를 발생한다.

클래스를 찾는 방법은 조금 어색합니다. 대신 패키지와 클래스 사이의 부모 - 자식 관계에 의존 할 수 있습니다 : 흥미로운 클래스를 포함하는 최상위 패키지 요소의 이름을 찾고 Element#getEnclosedElements을 사용하여 패키지 (및/또는 하위 패키지)로 내려갑니다. 또는 패키지 내에 단일 클래스를 배치 한 다음 Element#getEnclosingElement을 사용하여 최상위 패키지로 올라갈 수 있습니다. 패키지 객체는 Elements#getPackageElement을 사용하여 이름으로 얻을 수 있으며 클래스 객체는 Elements#getTypeElement을 사용하여 이름으로 가져올 수 있습니다.

파일 및 디렉토리와의 수동 상호 작용과 비교하여 훨씬 덜 부서지기 쉽고 소스 파일을 이동하거나 디렉토리간에 나누면 손상되지 않습니다.

봉쇄 주문은 "a single package" -> "class" -> "method" -> ...이며 모든 패키지의 부모는 패키지이며 자체 패키지가 아닙니다 (net.examplenet에 포함되어 있지 않음).

+0

문제를 끝내 @Responsible 주석하고 있는지 확인하기 위해 나는 훨씬 조사해 드리겠습니다, 요소 # getEnclosedElements' 하위 패키지를 통과하는 것을 허용하지 않습니다'이다 "*"프로세서와'roundEnv.getRootElements() ' –

+0

@MatthieuBROUILLARD 네, 이것이 바로 위의 의미입니다. 다행스럽게도'String # split'을 사용하여 직접 서브 패키지를 얻는 것을 막을 수있는 것이 아무것도 없습니다 :) – user1643723

+0

"*"사용에 대한 귀하의 힌트에 감사드립니다. –