Search code examples
spring-bootmodularitycomponent-scan

find package name - Spring Boot library


I'm making a library to be used with Spring Boot. This lib define some annotations that can be used in methods.

How can I find (at runtime) the package of the application where the library is being used?
I need this in order to scan for the annotated methods.


Solution

  • You can implement BeanFactoryPostProcessor:
    1. Using ConfigurableListableBeanFactory you can iterate over BeanDefinition
    2. Determine if bean's class has your annotation
    3. Get the package from the bean's class name

    Example:

    @Component
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            Set<String> packages = findAnnotationUsagePackages(MyAnnotation.class, beanFactory);
            ...
        }
    
        private Set<String> findAnnotationUsagePackages(Class<? extends Annotation> annotationClass,
                                                        ConfigurableListableBeanFactory beanFactory) {
            Set<String> annotationUsagePackages = new HashSet<>();
    
            for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
    
                if (beanDefinition instanceof ScannedGenericBeanDefinition) {
                    ScannedGenericBeanDefinition genericBeanDefinition = (ScannedGenericBeanDefinition) beanDefinition;
    
                    if (AnnotationUtils.isCandidateClass(genericBeanDefinition.getBeanClass(), annotationClass)) {
                        String beanClassName = genericBeanDefinition.getBeanClassName();
    
                        if (beanClassName != null) {
                            annotationUsagePackages.add(ClassUtils.getPackageName(beanClassName));
    
                        }
                    }
                }
            }
            return annotationUsagePackages;
        }
    
    }
    

    About the AnnotationUtils.isCandidateClass():

    Determine whether the given class is a candidate for carrying the specified annotation (at type, method or field level)

    Also pay attention to the AbstractBeanDefinition.getBeanClass():

    Throws: IllegalStateException - if the bean definition does not define a bean class, or a specified bean class name has not been resolved into an actual Class yet

    P.S. also you can collect classes or meta-information inside AnnotationUtils.isCandidateClass condition block