Make your own Java Annotations

What’s the use of Annotations?

The first question that comes into our mind is what’s the use case of annotations and why it is consider as a powerful part of Java. Annotations have a number of uses, among them:

  • Information for the compiler — There are three built-in annotations available in Java (@Deprecated@Override & @SuppressWarnings) that can be used for giving certain instructions to the compiler. For example, the @Override annotation is used for instructing compiler that the annotated method is overriding the method.

 @FunctionalInterface annotation, introduced in Java SE 8, indicates that the type declaration is intended to be a functional interface, as defined by the Java Language Specification.

  • Compile-time and deployment-time processing — Software tools can process annotation information to generate code, XML files, and so forth.
  • Runtime processing — We can define annotations to be available at runtime which we can access using java reflection and can be used to give instructions to the program at runtime.

Creating Custom Annotations

  • Annotations are created by using @interface, followed by annotation name as shown in the below example.
  • An annotation can have elements as well. They look like methods. For example in the below code, we have six elements. We should not provide implementation for these elements.
  • All annotations extends java.lang.annotation.Annotation interface. Annotations cannot include any extends clause.
@interface ClassInfo {
   String author();
   String date();
   int currentRevision() default 1;
   String lastModified() default "N/A";
   String lastModifiedBy() default "N/A";
   // Note use of array
   String[] reviewers();
}

Note: All the elements that have default values set while creating annotations can be skipped while using annotation and we can also have array elements in an annotation. For example if I’m applying the above annotation to a class then I would do it like this:

@ClassInfo(
    author="TheCodersStop",
    date = "05-10-2020"
    reviewers={"Me", "You"}
)
public class AnyClass {

}

As you can see, we have not given any value to the currentRevision , lastModified and lastModifiedBy elements as it is optional to set the values of these elements (default values already been set in Annotation definition, but if you want you can assign new value while using annotation just the same way as we did for other elements). However we have to provide the values of other elements (the elements that do not have default values set) while using annotation.

Annotations That Apply to Other Annotations

Annotations that apply to other annotations are called meta-annotations. There are several meta-annotation types defined in java.lang.annotation.

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface StudentAnnotation{
    int studentAge() default 15;
    String studentName();
    String studentAddress();
    String studentStream() default "PCM";
}

In the above custom annotation example we have used these four annotations :  @Documented,  @Target,  @Inherited &  @Retention. Lets discuss them one by one.

@Documented

@Documented annotation indicates that whenever the specified annotation is used those elements should be documented using the Javadoc tool. (By default, annotations are not included in Javadoc.) For more information, see the Javadoc tools page.

@StudentAnnotation
public class AnyClass { 
     //Class body
}

So while generating the javadoc for class AnyClass, the annotation @MyCustomAnnotation would be included in that.

@Target

@Target annotation marks another annotation to restrict what kind of Java elements the annotation can be applied to. In our case, we have defined the target type as METHOD which means the below annotation can only be used on methods.

public class AnyClass {
   @StudentAnnotation
   public void anyMethod()
   {
       //Doing something
   }
}

If you do not define any Target type that means annotation can be applied to any element. A target annotation specifies one of the following element types as its value:

  • ElementType.ANNOTATION_TYPE can be applied to an annotation type.
  • ElementType.CONSTRUCTOR can be applied to a constructor.
  • ElementType.FIELD can be applied to a field or property.
  • ElementType.LOCAL_VARIABLE can be applied to a local variable.
  • ElementType.METHOD can be applied to a method-level annotation.
  • ElementType.PACKAGE can be applied to a package declaration.
  • ElementType.PARAMETER can be applied to the parameters of a method.
  • ElementType.TYPE can be applied to any element of a class.
@Inherited

The @Inherited annotation indicates that a custom annotation used in a class should be inherited by all of its sub classes. This is not true by default.

@StudentAnnotation
public class AnyParentClass { 
  ... 
}
public class AnyChildClass extends AnyParentClass { 
   ... 
}

Here the class AnyParentClass is using annotation @StudentAnnotation which is marked with @inherited annotation. It means that the sub class AnyChildClass inherits the @AnyCustomAnnotation.

@Retention

@Retention annotation specifies how the marked annotation is stored:

  • RetentionPolicy.SOURCE – The marked annotation is retained only in the source level and is ignored by the compiler.
  • RetentionPolicy.CLASS – The marked annotation is retained by the compiler at compile time, but is ignored by the Java Virtual Machine (JVM).
  • RetentionPolicy.RUNTIME – The marked annotation is retained by the JVM so it can be used by the runtime environment.
