What is the Spring DI equivalent of CDI's InjectionPoint? - spring

I would like to create a Spring's bean producer method which is aware who invoked it, so I've started with the following code:
#Configuration
public class LoggerProvider {
#Bean
#Scope("prototype")
public Logger produceLogger() {
// get known WHAT bean/component invoked this producer
Class<?> clazz = ...
return LoggerFactory.getLogger(clazz);
}
}
How can I get the information who wants to get the bean injected?
I'm looking for some equivalent of CDI's InjectionPoint in Spring world.

Spring 4.3.0 enables InjectionPoint and DependencyDescriptor parameters for bean producing methods:
#Configuration
public class LoggerProvider {
#Bean
#Scope("prototype")
public Logger produceLogger(InjectionPoint injectionPoint) {
Class<?> clazz = injectionPoint.getMember().getDeclaringClass();
return LoggerFactory.getLogger(clazz);
}
}
By the way, the issue for this feature SPR-14033 links to a comment on a blog post which links to this question.

As far as I know, Spring does not have such a concept.
Then only thing that is aware of the point that is processed is a BeanPostProcessor.
Example:
#Target(PARAMETER)
#Retention(RUNTIME)
#Documented
public #interface Logger {}
public class LoggerInjectBeanPostProcessor implements BeanPostProcessor {
public Logger produceLogger() {
// get known WHAT bean/component invoked this producer
Class<?> clazz = ...
return LoggerFactory.getLogger(clazz);
}
#Override
public Object postProcessBeforeInitialization(final Object bean,
final String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(final Object bean,
final String beanName) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(),
new FieldCallback() {
#Override
public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException {
field.set(bean, produceLogger());
}
},
new ReflectionUtils.FieldFilter() {
#Override
public boolean matches(final Field field) {
return field.getAnnotation(Logger.class) != null;
}
});
return bean;
}
}

Related

Invoking PostConstruct for each bean in a list

I have the following pseudo code:
#Bean
public List<BeanB> beanB(
List<BeanA> beansA) {
List<BeanB> beansB = new ArrayList<>();
for (BeanA beanA : beansA) {
beansB.add(new BeanB(beanA))
}
return beansB;
}
#Bean
public BeanC beanC(
List<BeanB> beansB) {
return new BeanC(beansB);
}
Now the challenge is when the list of BeansB is constructed post construct is not invoked on those beans in the list. Is there any idiomatic way to trigger post construct invocation on those beans.
This does not work well as #PostConstruct is called by Spring. and from your code, for List<BeanB>, Spring will only try to find #PostConstruct in List. If it can find it, it will execute the #PostConstruct code.
I suspect you are writing beanA as follow in case you have #PostConstruct in beanA's class like below.
#Bean
public BeanA beanA_1() {
return new BeanA();
}
#Bean
public BeanA beanA_2() {
return new BeanA();
}
// which naming List of Bean B as beanB does not seems a good idea though
#Bean
public List<BeanB> beanB(List<BeanA> beansA) {
List<BeanB> beansB = new ArrayList<>();
for (BeanA beanA : beansA) {
beansB.add(new BeanB(beanA))
}
return beansB;
}
To make it work, there are multiple ways, I will just suggests some of them.
Creating a new Class, says BeanBCollectionWrappe to wrap the List of BeanB. And to make the code a bit more robust, I am implementing InitializingBean instead of #PostConstruct which is essentially the same, but allow me to ensure the method is afterPropertiesSet but not any methods.
public class BeanBCollectionWrapper implements InitializingBean {
private List<BeanB> beansB;
public void afterPropertiesSet() throws Exception {
for (BeanB beanB: beansB) {
beanB.afterPropertiesSet();
}
}
// getter and setter
}
public class BeanB implements InitializingBean {
public void afterPropertiesSet() throws Exception {
// ...
}
}
The Wrapper code can definitely be a bit better by use of Generics, like replacing BeanB to <T extends InitializingBean>.
And for the last Part,
#Bean
public BeanC beanC(BeanBCollectionWrapper wrapper) {
return new BeanC(wrapper.getBeansB());
}
Another method can be done by implementing BeanPostProcessor.
For example,
#Component
public class BeanBListBeanPostProcessor implements BeanPostProcessor{
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("beanB")) {
List<BeanB> beanBList = (List) bean;
for (BeanB beanB : beanBList) {
try {
beanB.afterPropertiesSet();
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
return null;
}
}
public class BeanB implements InitializingBean {
public void afterPropertiesSet() throws Exception {
// ...
}
}

How to use a custom deserializer with Spring #RequestParam

I have an interface that's not aware of its implementations (module-wise):
public interface SomeInterface {
}
and an enum implementing it:
public enum SomeInterfaceImpl {
}
I have a #RestController:
#RequestMapping(method = RequestMethod.GET)
public List<SomeClass> find(#RequestParam(value = "key", required = false) SomeInterface someInt,
HttpServletResponse response){
}
Although Jackson is aware that it should deserialize SomeInterface as SomeInterfaceImpl as follows:
public class DefaultSomeInterfaceDeserializer extends JsonDeserializer<SomeInterface> {
#Override
public SomeInterface deserialize(JsonParser parser, DeserializationContext context) throws IOException {
return parser.readValuesAs(SomeInterfaceImpl.class).next();
}
}
and:
#Configuration
public class MyJacksonConfiguration implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Jackson2ObjectMapperBuilder){
Jackson2ObjectMapperBuilder builder = (Jackson2ObjectMapperBuilder) bean;
builder.deserializerByType(SomeInterface.class, new DefaultSomeInterfaceDeserializer());
}
return bean;
}
}
and successfully serializes and deserializes SomeInterface as SomeInterfaceImpl in the #RequestBody, it doesn't seem to have any effect on mapping SomeInterface to SomeInterfaceImpl with #RequestParam. How do I overcome this?
Having a Converter in the application context as M.Denium suggested does the job:
#Component
public class SomeInterfaceConverter implements Converter<String, SomeInterface> {
#Override
public SomeInterface convert(String value) {
return new SomeInterfaceImpl(value);
}
}

