Руководство Java Annotation

View more Tutorials:

1- Что такое Annotation и цель использования

Annotation (Аннотация) используется для предоставления метаданных для вашего Java кода. Как метаданные, Annotation не влияют напрямую на выполнение ваших кодов, несмотря на то, что некоторые аннотации могут быть реально использованы с той целью.  Annotation добавлен в  Java, начиная с Java 5
Annotation используются с целью:
  1. Инструкция для компилятора (Compiler)
  2. Инструкция во время построения (Build-time)
  3. Инструкция во время запуска (Runtime)

1.1- Инструкция для компилятора

Java имеет 3 Annotation, которые вы можете использовать для предоставления инструкций для компилятора Java.
  • @Deprecated
  • @Override
  • @SuppressWarnings
Эти Annotation объяснены более детально в данной статье.

1.2- Интструкция по времени построения (Build-time)

Annotation может быть использован во время построения (Build-time), когда вы строите ваш проект программного обеспечения. Процесс построения включает создание исходных кодов, компиляции исходных кодов создание файлов XML (например дескрипторы развертывания), упаковка скомпилированного кода и файлов в один файл JAR, и т.д. Построение программного обеспечения обычно выполняется автоматическим инструментом строения как Apache Ant или Apache Maven . Строение инструментов, которые могут сканировать ваш код Java и в зависимости от ваших аннотаций (Annotation) создать исходный код или другие файлы на основании этих аннотаций.

1.3- Инструкция по времени запуска (Runtime)

Обчычно, Annotation не присутствуют в вашем коде Java после компиляции. Но можно определить ваши Annotation во время запуска. Эти аннотации потом могут быть доступны через  Java Reflection, и использоваться для инструкции ваших программ, или API третьей стороны (Third party API).
Смотрите так же:

2- Готовые Annotation в Java

Имеются  3 важных Annotation в Java
  • @Deprecated
  • @Override
  • @SuppressWarnings

2.1- @Deprecated

Это Annotation использующийся для аннотации чего-то устаревшего, как класс или метод, который не стоит больше использовать.
Аннотация  @Deprecated компилятор интересуется, чтобы оповестить вас об альтернативе. Или с программированием IDE, например  Eclipse так же показывает вам визуальные оповещения.
DeprecatedMethodDemo.java
package org.o7planning.tutorial.ann.builtin;

import java.util.Date;

public class DeprecatedMethodDemo {

  /**
   * @deprecated replaced by {@link #todo(String,Date)}
   */
  @Deprecated
  public void todoJob(String jobName) {
      System.out.println("Todo " + jobName);
  }

  public void todo(String jobName, Date atTime) {
      System.out.println("Todo " + jobName + " at " + atTime);
  }

  public void todoNothing() {
      System.out.println("Todo Nothing");
  }

  public static void main(String[] args) {

      DeprecatedMethodDemo obj = new DeprecatedMethodDemo();

      obj.todoJob("Java coding");

      obj.todoNothing();
  }
}
В следующей иллюстрации  Eclipse оповещает вас:

2.2- @Override

Annotation @Override используется для методов, которые переопределяют метод в суперклассе (superclass). Если данный метод не соответствует методу в суперклассе, компилятор оповестит вас об ошибке.

Annotation @Override не обязателен чтобы переопределить метод суперкласса. Все же это хорошая идея для использования. В случае, если кто-то изменил название метода супекласса, метод в вашем классе больше не будет переопределенным методом. При отсутствии аннотации @Override вы не найдете. С аннотациями  @Override компилятор оповестит вас о том, что методы подкласса не переопределяют методы в суперклассе. 
Смотрите пример:
Job.java
package org.o7planning.tutorial.ann.builtin;

public class Job {

	// Это метод класса Job.
	public String getName() {
		return null;
	}

}
JavaCoding.java
package org.o7planning.tutorial.ann.builtin;

public class JavaCoding extends Job {

