Home > Blockchain >  How force BeanPostProcessor proxy to look up on classes not interfaces?
How force BeanPostProcessor proxy to look up on classes not interfaces?

Time:12-02

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:


  1. Filter all beans that are marked with @Service annotation.
  2. Filter all methods that have the marker annotation @Refreshable over themselves.
  3. 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;
    }
}
  • Related