Base to Beyond: Guide to Spring Framework

Base to Beyond: Guide to Spring Framework

·

5 min read

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 the oldMethod.

  • 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

  1. 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.

  1. 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.

  1. 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:

  • @Test - Marks method as test case for test runner

  • @Before/@After - Execute before/after each test

  • @Ignore - Skip the test method

Type Annotations:

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 {
    // ...
}

Introducing Spring