@Repeatable

 @Repeatable annotation, introduced in Java SE 8, indicates that the marked annotation can be applied more than once to the same declaration or type use. For more information, see Repeating Annotations.

I hope you have enjoyed this post and it helped you to create a custom Java annotation. Please like and share and feel free to comment if you have any suggestions or feedback.

Tagged : / /

JUnit Annotations with Example

Introduction

Annotations were introduced in Junit4, which makes Java code more readable and simple. This is the big difference between Junit3 and Junit4 that Junit4 is annotation based.

JUnit5 is the next generation of JUnit. The goal is to create an up-to-date foundation for developer-side testing on the JVM. This includes focusing on Java 8 and above, as well as enabling many different styles of testing.With the knowledge of annotations in JUnit5, one can easily learn and implement a JUnit test.

JUnit offers integration with CI/CD tools such as Jenkins, Teamcity etc. to help you create a sturdy delivery pipeline.

Basic Java Annotations

So here are some basic JUnit annotation that are mostly used and required for unit testing :

  • @Test – This is the test method to run, public void
  • @BeforeClass – This annotation is used if you want to execute some statements before all the test cases for e.g. test connection must be executed before all the test cases., public static void
  • @AfterClass – This annotation can be used if you want to execute some statements after all test cases for e.g. Releasing resources after executing all test case, public static void
  • @Before – This annotation is used if you want to execute some statement such as preconditions before each test case, public void
  • @After – This annotation can be used if you want to execute some statements after each Test Case for e.g resetting variables, deleting temporary files ,variables, etc, public void

A simple example will help us to understand the working of JUnit annotations.

Java Class to be tested

We are going to use a simple example regarding Account balance where we want to perform our unit testing.

package com.thecodersstop.junit;
 
public class Account {
    private double bal;
 
    public Account(double bal) {
        this.bal = bal;
    }
 
    public double getBal() {
        return bal;
    }
 
    public void setBal(double bal) {
        this.bal = bal;
    }
 
    public void withdraw(double withdrawAmount) {
        this.bal = bal - withdrawAmount;
    }
 
    public void deposit(double depositAmount) {
        this.bal = bal + depositAmount;
    }
}

Junit Test Cases

Here we have our test cases for the Account java class. This test class includes all the basic annotations mentioned above.

package com.thecodersstop.junit;

import org.junit.*;
 
public class AccountTest extends Assert {
    private Account account;
    private static double bal;
 
    @BeforeClass
    public static void BeforeClass() {
		// Code executed before the first test method
        bal = 100;
        System.out.println("Before Class");
    }
 
    @Before
    public void beforeTest() throws Exception {
		// Code executed before each test
        account = new Account(bal);
    }
 
    @Test
    public void testCase1() {
        Assert.assertEquals("Test balance", account.getBal(), bal, 0);
        System.out.println("Test balance. Balance: " + account.getBal());
    }
 
    @Test
    public void testCase2() {
        account.deposit(10);
        Assert.assertEquals("Test deposit", account.getBal(), bal, 10);
        System.out.println("Test deposit. Balance: " + account.getBal());
    }
 
    @Test
    public void testCase3() {
        account.withdraw(30);
        Assert.assertEquals("Test withdraw", account.getBal(), bal, 30);
        System.out.println("Test withdraw. Balance: " + account.getBal());
    }
 
    @After
    public void afterTest() throws Exception {
		// Code executed after each test
        account = null;
        System.out.println("refresh");
    }
 
    @AfterClass
    public static void AfterClass() {
		// Code executed after the last test method
        balance = 0;
        System.out.println("After Class");
    }
}

Run the JUnit Test Cases

Here is the output of our test cases. As we can see, the sequence of the executed test methods, complies with what we described in the starting. This JUnit test is fully passed.

Before Class
Test balance. Balance: 100.0
refresh
Test deposit. Balance: 110.0
refresh
Test withdraw. Balance: 70.0
refresh
After Class

JUnit offers integrations with IDEs such as Eclipse, IntelliJ etc. so you could test run your code quickly and easily.

Execution Sequence of JUnit Annotations

Here is a basic process flowchart of JUnit annotations that will help you to understand the flow, step by step.

@Ignores – This annotation can be used if you want to ignore some statements during test execution for e.g. disabling some test cases during test execution.

I hope you have enjoyed this post and it helped you to understand the basics of JUnit annotations. Please like and share and feel free to comment if you have any suggestions or feedback.

Tagged : / /
%d bloggers like this: