Annotations provide metadata about the code, provide supplements to compiler, tools, framework, and don't directly affect the code allowing the extensibility of language
Let's create a custom annotation called @DeprecatedUsage
. This annotation will be used to mark methods or classes that are deprecated and should be avoided.
Step 1: Define the Annotation Interface
javaCopy codeimport java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE}) // This annotation can be applied to methods and classes
@Retention(RetentionPolicy.SOURCE) // This annotation will only be available in the source code, not at runtime
public @interface DeprecatedUsage {
String reason() default ""; // Optional reason for deprecation
}
Explanation:
We define the custom annotation
@DeprecatedUsage
.It can be applied to methods and classes (
@Target({ElementType.METHOD, ElementType.TYPE})
).It will not be available at runtime, only in the source code (
@Retention(RetentionPolicy.SOURCE)
).It has one optional element
reason()
to provide a reason for deprecation.
Step 2: Use the Custom Annotation
javaCopy code@DeprecatedUsage(reason = "This method is deprecated, use newMethod() instead")
public void oldMethod() {
// Deprecated code
}
Explanation:
We apply the
@DeprecatedUsage
annotation to theoldMethod
.We provide a reason for deprecation using the
reason
element.Annotations are categorized into three main groups:
visit git to learn how to create useful annotations.
Overview of reflection:
What is Reflection?
Reflection allows inspecting and modifying runtime behaviors of classes, interfaces, fields and methods at runtime.
It provides APIs to examine class files, retrieve class objects, inspect members and invoke methods dynamically.
Main Classes for Reflection
Class - Represents a loaded class and contains methods to get class name, package, methods, fields etc.
Field - Provides information about class variables and methods to get and set values dynamically.
Method - Represents class methods and provides APIs to invoke methods by name and pass arguments.
Constructor - Represents constructors and is used to instantiate classes dynamically.
How to Use Reflection
Get a Class instance using Class.forName() by passing the fully qualified class name.
// Get Class instance for a given class Class myClass = Class.forName("com.MyClass");
Use Class methods like getFields(), getMethods(), getConstructors() to inspect class, fields, methods.
Create instances using Constructor.newInstance() and invoke methods using Method.invoke().
Access and modify fields dynamically using Field get and set methods.
Common Use Cases
Integration with frameworks that manage objects for you like ORM tools, IoC containers etc.
Debugging and testing frameworks that need to inspect app code and data at runtime.
Meta-programming scenarios like ORM libraries populating data classes.
// Obtain Class reference
Class c = Class.forName("com.MyClass");
// Create instance
Object o = c.newInstance();
// Get all constructors
Constructor[] constructors = c.getConstructors();
// Invoke specific constructor
Object obj = constructors[0].newInstance(args);
// Get methods
Method[] methods = c.getDeclaredMethods();
// Invoke method by name
Method m = c.getMethod("methodName", paramTypes);
m.invoke(obj, args);
// Get fields
Field[] fields = c.getDeclaredFields();
// Get and set field value
Field f = c.getField("fieldName");
Object value = f.get(obj);
f.set(obj, newValue);
// Get super class and interfaces
Class superClass = c.getSuperclass();
Class[] interfaces = c.getInterfaces();
// Get annotations
Annotation[] annotations = c.getAnnotations();
// Define the annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyCustomAnnotation {
String value();
}
// Annotate a method with the custom annotation
public class MyClass {
@MyCustomAnnotation("Hello World")
public void myMethod() {
// method body
}
public static void main(String[] args) {
// Retrieve annotation value using reflection
Method m = MyClass.class.getMethod("myMethod");
MyCustomAnnotation ann = m.getAnnotation(MyCustomAnnotation.class);
System.out.println(ann.value()); //prints "Hello World"
}
}
This must straighten it out. visit git for more
Annotations are categorized into three main groups:
Marker, Single-Value, Multi-Value Annotations
Marker Annotations: Used to provide metadata but without any parameters.
@Override - Indicates that a method overrides a superclass method.
@Deprecated - Marks a class, method etc. as deprecated.
- Single Value Annotations: Take one parameter/value.
@SuppressWarnings("unchecked") - Suppress specified warning.
all, unchecked, deprecation, rawtypes, serial, finally, try, unused, cast, boxing, varargs, fallthrough, null, and resource are some of parameters.
@Retention(RetentionPolicy.RUNTIME) - Specifies retention policy.
- Multi Value Annotations: Allow multiple parameters.
@Author({"John", "Jane"}) - Specify multiple authors.
@RolesAllowed({"Admin", "Manager"}) - Allow multiple roles
@MarkerAnnotation
void myMethod(){
}
@SingleValueAnnotation("SomeValue")
void method2() {
}
@MultiValueAnnotation(value1 = "foo", value2 = "bar")
void method3() {
}
Lets look into some common annotation in core java
Annotations categorized by usage:
Compiler Annotations:
@Override - Checks method is overriding superclass method
@SuppressWarnings - Suppress compiler warnings
@Deprecated - Marks element is deprecated and discouraged
@Native: method is implemented in a platform-dependent manner.
@Inherited: annotation is inherited by subclasses.
@FunctionalInterface: the interface is intended to be a functional interface, only one abstract method is allowed.
Build/Testing Annotations:
Type Annotations:
@NonNull - Indicates parameter/return value won't be null
@Nullable - Indicates field/parameter may be null
Meta Annotations:
@Target - Applies an annotation to elements
@Retention - Specifies how long annotation is retained
@Documented - Annotation included in javadoc
ElementType.TYPE: Can be applied to a class, interface, enum, or annotation.
ElementType.FIELD: applied to field or property.
ElementType.METHOD: applied to a method.
ElementType.PARAMETER: applied to a method parameter.
ElementType.CONSTRUCTOR: applied to a constructor.
ElementType.LOCAL_VARIABLE:applied to a local variable.
ElementType.ANNOTATION_TYPE: for annotation type.
ElementType.PACKAGE: applied to a package
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyTargetAnnotation {
// ...
}
The @Retention annotation specifies how long an annotation is retained.
RetentionPolicy.SOURCE: only available in the source code and is not included for compiled bytecode.
RetentionPolicy.CLASS: included in the compiled bytecode not at runtime through reflection.
RetentionPolicy.RUNTIME: included in the compiled bytecode AND is available at runtime through reflection.
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRetentionAnnotation {
// ...
}