	// Это метод, который переопределяет метод getName() родительского класса.
	// @Override не обязан быть прикрепленным к этому методу.
	// Но необходим если кто-то менят название метода getName()
	// родительского класса, для вас будет оповещение об ошибке.
	@Override
	public String getName() {
		return "Java Coding";
	}

}
И это оповещение  Java Compiler:

2.3- @SuppressWarnings

Аннотация  @SuppressWarnings заставляет компилятор останавливать предупреждения определенного метода. Например, метод вызывает устаревший метод, или внутри метода есть небезопасный вид, компилятор может создать предупреждение. Вы можете отключить эти предупреждения аннотацией данного метода используя  @SuppressWarnings.
Смотрите пример:
SuppressWarningsDemo.java
package org.o7planning.tutorial.ann.builtin;

import java.util.Date;

public class SuppressWarningsDemo {

  @SuppressWarnings("deprecation")
  public Date getSomeDate() {

      Date date = new Date(2014, 9, 25);
      return date;
  }

}
Смотрите предупреждения компилятора:
 
SuppressWarningsDemo2.java
package org.o7planning.tutorial.ann.builtin;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class SuppressWarningsDemo2 {

	public List<?> getDatas() {
		List<String> list = new ArrayList<String>();
		list.add("One");
		return list;
	}

	@SuppressWarnings({ "deprecation", "unused", "unchecked" })
	public void processDatas() {

		// Вы используете устаревший конструктор
		// И переменная 'date' создана, но не используется.
		Date date = new Date(2014, 9, 25);

		// Сделать небезопасный cast.
		// Переменная 'datas' создана, но не используется в коде.
		List<String> datas = (List<String>) this.getDatas();
	}

}
Предупреждения компилятора:

3- Напишите ваш Annotation

Используя  @interface как ключевое слово объявления Annotation, annotation довольно похож на интерфейс. Annotation содержит или не содержить элементы (elements) внутри.
Характеристики элементов (element) annotation:
  • Нет функциональной основы
  • Нет функционального параметра
  • Возвращенное объявление должно быть определенного вида:
    • Примитивный вид (boolean, int, float, ...)
    • Enum
    • Annotation
    • Class (Например: String.class)
  • Может иметь значение по умолчанию 

3.1- Ваш первый Annotation 

MyFirstAnnotation.java
package org.o7planning.tutorial.ann1;

public @interface MyFirstAnnotation {

	// Элемент 'name'.
	public String name();

	// Элемент 'description', со значением по умолчанию "".
	public String description() default "";

}
Annotation может использоваться на:
  1. TYPE - Прикрепленный на объявлении Class, interface, enum, annotation.
  2. FIELD - Прикрепленный на объявлении поля (field), включая констанции enum.
  3. METHOD - Прикрепленный на объявлении method.
  4. PARAMETER - Прикрепленный на объявлении parameter
  5. CONSTRUCTOR - Прикрепленный на объявлении конструктора
  6. LOCAL_VARIABLE - Прикрепленный на локальной переменной.
  7. ANNOTATION_TYPE - Прикрепленный на объявлении Annotation
  8. PACKAGE - Прикрепленный на объявлении package.
UsingMyFirstAnnotation.java
package org.o7planning.tutorial.ann1;

@MyFirstAnnotation(name = "Some name", description = "Some description")
public class UsingMyFirstAnnotation {

	// Annotation (Аннотация) прикреплена к Constructor (Конструктору).
	// Со значением элемента name "John"
	// Значение элемента description является "Write by John".
	@MyFirstAnnotation(name = "John", description = "Write by John")
	public UsingMyFirstAnnotation() {

	}

	// Annotation được gắn trên một phương thức.
	// Со значением элемента 'name' "Tom"
	// Элемент 'description' не объявлен, он будет взят по умолчанию.
	@MyFirstAnnotation(name = "Tom")
	public void someMethod() {

	}

	// Annotation прикреплена к параметру одного метода.
	public void todo(@MyFirstAnnotation(name = "none") String job) {

		// Annotation прикреплена к локальной переменной.
		@MyFirstAnnotation(name = "Some name")
		int localVariable = 0;

	}

}

