Custom Annotation Scanning with Spring Boot
Tags: java, annotation, spring, tutorial
Published: 2021-10-13 04:31:08

In `Java` programming language, `annotation` offers a super way for supplying meta information about our code. These meta information can be used by frameworks to decide the functionality of that particular feature. When you design a module or a feature, you can define your own annotations and your feature can use it to achieve the functionalities similar to the existing frameworks

The information in the annotaion is made available to the runtime of the code in 2 ways.

1. Using `annotation processor`. Annotation Processors are called by java compiler to process the information given at the AnnotatedElements to generate new Java source files or other meta-data
2. Scanning the annotations during the JVM startup and using Java reflection, the `AnnotatedElement`s can be identified and we can create meta models accordingly.

This article deals with the 2nd way of scanning the annotated classes from the classpath or methods or variables in the runtime and using it for our feature.

There are libraries like [classgraph](https://github.com/classgraph/classgraph) that can be used in java applications that do not use `spring framework`. If your application do not use spring framework or spring boot, you can refer to the [classgraph](https://github.com/classgraph/classgraph) library documentation and proceed.

If your application uses spring framework, then you can use the below snippet and get the list of classes that have been annotated with a particular annotation

If your custom annotation is `@MyCustomAnnotation`, you can find all the classes which are annotated with annotation `@MyCustomAnnotation`using the below function call

`findAnnotatedClasses(MyCustomAnnotation.class, "com.abc.def.xyz")`

The packages list is given as varargs as it would enable neat code in the calling places.

The implementation of `findAnnotatedClasses()` method is given below. The class `ClassPathScanningCandidateComponentProvider` of spring framework does the magic of scanning the entire classpath and returns us the Bean classes which have the annotation `@MyCustomAnnotation.`

For spring framework to scan your class that has your custom annotation `@MyCustomAnnotation,`

your class must be annotated with `@Component` or the other spring annotations that make your class a managed component of Spring.

```java
public Set<String> findAnnotatedClasses(Class<? extends Annotation> annotationType, String... packagesToBeScanned)
{
    ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
    provider.addIncludeFilter(new 
    AnnotationTypeFilter(annotationType));
    
    Set<String> ret = new HashSet<>();
    
    for (String pkg : packagesToBeScanned)
    {
         Set<BeanDefinition> beanDefs = provider.findCandidateComponents(pkg);
         beanDefs.stream()
             .map(BeanDefinition::getBeanClassName)
             .forEach(ret::add);
    }
    
    return ret;
}
```

Spring Application's main class below shows how to call this method.

```java
@SpringBootApplication
public class SpringApp implements CommandLineRunner
{
    @Autowired
    private ClassScanner classScanner;

    public static void main(String[] args)
    {
        SpringApplication.run(SpringApp.class, args);
    }

    @Override
    public void run(String... args) throws Exception
    {
        Set<String> annotatedClasses = classScanner.findAnnotatedClasses(MyCustomAnnotation.class, "xyz.reachadi");

        for (String c : annotatedClasses)
            System.out.println("Annotated Class : " + c);
    }
}
```

The approach is very simple..... right?

So, what next? Enhance your codes' readability by defining custom annotations and using them on your codes.

The full working example of this blog is available in my [github repository.](https://github.com/adithyank/tutorials/tree/main/spring-boot-tutorials/custom-annotation-scanner)

Please refer to `readme.md` for instructions on running the tutorial.