Curently I use @CustomAnnotation on the classes directly, and use a BeanFactoryPostProcessor to change the bean definition of the annotated beans to my needs.
@CustomAnnotation public class MyBean implements IMybean{ } @Configuration public class MyConfiguration { @Bean public MyBean myBean(){ return new myBean(); } } What I want to do is instead be able to put the @CustomAnnotation on @Bean method of the configuration file, like this:
public class MyBean implements IMybean{ } @Configuration public class MyConfiguration { @Bean @CustomAnnotation public MyBean myBean(){ return new myBean(); } } From the BeanDefinition I can get from the beanFactory, I know I can get the factory bean and the factory method that creates myBean, and check if there is a @CustomAnnotation on the method.
What I am not sure is if doing that would break any spring principles, or if it is a regular thing to do.
My original intention is working. However I have another issue now. I can't autowire the bean that comes from the factory where I want, with the type I want. There are problems to resolve the depencies. This is the test code I use to try to solve the issue. test code on github
@Configuration public class MainConfiguration implements BeanDefinitionRegistryPostProcessor, Ordered { private SayenBeanDefinitionRegistryPostProcessor sayenBeanDefinitionRegistryPostProcessor = new SayenBeanDefinitionRegistryPostProcessor(); public int getOrder() { return sayenBeanDefinitionRegistryPostProcessor.getOrder(); } public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { sayenBeanDefinitionRegistryPostProcessor.postProcessBeanFactory(beanFactory); } public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException { sayenBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(beanFactory); } @Bean public AutowiredBean autowiredBean() { return new AutowiredBean(); } @Bean @Transform(type = MegaSuperKarim.class) public Karim Karim() { return new Karim(); } @Bean @Transform(type = SuperGuillaume.class) public Guillaume Guillaume() { return new Guillaume(); } @Bean public Yoann Yoann() { return new Yoann(); } @Bean public Nicolas Nicolas() { return new Nicolas(); } @Bean public BeanHolder beanHolder() { return new BeanHolder(); } } public class TransformFactoryBean implements FactoryBean<Object> { @Autowired private AutowiredBean pouet; private Class<?> objectType; boolean singleton = true; @Override public Object getObject() throws Exception { return objectType.getConstructor().newInstance(); } @Override public Class<?> getObjectType() { return objectType; } @Override public boolean isSingleton() { return singleton; } public void setObjectType(Class<?> objectType) { this.objectType = objectType; } public AutowiredBean getPouet() { return pouet; } public void setSingleton(boolean singleton) { this.singleton = singleton; } } public class SayenBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, Ordered { private static Logger logger = LoggerFactory.getLogger(MainConfiguration.class); @Override public int getOrder() { return 0; } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { logger.debug("rien"); } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException { //DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) beanFactory; for (String originalBeanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition originalBeanDefinition = beanFactory.getBeanDefinition(originalBeanName); logger.debug("original beanName=" + originalBeanName + ", " + originalBeanDefinition.toString()); if (originalBeanDefinition.isAbstract()) { continue; } Transform sayenAnnotation = getMethodAnnotation(beanFactory, originalBeanDefinition); /*if (sayenAnnotation == null) { Class<?> originalBeanClass = beanFactory.getType(originalBeanName); sayenAnnotation = AnnotationUtils.findAnnotation(originalBeanClass, Transform.class); */if (sayenAnnotation == null) { continue; }/* }*/ Class<? extends Sayan> sayenClass = sayenAnnotation.type(); RootBeanDefinition sayenFactoryBeanDefinition = new RootBeanDefinition(TransformFactoryBean.class, 3/*Autowire.BY_TYPE.value()*/, true); sayenFactoryBeanDefinition.getPropertyValues().add("objectType", sayenClass); sayenFactoryBeanDefinition.getPropertyValues().add("singleton", true); String factoryBeanName = originalBeanName; logger.debug("remove beanName=" + originalBeanName + ", " + originalBeanDefinition.toString()); beanFactory.removeBeanDefinition(originalBeanName); logger.debug("register beanName=" + factoryBeanName + ", " + sayenFactoryBeanDefinition.toString()); beanFactory.registerBeanDefinition(factoryBeanName, sayenFactoryBeanDefinition); } } private Transform getMethodAnnotation(BeanDefinitionRegistry beanFactory, BeanDefinition originalBeanDefinition) { String originalBeanFactoryBeanName = originalBeanDefinition.getFactoryBeanName(); String originalBeanFactoryMethodName = originalBeanDefinition.getFactoryMethodName(); if (originalBeanFactoryBeanName == null || originalBeanFactoryMethodName == null) { return null; } Class<?> originalBeanFactoryBeanClass = ClassUtils.getUserClass(((DefaultListableBeanFactory)beanFactory).getType(originalBeanFactoryBeanName)); try { Method method = originalBeanFactoryBeanClass.getMethod(originalBeanFactoryMethodName); return AnnotationUtils.getAnnotation(method, Transform.class); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } }