본문 바로가기
카테고리 없음

롬복 / 애노테이션 프로세서

by 문자메일 2022. 12. 21.

컴파일 시점에 자바가 제공하는 어노테이션 프로세서를 사용하여 소스코드의 AST(abstract syntax tree)를 조작한다.

 

특정한 어노테이션이 붙어있는 소스코드를 참조해서 또 다른 소스코드를 만들어 낼 수 있는 기능이다.

 

그런데 롬복은 공개된 API가 아니라 컴파일러 내부 클래스를 사용하여 기존 소스 코드를 조작한다.

특히 이클립스는 컴파일러 클래스까지 조작하여 사용한다. 마찬가지로 이것들은 공개된 API가 아니기 때문에 버전 호환성에 문제가 생길 수 있고, 언제라도 문제가 발생해도 이상하지 않다.

=> 즉 롬복으로 원본 소스코드를 조작하는 것은 정상 기능이 아닌 일종의 해킹 기능 같은 것이라는 의미

 

package org.example;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.SOURCE)
public @interface Magic {
}

 

package org.example;

import com.google.auto.service.AutoService;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;

@AutoService(Processor.class)
public class MagicMojaProcessor extends AbstractProcessor {

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Set.of(Magic.class.getName());
    }

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

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // Magic 인터페이스만 처리함
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Magic.class);
        for(Element element : elements){
            Name elementName = element.getSimpleName();

            // 엘리먼트가 interface가 아니라면 에러를 낸다.
            if (element.getKind() != ElementKind.INTERFACE){
                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,"Magic annotation can not be used on " + elementName);
            } else {
                processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "" + elementName);
            }
            
            // 여기부터 annotation이 인식되었을 때 어떤 동작을 수행하게 할 건지 코드로 작성하면 됨.
            // 강의에는 추가적으로 작성하는 코드 있었는데 귀찮아서 여기서는 안씀
            // 
        }

        return true;
    }
}

댓글