Search code examples
springvalidationtransactionsaopspring-aspects

@Transactional does not work when @Validated


If I add @Validated annotation to interface/implementation of my service then the service is not transactional anymore. Stacktrace shows there is no TransactionInterceptor but I see only MethodValidationInterceptor. If I remove @Validated then I see TransactionInterceptor and MethodValidationInterceptor disappears of course. Are these aspects mutually exclusive?

@Service
//@Validated <- here is my problem :)
public interface AdminService {
  String test(String key, String result);
}

public class AdminServiceImpl implements AdminService, BeanNameAware, ApplicationContextAware {

  @Override
  @Transactional(transactionManager = "transactionManager")
  public String test(String key, String result) {

    return "hehe";
  }
}

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
@EnableTransactionManagement(order = AspectPrecedence.TRANSACTION_MANAGEMENT_ORDER)
public class AppConfiguration {..}

enter image description here

enter image description here


Solution

  • SOLVED

    @Transactional and @Validated do not work together when a service injecting its own proxy by using ApplicationContextAware interface like below:

      private String beanName;
    
      private AdminService self;
    
      @Override
      public void setBeanName(String beanName) {
        this.beanName = beanName;
      }
    
      @Override
      public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        self = applicationContext.getBean(beanName, AdminService.class);
      }
    

    During the debugging process I noticed that setApplicationContext() method is called by ApplicationContextAwareProcessor during the post processing phase in which also MethodValidationPostProcessor (@Validated) and AnnotationAwareAspectJAutoProxyCreator (@Transactional and @Aspects) wrap the original beans into proxy instances.

    Invocation of getBean() method in the middle of this process causes the bean not to be fully initialized because some of the post processing operations are not applied. In my case TransactionInterceptor was not added.

    enter image description here

    For injection of the own proxy to services I finally created specialized Ordered BeaNPostProcessor executed with the LOWEST_PRECEDENCE to be sure I operate on a fully initialized bean.