Reputation: 13
Created a custom annotation to register proxy beans via ImportBeanDefinitionRegistrar and FactoryBean. At runtime, application seems to start and auto wire the beans as expected. However, IDE (IntelliJ) shows error on auto wired bean.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(CustomBeansRegistrar.class)
public @interface EnableCustomBeans {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface CustomBean {
}
public class CustomBeanFactoryBean
implements FactoryBean<Object>, InitializingBean, ApplicationContextAware, BeanFactoryAware {
private Class<?> type;
private String name;
private ApplicationContext applicationContext;
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public Object getObject() {
return getTarget();
}
<T> T getTarget() {
return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type},
new CustomBeanInvocationHandler());
}
@Override
public Class<?> getObjectType() {
return type;
}
@Override
public void afterPropertiesSet() {
Assert.hasText(name, "Name must be set");
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
beanFactory = context;
}
}
class CustomBeansRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private ResourceLoader resourceLoader;
private Environment environment;
CustomBeansRegistrar() {
}
@Override
public void setEnvironment(@NotNull Environment environment) {
this.environment = environment;
}
@Override
public void setResourceLoader(@NotNull ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void registerBeanDefinitions(@NotNull AnnotationMetadata metadata, @NotNull BeanDefinitionRegistry registry) {
registerCustomBeans(metadata, registry);
}
private void registerCustomBeans(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
... // logic to scan CustomBean annotation classes
registerCustomBean(registry, annotationMetadata, attributes)
}
private void registerCustomBean(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory
? (ConfigurableBeanFactory) registry : null;
assert beanFactory != null;
String className = annotationMetadata.getClassName();
Class<?> clazz = ClassUtils.resolveClassName(className, null);
String name = (String) attributes.get("name");
CustomBeanFactoryBean factoryBean = new CustomBeanFactoryBean();
factoryBean.setBeanFactory(beanFactory);
factoryBean.setType(clazz);
factoryBean.setName(name);
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> factoryBean.getTarget());
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
definition.setLazyInit(true);
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
beanDefinition.setAttribute("customBeansRegistrarFactoryBean", factoryBean);
beanDefinition.setPrimary(true);
String[] qualifiers = new String[]{name + "CustomBean"};
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
}
@SpringBootApplication
@EnableCustomBeans
public class MyApplication {
...
}
@CustomBean(name = "myServiceCustomBean")
public interface MyServiceCustomBean {
@Component
@RequiredArgsConstructor
public class SomeService {
private final MyServiceCustomBean myServiceCustomBean;
}
Above code works as expected, however, IDE shows error Could not autowire. No beans of 'MyServiceCustomBean' type found.
.
Also, have Spring attached to the project module. Tried invalidating cache and restarting IDE as well.
I have even tried using @Autowired
along with @Qualifier ("myServiceCustomBean")
.
Using @Resource
does hide the error.
What I am missing here in order to have these proxy beans recognized by IDE as Spring beans?
Upvotes: 0
Views: 28