컴파일 시점에 자바가 제공하는 어노테이션 프로세서를 사용하여 소스코드의 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;
}
}
댓글