Understanding Java Annotations: Concepts, Built‑in Annotations, Custom Annotations, and a Simple Test Framework
This article explains the purpose and syntax of Java annotations, describes built‑in annotations such as @Override, @Deprecated and @SuppressWarnings, shows how to create and use custom annotations with meta‑annotations, and demonstrates a lightweight testing framework that records annotation‑driven test failures.
Concept
Concept: describes the program for the computer.
Comment: textual description for developers.
Definition: An annotation (metadata) introduced in JDK 1.5, can be placed on packages, classes, fields, methods, local variables, parameters, etc., to provide additional information.
Purpose
Purpose categories:
Documentation generation: generate docs from annotated code.
Code analysis: use reflection to analyze code based on annotations.
Compilation checks: enable compiler checks such as @Override.
Predefined Annotations in JDK
@Override: checks whether the annotated method overrides a method from a superclass or interface.
@Deprecated: marks the annotated element as outdated.
@SuppressWarnings: suppresses compiler warnings, e.g., @SuppressWarnings("all") .
Annotation Documentation Generation Example
Example API class for generating Javadoc:
/**
* 注解javadoc演示
*
* @author zjq
* @version 1.0
* @since 1.5
*/
public class AnnoDoc {
/**
* 计算两数的和
* @param a 整数
* @param b 整数
* @return 两数的和
*/
public int add(int a, int b) {
return a + b;
}
}Run the following command in the class directory:
javadoc AnnoDoc.javaAfter execution, many HTML and JS files are generated; opening index.html shows the documentation.
Custom Annotations
Format
Meta‑annotation example:
public @interface 注解名称{
属性列表;
}Essence
A custom annotation is essentially an interface that implicitly extends Annotation :
public interface MyAnno extends java.lang.annotation.Annotation {}Attributes: Abstract Methods in Interface
Requirements:
Attribute return types can be primitive, String, enum, annotation, or arrays of these types.
If a default value is provided, the attribute can be omitted when using the annotation.
If there is a single attribute named value , the name can be omitted.
Array values are enclosed in {} ; braces can be omitted for a single element.
Example
public @interface MyAnno {
int value();
Person per();
MyAnno2 anno2();
String[] strs();
}
public enum Person {
P1, P2;
}Usage:
@MyAnno(value=12, per=Person.P1, anno2=@MyAnno2, strs="bbb")
public class Worker {}Meta‑annotations
@Target : specifies where the annotation can be applied (TYPE, METHOD, FIELD, etc.).
@Retention : defines the retention policy, e.g., @Retention(RetentionPolicy.RUNTIME) keeps the annotation in the bytecode for runtime reflection.
@Documented : indicates whether the annotation should appear in Javadoc.
@Inherited : determines if the annotation is inherited by subclasses.
Using Annotations for Reflection
Previously, configuration files were read to create objects and invoke methods. The following code shows the traditional approach:
// Load properties file
Properties pro = new Properties();
InputStream is = ReflectTest.class.getClassLoader().getResourceAsStream("pro.properties");
pro.load(is);
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
// Load class, create instance, invoke method
Class cls = Class.forName(className);
Object obj = cls.newInstance();
Method method = cls.getMethod(methodName);
method.invoke(obj);We can replace this with an annotation:
/**
* 描述需要执行的类名,和方法名
* @author zjq
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
String className();
String methodName();
}Parsing the annotation:
@Pro(className = "com.zjq.javabase.base25.annotation.Demo1", methodName = "show")
public class ReflectTest {
public static void main(String[] args) throws Exception {
// Get annotation
Pro an = ReflectTest.class.getAnnotation(Pro.class);
String className = an.className();
String methodName = an.methodName();
// Load class, create object, invoke method
Class cls = Class.forName(className);
Object obj = cls.newInstance();
Method method = cls.getMethod(methodName);
method.invoke(obj);
}
}Example: Simple Test Framework Using Custom Annotation
Define a test annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {}Define a calculator class with methods annotated by @Check :
/**
* 小明定义的计算器类
* @author zjq
*/
public class Calculator {
@Check
public void add() {
String str = null;
str.toString(); // will cause NullPointerException
System.out.println("1 + 0 =" + (1 + 0));
}
@Check
public void sub() { System.out.println("1 - 0 =" + (1 - 0)); }
@Check
public void mul() { System.out.println("1 * 0 =" + (1 * 0)); }
@Check
public void div() { System.out.println("1 / 0 =" + (1 / 0)); }
public void show() { System.out.println("永无bug..."); }
}Test framework that runs all @Check methods and records failures to bug.txt :
/**
* 简单的测试框架
* 当主方法执行后,会自动检测所有标有Check注解的方法,记录异常到文件中
* @author zjq
*/
public class TestCheck {
public static void main(String[] args) throws IOException {
Calculator c = new Calculator();
Class cls = c.getClass();
Method[] methods = cls.getMethods();
int number = 0;
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for (Method method : methods) {
if (method.isAnnotationPresent(Check.class)) {
try {
method.invoke(c);
} catch (Exception e) {
number++;
bw.write(method.getName() + " 方法出异常了");
bw.newLine();
bw.write("异常的名称:" + e.getCause().getClass().getSimpleName());
bw.newLine();
bw.write("异常的原因:" + e.getCause().getMessage());
bw.newLine();
bw.write("--------------------------");
bw.newLine();
}
}
}
bw.write("本次测试一共出现 " + number + " 次异常");
bw.flush();
bw.close();
}
}Resulting bug.txt content after execution:
add 方法出异常了
异常的名称:NullPointerException
异常的原因:null
--------------------------
div 方法出异常了
异常的名称:ArithmeticException
异常的原因:/ by zero
--------------------------
本次测试一共出现 2 次异常Summary
Most of the time we use built‑in annotations rather than creating custom ones.
Annotations are not part of the program logic; they act as metadata tags.
Who uses annotations?
Compilers
Runtime processing tools
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.