3.2- Annotation с элементом value. (Особенный)

Annotation имеет элемент с названием value, который имеет особенные характеристики:
AnnWithValue.java
package org.o7planning.tutorial.ann2;

public @interface AnnWithValue {

	// Элемент с названием 'value', Аннотации.
	// Имеет некоторую особенность при использовании данного элемента.
	public int value();

	// Элемент 'name'
	public String name() default "";

}
UsingAnnWithValue.java
package org.o7planning.tutorial.ann2;

public class UsingAnnWithValue {

	// Генерировать элементы Аннотации обычным способом.
	@AnnWithValue(name = "Name1", value = 100)
	public void someMethod1() {

	}

	// Генерировать элементы Аннотации обычным способом.
	// Элемент 'name' Аннотации будет иметь значение по умолчанию
	@AnnWithValue(value = 100)
	public void someMethod2() {

	}

	// Элемент с названием 'value' является особенным.
	// Вместо @AnnWithValue(value = 100)
	// Вам нужно написать только @AnnWithValue(100)
	@AnnWithValue(100)
	public void someMethod3() {

	}
}

3.3- @Retention & @Target

@Retention & @Target это 2 готовые annotation в  Java.

@Retention

@Retention: Используется для примечания уровня существования любого nnotation.
В частности, есть 3 уровня распознания существования предмета с примечанием:
  1. RetentionPolicy.SOURCE: Существует на исходном коде, и не узнаваем компилятором (compiler).
  2. RetentionPolicy.CLASS: Компилятер разпознает существование, но не распознается виртуальной машиной при запуске (Runtime).
  3. RetentionPolicyRUNTIME: достигает высшую степень существования, разпознается компилятором (compiler), и распознается существование виртуальной машиной при запуске.

@Target

@Target: Используется для примечания другого annotation, и в каких сферах тот annotation будет использоваться.
  1. ElementType.TYPE - Прикреплен на объявлении Class, interface, enum, annotation.
  2. ElementType.FIELD - Прикреплен на объявлении поля (field), включая константы enum.
  3. ElementType.METHOD - Прикреплен на объявлении method.
  4. ElementType.PARAMETER - Прикреплен на объявлении parameter
  5. ElementType.CONSTRUCTOR - Прикреплен на объявлении конструктора
  6. ElementType.LOCAL_VARIABLE - Прикреплен на объявлении локальной переменной.
  7. ElementType.ANNOTATION_TYPE - Прикреплен на объявлении Annotation
  8. ElementType.PACKAGE - Прикреплен на объявлении package.
AnnFM.java
package org.o7planning.tutorial.ann3;

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

// Данная аннотация (Annotation) говорит, что AnnFM только распознается на исходном коде.
// Он не будет распознан компилятором (compiler),
// и во время запуска виртуальной машины, так же не будет знать о его существовании.
@Retention(value = RetentionPolicy.SOURCE)

// Данная аннотация (Annotation) говорит:
// AnnFM будет использован только как аннотация (annotate) на FIELD или METHOD.
@Target(value = { ElementType.FIELD, ElementType.METHOD })
public @interface AnnFM {

}
UsingAnnFM.java
package org.o7planning.tutorial.ann3;

public class UsingAnnFM {

	// AnnFM может только аннотировать (annotate) на FIELD или METHOD.
	@AnnFM
	protected int someField = 100;

	// AnnFM может только аннотировать (annotate) на FIELD или METHOD.
	@AnnFM
	public void someMethod() {

	}

}

3.4- Annotation & Reflection

Примечание: Если вы только начали изучать Java, вы можете пропустить этот пункт, так как он требует общее знание, и пока не нужно изучать.

Java Reflection может определить такие вещи как (Class, field, method, ..) аннотированный используя некоторый  Annotation. И конечно же, он распознает  Annotation имеющие  @Retention(RetentionPolicy.RUNTIME)
Смотрите так же:
Пример ниже описывет программу, которая читает аннотации в файлах Java и создает файлы Html. Каждый class соответствует файлу html.
AnnHtmlUL.java
package org.o7planning.tutorial.ann4;

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

