Здравствуйте, уважаемые обитатели форума. Мне в очередной раз требуется Ваша помощь, совет, или просто подсказка. Не далее как вчера, столкнулся с такой штукой как annotation processor, штука оказывается полезная, но достаточно плохо осваиваемая.
Передо мной стоит задача. Имеется небольшая программа:
Открыть спойлер
source code[src=java]
public class TestClass {
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.SOURCE)
@interface link {
}
public void doWork(@link int str) {
System.out.println(str);
}
public static void main(String[] args) {
TestClass test = new TestClass ();
test.doWork("101");
}
}
[/src]
Естественно, всё это дело не компилируется в данном виде. Необходимо с помощью процессора аннотаций на выхлопе получить исходный код такого вида:
Открыть спойлер
target code[src=java]
public class TestClass {
public void doWork(int str) {
System.out.println(str);
}
public static void main(String[] args) {
TestClass test = new TestClass ();
test.doWork(101);
}
}
[/src]
Задача, вроде бы не сложная, заменить String на int. Но по причине отсутствия достаточной документации, задача превращается в довольно-таки трудоемкую.
Не могли бы Вы указать, где про процессор аннотаций можно почитать более подробно, либо вкратце объяснить принцип его работы?
P.S.
Google в данном случае плохо вывозит.
Добавлено через 1 час 4 минуты
Не актуально, цель была достигнута в следующей реализации:
Открыть спойлер
code
[src=java]
@SupportedAnnotationTypes(AnnotationProcessor.ANNOTATION_TYPE)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class AnnotationProcessor extends AbstractProcessor {
public static final String ANNOTATION_TYPE = "*";
private TreeMaker maker;
private Trees trees;
private AnnotationVisitor visitor;
@Override
public void init(ProcessingEnvironment procEnv) {
super.init(procEnv);
JavacProcessingEnvironment javacProcessingEnv = (JavacProcessingEnvironment) procEnv;
this.maker = TreeMaker.instance(javacProcessingEnv.getContext());
this.trees = Trees.instance(javacProcessingEnv);
visitor = new AnnotationVisitor();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element element : roundEnv.getRootElements()) {
CompilationUnitTree unit = trees.getPath(element).getCompilationUnit();
visitor.roundEnv = roundEnv;
visitor.scan(unit, null);
}
return false;
}
private class AnnotationVisitor extends TreePathScanner<Object, Trees> {
public RoundEnvironment roundEnv;
@Override
public Object visitMethodInvocation(MethodInvocationTree node, Trees p) {
JCMethodInvocation jcMethodInvocation = (JCMethodInvocation) node;
if (jcMethodInvocation.getMethodSelect() instanceof JCFieldAccess) {
JCFieldAccess jcFieldAccess = (JCFieldAccess) jcMethodInvocation.getMethodSelect();
Name methodName = jcFieldAccess.name;
//javacProcessingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Method.name: " + String.valueOf(methodName));
// Получаем элементы, помеченные аннотацией @link
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(link.class);
if (elements.size() > 0) {
for (Element element : elements) {
// Обрабатываем только параметры методов
if (element instanceof Symbol.VarSymbol) {
Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) element;
//javacProcessingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "varSymbol: " + String.valueOf(varSymbol.name));
// Проеряем совпадение имени посещенного метода, с именем метода текущего элемента
Symbol.MethodSymbol methodSymbol = (Symbol.MethodSymbol) element.getEnclosingElement();
//javacProcessingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "methodSymbol: " + String.valueOf(methodSymbol.name));
if (methodSymbol.name == methodName) {
// Получаем индекс параметра, помеченного аннотацией @link
int index = methodSymbol.getParameters().indexOf(element);
// Получаем массив параметров, переданных в метод
//javacProcessingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "index: " + String.valueOf(index));
JCExpression[] expressions = new JCExpression[jcMethodInvocation.args.size()];
expressions = jcMethodInvocation.args.toArray(expressions);
//javacProcessingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Type before: " + String.valueOf(expressions[index].getClass()));
// Получаем значение текущего элемента и выполняем замену
int value = Integer.valueOf(String.valueOf(((JCLiteral) expressions[index]).value));
//javacProcessingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Type: " + String.valueOf(expressions[index].getClass()));
expressions[index] = maker.Literal(value);
jcMethodInvocation.args = List.from(expressions);
}
}
}
}
}
return super.visitMethodInvocation(node, p);
}
}
}
[/src]