Недавно передо мной встала задача написания своих кастомных аннотации и их обработки во время компиляции. Первый вопрос, который я себе задала: с чего начать? После анализа я решила поделиться с вами ответом на этот вопрос.
Думаю, рассказывать, что такое аннотации в java и с чем их едят, не имеет смысла, так как каждому юному программисту это знакомо ( а кому не знакомо, может прочесть самостоятельно). К тому же на хабре есть интересная ознакомительная статья об этом явлении.
Но сегодня я хочу поговорить именно о кастомных аннотациях в Android-приложении, которые обрабатываются в процессе компиляции проекта вашим собственным обработчиком и о автогенерации классов на их основе. А так же, по ходу дела, расскажу вам, как быстро все настроить в IDEA (сама я пользуюсь версией 12.1, возможно в других есть отличия).
Для реализации нам понадобится 2 проекта: в первом опишем наши кастомные аннотации и их обработчик, из него сгенерируем jar файл, который подключим ко второму тестовому проекту, который и будет использовать наши аннотации.
Шаг 1
Создаем новый library проект, в котором описываем свою аннотацию. Класс с аннотацией выглядит примерно так:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface CustomAnnotation { String className(); String value() default "Hello"; int type() default 0; }
@Retention говорит о том, что наша аннотация будет присутствовать только в исходном коде и отброшена компилятором (а до этого момента мы её обработаем).
Шаг 2
Создаем непосредственно наш обработчик аннотаций. Он представляет собой класс, расширяющий AbstractProcessor. Ему мы говорим, что он будет обрабатывать все аннотации и указываем поддерживаемую версию исходных файлов таким образом:
@SupportedAnnotationTypes({"*"}) @SupportedSourceVersion(SourceVersion.RELEASE_6) public class CustomProcessor extends AbstractProcessor { }
Далее переопределяем метод process, в котором прописываем логику генерации нового класса. Мой метод выглядит так:
@Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (Element e : roundEnv.getElementsAnnotatedWith(CustomAnnotation.class)) { CustomAnnotation ca = e.getAnnotation(CustomAnnotation.class); String name = e.getSimpleName().toString(); char[] c = name.toCharArray(); c[0] = Character.toUpperCase(c[0]); name = new String(name); TypeElement clazz = (TypeElement) e.getEnclosingElement(); try { JavaFileObject f = processingEnv.getFiler(). createSourceFile(clazz.getQualifiedName() + "Autogenerate"); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Creating " + f.toUri()); Writer w = f.openWriter(); try { String pack = clazz.getQualifiedName().toString(); PrintWriter pw = new PrintWriter(w); pw.println("package " + pack.substring(0, pack.lastIndexOf('.')) + ";"); pw.println("\npublic class " + clazz.getSimpleName() + "Autogenerate {"); TypeMirror type = e.asType(); pw.println("\n public " + ca.className() + " result = \"" + ca.value() + "\";"); pw.println(" public int type = " + ca.type() + ";"); pw.println("\n protected " + clazz.getSimpleName() + "Autogenerate() {}"); pw.println("\n /** Handle something. */"); pw.println(" protected final void handle" + name + "(" + ca.className() + " value" + ") {"); pw.println("\n//" + e); pw.println("//" + ca); pw.println("\n System.out.println(value);"); pw.println(" }"); pw.println("}"); pw.flush(); } finally { w.close(); } } catch (IOException x) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, x.toString()); } } return true; }
На этом этапе можно включить фантазию и писать, что душе угодно (ну или что требуется =). После того, как вы закончили с обработчиком аннотаций и описали все свои кастомные аннотации, из этого проекта нужно сгенерировать jar файл. В Idea 12 это делается достаточно просто: Project Settings -> Artifacts -> Add -> Jar -> From modules… Далее делаем Build -> Rebuild Project и находит наш сгенерированный файл jar в Output директории проекта.
Шаг 3
Создаем тестовый проект, в котором и будем использовать наши кастомные аннотации. К проекту подключаем сгенерированный на прошлом шаге jar файл и радуемся, что наши аннотации теперь нам доступны. В любом классе прописываем нашу аннотацию, например так:
public class MyActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @CustomAnnotation(className = "String", type = 1) public void annotatedMethod(String value) { } }
Помните, что мы указали нашей аннотации @Target(ElementType.METHOD)
, а это значит что мы можем прописать ее только перед методом.
Шаг 4
Теперь скажем Idea использовать наш обработчик аннотаций и магия начнет работать! Для этого идём в Settings в раздел Compiler — > Annotation Processors. Ставим галочку Enable annotation processing, в поле Processor path указываем путь к нашему сгенерированному jar файлу. Так же в окне Processor FQ name вводим полное название класса, который отвечает за обработку. В нашем случает это CustomProcessor. Заполненное окно должно выглядеть примерно так.
Шаг 5
Делаем Build -> Rebuild project и наслаждаемся результатами. В дереве проекта должна появиться папка generated, в которой будут лежать новые файлы.
Вот что получилось у меня:
public class MyActivityAutogenerate { public String result = "Hello"; public int type = 1; protected MyActivityAutogenerate() {} /** Handle something. */ protected final void handleannotatedMethod(String value) { //annotatedMethod(java.lang.String) //@com.example.AnnotationsProcessor.CustomAnnotation(type=1, value=Hello, className=String) System.out.println(value); } }
Happy codding!
ссылка на оригинал статьи http://habrahabr.ru/post/200354/
Добавить комментарий