I have an EJB class in which I need to inject two beans - one should be injected by the EJB container and other is a Spring Container.
@Stateless
@Interceptors(SpringBeanAutowiringInterceptor.class)
@LocalBean
public class SomeClass {
@Inject
private EJBClass a;
@Autowired
private SpringComponent b;
}
Here, the Spring interceptor trying to intercept the injection of bean 'a' and it's getting failed. I want the EJB container to inject the bean 'a' and Spring container to inject bean 'b'.
Please show me a way out here.
By customizing the SpringBeanAutowiringInterceptor
class, dependencies annotated with @Inject
can be excluded from auto wiring.
To understand what happens behind the scene, have a look at source code of SpringBeanAutowiringInterceptor.java -
/**
* Actually autowire the target bean after construction/passivation.
* @param target the target bean to autowire
*/
protected void doAutowireBean(Object target) {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
configureBeanPostProcessor(bpp, target);
bpp.setBeanFactory(getBeanFactory(target));
bpp.processInjection(target);
}
At first line, of doAutowireBean
, a new instance of AutowiredAnnotationBeanPostProcessor
is created. Here set of annotations to be scanned for auto wiring dependencies are configured.
/**
* Create a new AutowiredAnnotationBeanPostProcessor
* for Spring's standard {@link Autowired} annotation.
* <p>Also supports JSR-330's {@link javax.inject.Inject} annotation, if available.
*/
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
Since, by default, the @Inject
annotation is configured spring scans respective dependencies marked with @Inject
and tries to auto wire them.
To exclude @Inject
annotated dependencies write below custom class.
public class CustomSpringBeanAutowiringInterceptor extends SpringBeanAutowiringInterceptor {
/**
* Template method for configuring the
* {@link AutowiredAnnotationBeanPostProcessor} used for autowiring.
* @param processor the AutowiredAnnotationBeanPostProcessor to configure
* @param target the target bean to autowire with this processor
*/
protected void configureBeanPostProcessor(AutowiredAnnotationBeanPostProcessor processor, Object target) {
Set<Class> annotationsToScan = new HashSet<Class>();
annotationsToScan.add(Autowired.class);
annotationsToScan.add(Value.class);
processor.setAutowiredAnnotationTypes(annotationsToScan);
}
}
Here configureBeanPostProcessor
hook is utilized to customize the bean post processor so as to include only those annotations which we require to be auto wired.
After applying this custom class as interceptor in code the desired behaviour can be achieved
@Stateless
@Interceptors(CustomSpringBeanAutowiringInterceptor.class)
@LocalBean
public class SomeClass {
@Inject
private EJBClass a;
@Autowired
private SpringComponent b;
}
Let know in comments if you face any issues. Also feel free to optimize the code as deemed fit and excuse any compilations / formatting issues.