1

Please consider following situation with spring 4.0.7

For Eclipselink, we use a load-time-weaver. So we wanted to experiment with Springs @Configurable annotation using @EnableSpringConfigured with @EnableLoadTimeWeaving at the same time.

This is fully functional, and Spring-Beans are injected perfectly into POJOs during construction. This functionality is helpful for us, because we want to keep some code regarding validation of these POJOs inside these and not somewhere else in a Bean.

SOme of our Spring Context contains Beans that do not implement any interface, because they are local to some package and used only there. Lets say, FooLogicBean is one of them. If this is to be injected into another Bean, and some Spring-AOP-Aspect (not-aspectj) like some performance measurement aspect is in the execution path, Spring will create a CGLIB autoproxy for the FooLogicBean and inject that. This is fully functional and works perfectly too.

Problems arise, when we want to actually use a POJO that is annotated with @Configurable as a parameter in a method of FooLogicBean (like fooLogicBean.doValidate(myPojo); ), respectively a CGLIB Proxy. In this case, some non-trivial magic stops that POJO from being woven thru aspectj (AnnotationBeanConfigurerAspect from spring-aspects). It is even never woven anywhere in the code regardless of calling the aforementioned doValidate() Method.

If we create that POJO inside FooLogicBean, but dont use it as a method Parameter, it gets woven again due to @Configurable.

Without knowing the Autoproxy creation code, we assume some fancy marking routine from hindering a class from being detected by aspectj, if that class was already used in spring-aop. use in this case means Access.

Did anyone experiment with such obscure constellation and knows a solution for that?

Thanks in advance!

  • Can you provide an [SSCCE](http://sscce.org/), please? Maybe a mavenised GitHub project? Reproduceability is always nice for debugging. – kriegaex Sep 24 '14 at 09:45

1 Answers1

1

Proxies are created by subclassing, i.e. when you create a proxy of an annotated class Foo:

class Foo {
  @Bar
  void bar() { }
}

the proxy is created by implementing a class

class Foo$Proxy extends Foo {
  @Override
  void bar() { 
    // Proxy logic
  }
  // Overridden methods of Object
}

This makes the Foo$Proxy class a valid Liskov substitute for Foo. However, normal override semantics apply, i.e. non-inherited annotations such as @Bar are not longer present for the overridden methods. Once another annotation-based API processes your beans, all annotations have disappeared which leads to your outcome. This is true for all kinds of annotations. Those on types, methods and method parameters.

But is it avoidable? It most certainly is by using a proxy generator that was written recently and is built with knowledge of what annotations are, something that is not true for cglib which was first shipped in the early days of the Java virtual machine. However, as long as Spring does not move away from cglib, you will have to live with today's limitations.

Community
  • 1
  • 1
Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • I am not sure if CGLIB is the cause of this problem. The problem does not happen on somehow annotated methods, but on objects with annotations that are used in methods of proxies. Spring AOP Proxy logic does code-share with aspectj when processing the aop-pointcuts. So my thought was that this leads to the aspect-parsing-subsystem to detecting / loading classes before the real-aspectj part of the spring-context gets in action. I think, I got somewhere the information that one has to ensure that aspectj-aspects must loaded far more before than the rest to "detect" newly to weave classes. – Yusuf Iskenderoglu Sep 17 '14 at 13:06