#Before #PostConstruct Spring AOP ineterception

I'm trying to write an aspect that can intercept PostConstruct methods. I've looked at related questions on SO and others, and following them, this is what I have so far:
The Spring configuration
#Configuration
#EnableAspectJAutoProxy
#EnableLoadTimeWeaving
#...//other config annotations
public class WebConfiguration {
#Bean
public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
return new CommonAnnotationBeanPostProcessor();
}
... // etc
}
The annotation:
#Retention(RetentionPolicy.RUNTIME)
public #interface Secured {
Permission[] permissions() default {};
}
The bean
#Component
#Scope("request")
public class SomeWebBean {
#Secured(permissions = Permission.SOME_PERMISSION)
#PostConstruct
public void secure() {
... // some stuff
}
}
The aspect
#Component
#Aspect
public class SecuredAspect {
#Before("#annotation(secured)")
public void doAccessCheck(Secured secured) {
... // actually do the access check
}
}
If I call someWebBean.secure() from a page, then the aspect is invoked. However, it is not invoked on bean creation.
So as a note to future me - this absolutely cannot be done in this way using Spring AOP.
However, the same effect can be achieved by implementing a BeanPostProcessor as below:
public class SecureBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Secured secured = bean.getClass().getAnnotation(Secured.class);
if (secured != null) {
// do your security test here, throw an exception, return false, however you like
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
You can extend CommonAnnotationBeanPostProcessor and override postProcessBeforeInitialization(Object bean, String beanName)
Then register replace the original CommonAnnotationBeanPostProcessor with a BeanFactoryPostProcessor .
public class InitCommonAnnotationBeanPostProcessor extends CommonAnnotationBeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return super.postProcessBeforeInitialization(bean, beanName);
}
}
public class InitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
RootBeanDefinition def = new RootBeanDefinition(InitCommonAnnotationBeanPostProcessor.class);
def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME, def);
}
}
#Configuration
public class InitialisationMonitoringConfig {
public static final String BEAN_INIT_MONITOR = "BEAN_INIT_MONITOR";
#Bean
public static InitBeanFactoryPostProcessor initBeanFactoryPostProcessor() {
return new InitBeanFactoryPostProcessor();
}
}
This is ugly, but I had to do that to analyse startup times in dev environment.
Maybe it's enough to just declare InitCommonAnnotationBeanPostProcessor as a bean, I didn't tried.

Spring proxy beans from Interface

What is the correct way to create proxy beans by interfaces?
public class JdbiRepositoryAnnotationBeanPostProcessorTest {
private DBI dbi = mock(DBI.class);
#org.junit.Test
public void testIncompleteBeanDefinition() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(JdbiRepositoryAnnotationBeanPostProcessor.class);
ctx.register(MyConfig.class);
ctx.refresh();
ITest bean = ctx.getBean(ITest.class);
assertNotNull(bean);
}
#JdbiRepository
public static interface ITest {
}
#Configuration
#ComponentScan(basePackageClasses = {ITest.class},
includeFilters = {#ComponentScan.Filter(type = FilterType.ANNOTATION, value = JdbiRepository.class)})
public static class MyConfig {
}
}
I have tried bean post processor but It did not help me.
Edit:
I wanted to use component scanning by including annotation filter but it did not help me too.
Edit:
I want to create instances by another library which is creating proxy beans as this:
TestInterface proxy = factory.onDemand(TestInterface.class);
Edit:
I have extended InstantiationAwareBeanPostProcessorAdapter for JdbiRepositoryAnnotationBeanPostProcessor.
I have been just logging currently. But I can not see my interfaces as a bean.
Please note that I have also changed my test code above.
public class JdbiRepositoryAnnotationBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if(!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException("AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
}
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
// this.dbiMap = this.beanFactory.getBeansOfType(DBI.class);
}
}
The problem was related to ComponentScanning not PostBeanProcessor. ComponentScan is scanning only concrete classes that is why my processor did not work. I had to create a custom importer for interfaces.

Can I access a annotation on the instance of a bean to be injected

Given a class :
public ClassA {
#Autowired
#SomeAnnotation("foo")
private ClassB bar;
}
#Component
#Scope(prototype)
public ClassB {
private String someString;
}
I would like to write some bean processor (post construct...) that can at ClassB construction time can access the #SomeAnnotation on the intances that ClassB is getting injected into so that I can set the value of someString to "foo".
I know this isn't very IoC and I'm going to guess it cannot be done.
You might be able to do something like this with a #PostConstruct of ClassA:
#PostConstruct
public void postConstruct(){
SomeAnnoation someAnnotation = this.getClass().getField("bar").getAnnotation(SomeAnnotation.class);
bar.someString(someAnnotation.value());
}
Update: - General solution using a BeanPostProcessor :
public class SomeAnnotationFieldInitalizer implements BeanPostProcessor{
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Field[] fields = bean.getClass().getFields();
if (fields!=null){
for (Field field:fields){
SomeAnnotation someAnnotation = field.getAnnotation(SomeAnnotation.class);
if (someAnnotation!=null){
try {
ReflectionUtils.makeAccessible(field);
field.set(bean, someAnnotation.value());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return bean;
}
}

Resources