@Retention(RetentionPolicy.RUNTIME)

// Данная аннотация (Annotation) говорит:
// AnnHtmlUL используется только для Class, interface, annotation, enum.
@Target(value = { ElementType.TYPE })

// AnnHtmlUL: Симулирует тег (tag) <UL> в HTML.
public @interface AnnHtmlUL {

	public String border() default "border:1px solid blue;";
	
}
AnnHtmlLI.java
package org.o7planning.tutorial.ann4;

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

@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD })

// Симулирует тег  (tag) <LI> в HTML.
public @interface AnnHtmlLI {

	public String background();

	public String color() default "red";
	
}
DocumentClass.java
package org.o7planning.tutorial.ann4;

@AnnHtmlUL(border = "1px solid red")
public class DocumentClass {

	private String author;

	@AnnHtmlLI(background = "blue", color = "black")
	public String getDocumentName() {
		return "Java Core";
	}

	@AnnHtmlLI(background = "yellow")
	public String getDocumentVersion() {
		return "1.0";
	}

	@AnnHtmlLI(background = "green")
	public void setAuthor(String author) {
		this.author = author;
	}

	@AnnHtmlLI(background = "red", color = "black")
	public String getAuthor() {
		return author;
	}
	
	// Этот метод не аннотирован никакой аннотацией (Annotation).
	public float getPrice()  {
		return 100;
	}

}
HtmlGenerator.java
package org.o7planning.tutorial.ann4;

import java.lang.reflect.Method;

public class HtmlGenerator {

	public static void main(String[] args) {

		Class<?> clazz = DocumentClass.class;

		// Проверить аннотирован (annotate) ли класс с помощью AnnHtmlUL или нет.
		boolean isHtmlUL = clazz.isAnnotationPresent(AnnHtmlUL.class);

		StringBuilder sb = new StringBuilder();
		if (isHtmlUL) {

			// Получить объект AnnHtmlUL, аннотированный на данном классе.
			AnnHtmlUL annUL = clazz.getAnnotation(AnnHtmlUL.class);

			sb.append("<H3>" + clazz.getName() + "</H3>");
			sb.append("\n");

			// Получить значение элемента 'border' в AnnHtmlUL.
			String border = annUL.border();

			sb.append("<UL style='border:" + border + "'>");

			// Добавить новую строку.
			sb.append("\n");

			Method[] methods = clazz.getMethods();

			for (Method method : methods) {
				// Проверить аннотирован (annotate) ли данный метод с помощью AnnHtmlLI или нет?
				if (method.isAnnotationPresent(AnnHtmlLI.class)) {
					// Получить ту аннотацию (annotation).
					AnnHtmlLI annLI = method.getAnnotation(AnnHtmlLI.class);

					// Получить значение элементов AnnHtmlLI.
					String background = annLI.background();
					String color = annLI.color();

					sb.append("<LI style='margin:5px;padding:5px;background:" + background + ";color:" + color + "'>");
					sb.append("\n");
					sb.append(method.getName());
					sb.append("\n");
					sb.append("</LI>");
					sb.append("\n");
				}
			}
			sb.append("</UL>");
		}
		writeToFile(clazz.getSimpleName() + ".html", sb);
	}

	// Записать информацию на экран Console (Или файл).
	private static void writeToFile(String fileName, StringBuilder sb) {
		System.out.println(sb);
	}

}
Результаты запуска примера:
Случай записи файла html:

4- Annotation Processing Tool (Знания повышенного уровня)

The situation is that:

Вы создаете ваш  Annotation и используете их в вашем приложении Java. Эти  Annotation имеют правило использования данное вами. Вы хотите, чтобы компилятор Java оповещал ошибку при неправильном использовании во время компиляции. И если вы используете  Eclipse чтобы написать код,  Eclipse оповещает об ошибке прямо на  IDE.

Это вполне возможно с  APT ( Annotation Processing Tool).
Вы можете посмотреть инструкцию  APT по ссылке:

View more Tutorials: