Hesk
Hesk

Reputation: 327

Spring - Create bean based on Annotation field

UPDATE: I used a different approach for my problem.

Side-Question: I would like to know how spring does it with the exclude in SpringBootApplication

The SpringBootApplication:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {

So when the context is loaded, and the EnableAutoConfiguration is executed, the excludes are available.

Thats the same what i want.

At Bean-Creation i want to know if an Annotation has some field (for example boolean)

Old Question:

I have an Annotation:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(TaskSpringContext.class)
public @interface TaskTest
{
    Class<? extends DatabaseService> db() default DatabaseService.class;
}

This Annotation is used at:

@TaskTest(db = DatabaseServiceExtended.class)
@SpringBootApplication()
public class TaskServer
{

    public static void main(String[] args)
    {
        final ApplicationContext ctx = SpringApplication.run(TaskServer.class, args);
    }

}

Now, at TaskSpringContext.class i want to create a bean based on the db-Field of the TaskTest-Annotation:

@Bean(name = "databaseService")
public DatabaseService databaseService()
{
    return ??
    Here i want to return the DatabaseServiceExtended
}

Anyone knows how to do it?

Upvotes: 0

Views: 2146

Answers (1)

Florian Schaetz
Florian Schaetz

Reputation: 10652

I assume that there's a better way for it, but this will scan your classpath, starting from "com.example" for all classes annotated with com.example.TaskTest and add a bean definition for it, so that bean will be created later.

This will allow you to check all classes for your annotation, but of course you will have to solve the problem that two (or more) @TaskTest could be on your classpath.

@Component
public class TestBeanProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        ; // does nothing
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        Set<BeanDefinition> definitions = scanForBeanDefinitionsIn("com.example"); // the base package

        // test if one or more, perhaps error, whatever

        BeanDefinition def = ...; // one of them

        Class<?> clz = Class.forName(def.getBeanClassName());
        TaskTest annotation = clz.getAnnotation(TaskTest.class);

        // create new RootBeanDefinition with TaskText Data (pretty analogous to XML)

        RootBeanDefinition dataSourceDefinition = ...;

        registry.registerBeanDefinition("dataSource", dataSourceDefinition);
    }

    protected Set<BeanDefinition> scanForBeanDefinitionsIn(String basePackage) {
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new TypeFilter() {

            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                return metadataReader.getAnnotationMetadata().getAnnotationTypes().contains("com.example.TaskTest");
            }

        });     
        return scanner.findCandidateComponents(basePackage);
    }
}

Upvotes: 1

Related Questions