8

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

Artem Malchenko
  • 2,320
  • 1
  • 18
  • 39
Marek Raki
  • 3,056
  • 3
  • 27
  • 50
  • 1
    What are you trying to validate at your service layer? The entities you receive at that level should have already *been* validated by the time your service starts to handle them. – Makoto Mar 02 '18 at 16:21
  • 1
    You are probably right but this is not the answer to my question :( – Marek Raki Mar 02 '18 at 16:32
  • If the answer turns out to be, "It doesn't make sense to put your validation at that level, move it up," and then you get your transactions back... – Makoto Mar 02 '18 at 16:33
  • I have just check another thing @Validated also turns off other aspects advising my service so for sure there is something wrong with this behavior :( – Marek Raki Mar 02 '18 at 16:44
  • from doc; a class-level annotation is nevertheless necessary to trigger method validation for a specific bean to begin with. Can also be used as a meta-annotation on a custom stereotype annotation or a custom group-specific validated annotation. – Y.Kaan Yılmaz Mar 03 '18 at 00:40
  • and the link is https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/validation/annotation/Validated.html – Y.Kaan Yılmaz Mar 03 '18 at 00:40
  • Could [this](https://stackoverflow.com/a/48655681/1082681) be your problem? See also [here](https://stackoverflow.com/q/39271035/1082681). – kriegaex Mar 03 '18 at 04:24

1 Answers1

5

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.

Artem Malchenko
  • 2,320
  • 1
  • 18
  • 39
Marek Raki
  • 3,056
  • 3
  • 27
  • 50