410013796724260
• Webmoney
R335386147728
Z369087728698
Аннотация методов, annotationАннотация "annotation" в языке Java – это специальная форма синтетических метаданных, которая может быть добавлена в исходный код. Аннотации используются для анализа кода, компиляции или выполнения. Аннотированы могут быть пакеты, классы, методы, переменные и параметры. Аннотация выполняет следующие функции :
Встроенные аннотации : @Override, @Deprecated, @SuppressWarningsВстроенные аннотации отслеживаются средой разработки IDE и применяются к java-коду метода :
Аннотации, применяемые к другим аннотациям : @Retention, @Documented, @Target, @Inherited
Первоначально в платформе Java имелся механизм, предваряющий механизм аннотаций — например, модификатор transient или тэг @deprecated. В сентябре 2002 года сообществу Java представлен документ JSR-175, описывающий основные тезисы по аннотациям. Он был утвержден в 2004 году. Аннотации стали доступны в самом языке начиная с версии Java 5.0 и описаны в JSR-269. В версии Java 6 аннотации были интегрированы в компилятор javac. Пример аннотации :
public class Animal
{
public void speak() {
}
}
public class Cat extends Animal
{
@Override // Аннотация говорит о том, что этот метод переопределен
public void speak() {
System.out.println("Meow.");
}
}
Синтаксис аннотации, @interfaceАннотации представляют из себя дескрипторы, включаемые в текст программы, и используются для хранения метаданных программного кода, необходимых на разных этапах жизненного цикла программы. Информация, хранимая в аннотациях, может использоваться соответствующими обработчиками для создания необходимых вспомогательных файлов или для маркировки классов, полей и т.д. То есть, аннотации могут быть применены к декларациям классов, полей, методов, ну и конечно же аннотаций. Для описания новой аннотации используется ключевое слово @interface. Например :
public @interface Description {
String title();
int version() default 1;
String text();
}
Пример использования аннотации Description :
@Description(title="title", version=2, text="text")
public class Sample {
// ...
}
Пример аннотации с параметрами:
import java.lang.annotation.*;
@Target(value=ElementType.FIELD)
@Retention(value= RetentionPolicy.RUNTIME)
public @interface Name
{
String name();
String type() default "string";
}
В данном примере аннотация включает в себя несколько полей (name, type), которые можно задать как обязательными, так и необязательными. В последнем случае подставляется default значение поля. Из синтаксиса аннотации следует, что саму аннотацию можно пометить несколькими параметрами. В качестве типов параметров аннотации могут использоваться только примитивные типы, перечисления и класс String. Если у аннотации нет элементов, ее называют маркером (marker annotation type). В этом случае при использовании аннотации круглые скобки можно не писать. Параметры аннотации@RetentionАннотация @Retention позволяет определить жизненный цикл аннотации : будет она присутствовать только в исходном коде, в скомпилированном файле, или она будет также видна и в процессе выполнения. Выбор нужного типа аннотации @Retention зависит от того, как будет использоваться данная аннотацию. Например, генерировать что-то побочное из исходных кодов, или в процессе выполнения "стучаться" к классу через reflection.
@TargetПараметр @Target указывает, что именно должно быть помечено аннотацией. Это может быть поле, метод, тип и т.д. Для этого следует использовать параметры к аннотации.
В случае, если необходимо, что бы аннотация использовалась больше чем для одного типа параметров, то можно указать @Target следующим образом:
@Target({ ElementType.PARAMETER, ElementType.LOCAL_VARIABLE })
В данном случае аннотацию можно использовать только для параметров метода и для локальных переменных. @Documented Параметр @Documented указывает, что помеченные таким образом аннотацией класс/метод/поле должны быть добавлены в javadoc. Например, класс, помеченный аннотацией без @Documented, будет выглядеть так: public class TestClass extends java.lang.Object А если в описание аннотации добавить @Documented, получим: @ControlledObject(name="name") public class TestClass extends java.lang.Object Использование аннотацииПредположим, нам нужно ограничить доступ к некоторым функциям веб-приложения для разных пользователей. Иными словами необходимо реализовать права (permissions). Для этого можно добавить следующее перечисление в класс пользователя:
public class User {
public static enum Permission {
USER_MANAGEMENT, CONTENT_MANAGEMENT
}
private List<Permission> permissions;
public List<Permission> getPermissions() {
return new ArrayList<Permission>(permissions);
}
// ...
}
Создадим аннотацию, которую будем использовать для проверки прав доступа :
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionRequired {
User.Permission value();
}
Предположим, что у нас есть некоторое действие, право на выполнение которого мы хотим ограничить, например, UserDeleteAction. Для этого добавляем аннотацию на это действие следующим образом:
@PermissionRequired(User.Permission.USER_MANAGEMENT)
public class UserDeleteAction {
public void invoke(User user) { /* */ }
}
Теперь используя reflection, можно принимать решение, разрешать или не разрешать выполнение определенного действия :
User user = ...;
Class<?> actionClass = ...;
PermissionRequired permissionRequired = actionClass.getAnnotation(PermissionRequired.class);
if (permissionRequired != null){
if (user != null && user.getPermissions().contains(permissionRequired.value())){
// выполнить действие
}
}
Пример анализатора аннотацииСоздадим класс анализатора, который будет определять аннотации и выполнять некоторые действия, связанные с аннотируемыми параметрами. Необходимо иметь в виду, что если используется более чем одна пользовательская аннотации, то целесообразно иметь отдельный анализатор для каждой аннотации. Что должен делать анализатор? Он использует reflection для доступа к аннотируемым данным. Пример анализатора для класса @Test:
public class AnnotationAnalyzer {
public void parse(Class<?> clazz) throws Exception {
Method[] methods = clazz.getMethods();
int pass = 0;
int fail = 0;
for (Method method : methods) {
if (method.isAnnotationPresent(Test.class)) {
try {
// вызов аннотируемого метода
method.invoke(null);
pass++;
} catch (Exception e) {
fail++;
}
}
}
}
}
Сочетание использования аннотации и reflection позволяет выполнить определенную проверку и вызвать метод на исполнение через invoke. Анализатор готов к использованию. Для использования атрибутов аннотации расширим код.
public class AnnotationAnalyzer {
public void analyze(Class<?> clazz) throws Exception {
Method[] methods = clazz.getMethods();
int pass = 0;
int fail = 0;
for (Method method : methods) {
if (method.isAnnotationPresent(Test.class)) {
// Получаем доступ к атрибутам
Test test = method.getAnnotation(Test.class);
Class expected = test.expected();
try {
method.invoke(null);
pass++;
} catch (Exception e) {
if (Exception.class != expected) {
fail++;
} else {
pass++;
}
}
}
}
}
}
После получения доступа к атрибуту аннотации определяем ее значение. В нашем случае это значение типа Class, так как expected — это ожидаемая ошибка и мы будем получать exception. Пример использования класса анализа аннотации:
public class Demo
{
public static void main(String [] args)
{
AnnotationAnalyzer analyzer = new AnnotationAnalyzer();
analyzer.analyze(MyTest.class);
}
}
|
