I am not sure if question is correctly asked because I am still newbie in this stuff.
I want to complete the following scenario using a BeanPostProcessor
:
- Filter all beans that are marked with
@Service
annotation. - Filter all methods that have the marker annotation
@Refreshable
over themselves. - Perform the specified method on the return objects of these methods.
Below is my working example:
@Retention(RUNTIME)
public @interface Refreshable {
}
public interface VisitServiceI {
@Refreshable
VisitDtoOut addVisitToPatient(UUID idPatient, VisitDtoIn visitDtoIn);
}
public interface RefreshableDto {
void copyId();
}
@Component
public class MethodBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof VisitServiceI) {
ProxyFactory factory = new ProxyFactory(bean);
factory.addInterface(VisitServiceI.class);
factory.addAdvice((AfterReturningAdvice) (returnValue, method, args, target) -> {
if (method.isAnnotationPresent(Refreshable.class)) {
var refreshableDto = (RefreshableDto) returnValue;
if (refreshableDto != null) {
refreshableDto.copyId();
}
}
});
factory.setExposeProxy(true);
return factory.getProxy();
}
return bean;
}
}
Is this possible to get rid of that useless interfaces like: VisitServiceI
I want to force BeanPostProcessor
to somehow works when I will give him standard classes instead of interfaces of them.
CodePudding user response:
Ditch the BeanPostProcessor
and just write an aspect instead, let Spring do the heavy lifting.
@Aspect
@Component
public RefreshableAspect {
@AfterReturn("within(@Service) && @annotation(@Refreshable)", returning="retVal")
public void refresh(Object retVal) {
if (retVal instanceof RefreshableDto) {
((RefreshableDto) retVal).copyId();
}
}
}
Something like that will accomplish what you need without interfaces and without an additional BeanPostProcessor
.
But if you really want the complex route do something like this
@Component
public class MethodBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (AnnotationUtils.findAnnotation(bean.getClass(), Service.class) != null) {
ProxyFactory factory = new ProxyFactory(bean);
factory.setProxyTargetClass(true);
factory.addAdvice((AfterReturningAdvice) (returnValue, method, args, target) -> {
if (method.isAnnotationPresent(Refreshable.class)) {
var refreshableDto = (RefreshableDto) returnValue;
if (refreshableDto != null) {
refreshableDto.copyId();
}
}
});
factory.setExposeProxy(true);
return factory.getProxy();
}
return bean;
}
}