AspectJ load time weaving not working on Spring beans - java

I'm working on a project that uses the Java (not xml) flavour of Spring configuration for wiring up dependencies. It also has profiling logic that should be weaved via AspectJ onto the desired methods (via annotations). The setup is working and I can see classes from my desired package being weaved and profiling information being logged out of them.
The problem is that weaving does not work for #Bean classes. I've enabled debug in aop.xml via:
<weaver options="-XnoInline -Xreweavable -verbose -debug -showWeaveInfo">
And I can see classes in my desired package being weaved, but not the beans in the configuration. If I instantiate the classes directly (not inject them) weaving works.
Unfortunately, I can't post real code here, but here's a dumbed down example:
#Configuration
#EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
public class MySpringConfig {
#Bean
AnnotatedClass1 annotatedClass1() {
return new AnnotatedClass1(new AnnotatedClass2());
}
}
AnnotatedClass1 and AnnotatedClass2 live in the same package and weaving works on the one instantiated directly and not the one returned by the bean.
I've searched through the Spring AOP docs but I can't seem to find anything related to this. There is some magic you need to do for auto-proxying and some limitations for SpringAOP but load time weaving should just work as far as I can tell - I've tried on private methods for example and it worked.

The problem was the return type - if I do:
#Bean
Object annotatedClass1() {
return new AnnotatedClass1(new AnnotatedClass2());
}
the weaving starts to work for the bean as well. My initial assumption was that it has something to do with Spring caching the bean and not using the weaved version, but this didn’t make sense because:
load time weaving is supposed to act at, well… class load time :). Then, it doesn’t matter what the method returns, the class should have the aspects.
I’ve actually checked the debug output for both Spring and AspectJ and no mention of my class so it must have been ignored somehow.
This is the first time I’ve used this stuff, so I might be misunderstanding things. If anyone can explain why the return type of the #Bean method has anything to do with weaving I’d be happy to accept your answer instead of this one.

Related

Quarkus testing using #QuarkusTest, mocks and javax.enterprise.inject.Instance

We have an application that uses javax.enterprise.inject.Instance to find all validators for a service. This seems to work nicely but during testing we would like to swap out a few of those validators with a mock to skip their behaviour so it's easier to reach other validators.
When we try to do this using the 'Old approach' (See Blog-post on this) we notice only the classes with #Mock are injected, not any of the normal ones.
When trying it the 'New approach' we get a javax.enterprise.inject.AmbiguousResolutionException that tells us TypeBValidator is found twice.
This is the setup of a trimmed-down version of our app showing the behaviour:
Validator-interface
TypeAValidator (#ApplicationScoped)
TypeBValidator (#ApplicationScoped)
REST-Service-class that has a #Inject like this: Instance<Validator> validators via the constructor.
In test-scope we have:
TypeBMockValidator (which does have #Mock in old and no #Mock in the new approach)
Test class for REST-Service that is annotated with #QuarkusTest. This test-class calls the REST-service using restassured, right as it's provided when one generates an example project.
See the example project for all details.
I'm looking for a stable and predictable way to replace only the TypeBValidator during my tests. Any help would be highly appreciated.
Turns out that this was not a bug, but the expected behavior of CDI when multiple there is a class hierarchy where multiple classes are beans.
In this case, the simplest solution is to annotate TypeBValidator with #DefaultBean.
See https://github.com/quarkusio/quarkus/issues/19773#issuecomment-909974623 for more details

How to use Spring #Component annotation with AspectJ compiler

I excluded part of my project for easier reproduce problem: GitHub repo.
When I compile it by Javac everything works as expected. I see logging in console when I open URLs /user/ and /user/2/:
Access: execution(List ru.krivochenko.demo.user.UserController.getAll())
Access: execution(User ru.krivochenko.demo.user.UserController.getOne(Integer))
But I wanna use AspectJ compiler. When I switch to it, error occurs:
java.lang.NoSuchMethodError: ru.krivochenko.demo.logging.LoggingAspect: method <init>()V not found
As I understood it happens because there is not no-args constructor in LoggingAspect. If I add it, I get another error, because logger is not injected:
java.lang.NullPointerException: null
at ru.krivochenko.demo.logging.LoggingAspect.beforeGettingUsers(LoggingAspect.java:28) ~[classes/:na]
So, how we can see, AspectJ ignores Autowired constructor with args.
In branch via-setter of my repo I implemented another solution. I removed #Component annotation of LoggingAspect and replaced constructor injection to setter injection. In DemoApplication.java I added #Bean configuration of LoggingAspect. It works fine, but in some situations it requires getting dependencies from application context. What is the best practice to resolve it?
Thanks for help.
Spring Aspects and compile time weaving don't automatically integrate. This is primary because aspectj and spring are fairly separate and I suspect Spring's recommended approach is not to use compile time weaving.
So thus by default Aspects are not spring magic and we need to add a little bit of plumbing to ensure they are.
In this regard, it is important to note that Aspects are not spring managed (they are managed by aspectj so we need to add something to ensure they are).
Thus the reason why you need a parameterless constructor on your aspect (so must use field injection).
Traditionally I have had to add the following piece of xml to my xml config files:
<bean id="securityAspect" class="com.<skip>.security.AuthorizationAspect"
factory-method="aspectOf" autowire="byType" />
So this works because the AspectJ compiler adds the static method aspectOf to the aspects and this method is available for acquiring the instance of the Aspect that aspectj creates (and uses).
This method is obviously not available in the source so we can't just add to our application class (DemoApplication):
#Bean
public LoggingAspect loggingAspect() {
return LoggingAspect.aspectOf();
}
Then what to do? My next option was to write some reflective code to call this method then having looked at this very helpful example that demonstrates exactly what you need - The Aspects class from AspectJ has a utilty method that does this work for us, so adding the following to our DemoApplication we have success:
#Bean
public LoggingAspect loggingAspect() {
return Aspects.aspectOf(LoggingAspect.class);
}
Btw, remove the #Component from the LoggingAspect as that will mean both Aspectj and Spring create an instance of the class...
Btw, I'd also suggest you add the following to your test class to demonstrate the problem in a test:
#Autowired
private UserController controller;
#Test
public void contextLoads() {
controller.getAll();
controller.getOne(1);
}
Btw, other suggestions to address this problem used #Configurable. I suspect this might work but you'll need to make sure you include the spring aspects java in your aspectj compile time config and I suspect it may still not work as I'm not sure the Spring context will be ready in time. i.e. if the Aspect is created before the spring context then #Configurable won't work as the beans to be injected will not yet be created.
Your approach to configure the aspect via setter injection looks valid to me. For more information about how to use AspectJ in combination with Spring check out the corresponding chapter in the Spring manual, specifically the description about how to configure AspectJ aspects by Spring IoC. It is mostly explained in the context of LTW, but it should work pretty much the same for CTW.

Spring profile not properly applied to tests involving #Configurable

I have a very weird situation, that has happened in several systems already. I am using Spring Boot and AspectJ CTW to #Autowired dependencies in some entities (instanciated outside the container).
The class that receives dependencies (an abstract entity) some times receive the dependency without applying the profile (configured by #ActiveProfile in my test class). It is not deterministic, since by changing how tests are executed different outputs can happen. To illustrate the situation with code:
The entity
#Configurable
public class AbstractMongoDocument<T> implements Persistable<T> {
#Transient
private transient MongoTemplate mongoTemplate;
//entity stuff
}
One of the failing tests
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = LOVApplication.class)
#ActiveProfiles("local-test")
public class MyCrazyIntegrationTest {
#Test
public void filterByFieldsFullMatchShouldReturnResult() throws Exception {
//Given
Location l1 = new Location("name","code",new GeoJsonPoint(11,10));
l1.save(); //Hence the need of autowiring there.
//When: whatever
//Then: Some assertions
}
}
There are some facts that I find very disturbing here:
The dependency is always injected, but some times it apparently comes from an AppCtx with the default profile.
If it fails for 1 test in 1 class, it behaves the same for all the tests in that particular class.
It may or may not happen depending on how you execute that class (At the moment it fails only if I run all the tests, but succeed if I run that class in isolation, it also behaves differently in maven).
If I debug it, I can see that the dependency injected didn't get the proper profile. (I discovered that by injecting ApplicationContext and surprisingly discovering that it was a different object than the one I received in my tests).
What worries me the most, is that now I am not sure if this situation could also happen for non-test environments with for example a Production profile, which would imply a catastrophe.
I have tried to look for open bugs in Jira and I found nothing, so I don't discard I am misconfiguring something. Any help or ideas would be very much appreciated.
The behavior you are experiencing typically should not happen in a production deployment; however, it is a known issue with integration test suites that load multiple ApplicationContexts utilizing #Configurable and AspectJ load-time weaving.
For details, see the following issues in Spring's issue tracker:
https://jira.spring.io/browse/SPR-6353
https://jira.spring.io/browse/SPR-6121

Building custom java config annotations - similar to custom XML namespaces

We're building a framework on top of Spring & Spring MVC. Our framework is quite mature at this point - about 2 years old and is used widely within our organization. Our framework is very modular (much like spring itself is). There are various modules that can be used independently or together. When used together they provide many benefits to the end user. We have built a handful custom spring XML namespaces (NamespaceHandlers, BeanDefinitionParsers, etc). Each module provides their own which brings in its own set of XML configuration elements. This is all working great for us and has been a really big win for us.
What we'd like to do now is move away from XML-based configuration and into java config. My idea/thought is for each module to introduce a set of java config annotations that can be used (something similar to the #EnableCaching, #EnableMBeanExport annotations). My question is this - even if I create my annotations - how do I "wire" them in so that if they are present I can do "stuff"? This would be similar conceptually to the NamespaceHandlers & BeanDefinitionParsers. I can't find any documentation anywhere as to how to get started.
I've thought about creating some custom abstract base classes which do what I need them to do - but the problem is when it comes to the end user's application - they can only extend a single class. I need a flexible way for each module in my framework to expose its own custom configuration that end user applications can use, just like they use our XML namespace elements.
Here's a glimpse as to what we do in XML (not full application context file - just a blurb from it pertaining to our custom XML namespaces):
<atom-web:web/>
<atom-web:logging/>
<atom-web:security entitlementsProvider="XML" xmlRefreshInterval="${cache.refresh.interval.ms}"/>
<atom-profile:profile caching="IN_MEMORY" entryExpiryDelay="${cache.refresh.interval.ms}"/>
<atom-prefs:preferences backingStoreUrl="${pref.backingStore.url}"/>
<atom-content:content contentServerBaseUrl="${content.server.url}" contentServerFileUrl="${content.server.file.url}" site="${site.name}" contentTaskExecutor="contentTaskExecutor" snippetCaching="IN_MEMORY" cacheRefreshInterval="${cache.refresh.interval.ms}"/>
<bean id="contentTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" p:corePoolSize="3" p:maxPoolSize="20"/>
What I'm envisioning is some kind of set of annotations - something like this:
#EnableAtomWebApplication
#EnableAtomWebLogging
#EnableAtomWebSecurity(entitlementsProvider=EntitlementsProvider.XML, xmlRefreshDelay=120000)
#EnableAtomProfile(caching=CachingType.IN_MEMORY, expiryDelay=120000)
// Other annotations for rest of modules
#Configuration
public class ConfigurationClass {
// Rest of configuration in here
}
Any help here would be greatly appreciated. I'm not quite sure where to start and can't really find any documentation anywhere to help me get started.
So after thinking about this a bit I think I've found the correct starting point. I wanted to throw this out there for anyone who might be able to say "yeah thats the right place" or "no you aren't looking in the correct place".
Using my example above
#EnableAtomProfile(caching=CachingType.IN_MEMORY, expiryDelay=120000)
I would create an annotation for the #EnableAtomProfile annotation like this:
#Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
#Target(value={java.lang.annotation.ElementType.TYPE})
#Documented
#Import({AtomProfileBeanDefinitionRegistrar.class})
public #interface EnableAtomProfile {
CachingType caching() default CachingType.NONE;
long expiryDelay default 0;
}
The AtomProfileBeanDefinitionRegistrar class would implement org.springframework.context.annotation.ImportBeanDefinitionRegistrar and do any of the necessary stuff that I'm currently doing in my BeanDefinitionParser
You can have a BeanPostProcessor defined, which would basically:
inspect every single bean created
with reflection check if the object's class is annotated with #YourAnnotation
and if it is, then apply some custom logic - e.g. package the object into some other class or something
Reference:
Spring docs on BeanPostProcessors
source code for RequiredAnnotationBeanPostProcessor, which is a BeanPostProcessor which analyzes annotations

Spring Test: better use XML configuration over annotations?

I'm learning Spring and looking at using Spring Test for my web app (JQuery/CXF/Hibernate). I have been using annotations to wire up my beans and noticed that this sometimes got into the way of polymorphism. For example I have a GenericDAO extended by all DAOs. It is also a concrete class used by simple services, so when I wired it for one of those services, ALL other DAOs became candidates for runtime wiring (because of polymorphism). I could solve that by wiring explicitly by type: #Resource(type= GenericDaoImpl.class), but this goes against the best practice of coding to interfaces ..
Now I want to create unit tests using a MockGenericDaoImpl, and integration tests using GenericDaoImpl. How will I override the annotations? I'm guessing the best approach is to stick to XML-based wiring, so that I can have several versions of beans.xml, one for prod, one for unit tests, one for integration tests, and possibly split them into parallel sub-files, as needed. Isn't this approach more flexible than depending on annotations that either scan to guess the appropriate candidate, or constrain polymorphism?
Can someone give me broad directions on how to organize my test configuration setup? Thank you!
How about using #Configuration class? If you're not familiar with this method - you can declare a class that replaces the XML context file and looks something like this:
#Configuration
#ComponentScan({ "com.project.dao"})
public class TestConfiguration {
#Bean
public GenericDao getGenericDao() {
return new MockGenericDaoImpl();
}
}
In the #ComponentScan annotation just put the relevant packages to scan. This way you're very flexible with the beans you're creating and the way to create them. You can injects mock to the beans whatever way you'd like.
Also you can create several test configurations, each configuration for a different purpose. In order to load the context you need to put this annotation on your test class:
#ContextConfiguration(classes={TestConfiguration .class})
Using XML configuration files prevent you from depending on Spring dependencies. You can replace it with another DI framework(maybe Guice, but this is not realistic for big projects I know). Using XML configuration files enables you to code cleanly.
I hate XML but I hate existence of not-business-logic-specific things in my code more.
I see you know how to overcome the test issues using XML configuration files. I will try to show how to overcome duplication of implementations(one real one mock implementation) problems using annotations.
You can define your beans via annotations. You can select implementation using aliases:
project.dev.properties:
my.project.dao.xDao=xDaoJpaBean
project.test.properties:
my.project.dao.xDao=xDaoMockBean
<alias name="${my.project.dao.xDao}" alias="xDao"/>
#Autowired
#Qualifier("xDao")
protected XDao xDao;
So you can select your implementation just using your properties file. If you want to use Annotations purely you can do this as well:
#Autowired
#Qualifier("${my.project.dao.xDao}")
protected XDao xDao;
Your build environment will specify which properties file to load, in return your bean will be assigned.

Categories