Using aspectj in Hibernate entity - spring

I have entity class like this:
package tr.com.example.model.porting
...//omitting imports
#Configurable
#Data
#Entity
public class PortOut{
public void handleRequest(Long portingId) {
processRequest(portingId);
...
}
}
And here is my aspect code in different class annotated with #Aspect and #Component:
#Around("execution(* tr.com.example..PortOut.handleRequest(..))")
public void handlePortingProcessAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
joinPoint.proceed();
log.debug(log.debug("[POM]:{} is executed with parameters:{}", joinPoint.toShortString(), joinPoint.getArgs()))
}
Normally, my aspect code works fine for other Spring managed classes such as using #Service, #Component annotation. I am using https://github.com/subes/invesdwin-instrument as a weaving agent and also using Lombok.
I tried this link(along with other so posts). But since I am using Lombok, I cannot directy compile with aspectj compiler for weaving #Configurable classes, it doesn't work with Lombok as I found out.
https://groups.google.com/forum/#!topic/project-lombok/ZkLsTZVSgD4
Shortly, what I want is using aspectj for logging some methods's arguments, but I can't use it in any Hibernate entity class, other than that it works fine. How to get it working in entity classes?

Here you find the explanation why Lombok and AspectJ do not like each other.
What is said to work though, is to delombok the Lombok-annotated source code and then normally compile the generated source code with the AspectJ compiler (e.g. via AspectJ Maven plugin, which is what I use all the time in Maven projects). Assuming you do use Maven, also the delombok step can be done with Lombok Maven plugin. If you assign the right phases to the respective plugins, it should be possible to fully automate the build process.
Disclaimer: I have never used Lombok in my whole life, but know a thing or two about AspectJ and Maven.

Related

Spring AOP (AspectJ) with Kotlin and Gradle - I can't get it to work

I have a Spring Boot + Kotlin + Gradle project. I'd like to create a small library for my use-cases. This library should use AOP to remove some cross cutting concerns I observed.
Therefore I started adding these two dependencies to my gradle build file.
build.gradle.kts
implementation("org.springframework:spring-aop:5.2.9.RELEASE")
implementation("org.springframework:spring-aspects:5.2.9.RELEASE")
I also added the freefair aspectj plugin due some suggestions from the interwebs.
The following aspect I created should be placed in src/main/aspectj according to this documentation: https://docs.freefair.io/gradle-plugins/5.2.1/reference/#_io_freefair_aspectj
This plugin adds AspectJ support to the project, by adding a aspectj directory to every source set.
Source contained in the src/main/aspectj directory will be compiled with ajc by the compileAspectj task.
plugins {
// ...
id("io.freefair.aspectj") version "5.2.1"
// ...
}
I then started to create my first aspect that matches on every method which is annotated with #Foozy
src/main/aspectj/FoozyAspect.kt < the 'special' source path
#Component
#Aspect
class FoozyAspect {
#Before("#annotation(com.client.annotation.Foozy)")
fun doStuff() {
LOG.info("Do Stuff")
}
companion object {
private val LOG = LoggerFactory.getLogger(FoozyAspect::class.java)
}
}
Then I created this annotation
src/main/kotlin/com.client.annotation/Foozy.kt
#Target(AnnotationTarget.FUNCTION)
annotation class Foozy
Now to test if everything works as expected I created a unit test
src/test/kotlin/FoozyAspectTest.kt
#SpringBootTest
#EnableAspectJAutoProxy
internal class FoozyAspectTest {
private val testCandidate: TestCandidate = TestCandidate()
#Test
fun `should work with aspect`() {
testCandidate.doStuff()
}
}
src/test/TestCandidate.kt
class TestCandidate {
#Foozy
fun doStuff(): String {
return "stuff"
}
}
Result
Executing the text in debug mode does not yield the awaited info log Do Stuff and also does not cease the thread at the breakpoint in the FoozyAspect.kt doStuff() method.
I have no idea what to configure here.
For good reason I kinda have the suspicion that I am mixing up different "ways" to get this to work or am just missing some final steps in preconfiguration/prerequisites.
The AspectJ compiler can't compile Kotlin source code. Your .kt file in src/main/aspectj will be completely ignored.
You have different options depending on what you really want to do:
Do you want your Aspect to be woven by ajc at compile-time, or do you just want to use "plain" Spring AOP?
The differences are explained here: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-choosing
If you just want to use Spring AOP, you dont need a special gradle plugin. Just put your .kt file in src/main/kotlin and follow the Spring AOP docs.
If you want to weave your aspect at compile-time with ajc, you have two options:
Keep the io.freefair.aspectj plugin to compile an weave the aspect in one step: Implement your aspect as .java or .aj so it can be compiled by ajc
Switch to the io.freefair.aspectj.post-compile-weaving plugin in order to separate the compilation an weaving steps: In this case you can keep your Aspect implementation as Kotlin, but you have to put it in src/main/kotlin. Your Aspect will then be compiled by kotlinc and then woven by ajc.
This looks like the 347th duplicate of a classical Spring AOP question: If you read the manual, you will notice that Spring AOP only works for Spring components, e.g. declared via #Component or #Bean.
Your TestCandidate seems to be a POJO, so Spring does not know about it. Also if you make it a component, make sure you get an instance from the container and do not just create one via constructor call in your test.

Spring boot aspectj gradle compile time weaving issue

I have a spring book application, which works fine. I would like to send email notifications to me if there are exceptions thrown from my application. I think aspectj is a good fit.
First, I tried to use Spring AOP runtime weaving, which works OK for public methods. However, I would like to get notified on private methods as well, and I have scheduled tasks. According to Spring AOP doc, runtime weaving won't work for scheduled tasks and private methods. Thus I have decided to use aspectj compile time weaving in my boot application.
I found the official aspectj gradle plugin here:
https://plugins.gradle.org/plugin/at.jku.isse.gradient-gradle
My boot application has this dependency:
compile group: 'org.springframework.boot', name: 'spring-boot-configuration-processor', version:'1.5.14.RELEASE'
My project compiles fine if I use default compiler. But if I use AspectJ compiler, it always complains:
[ant:iajc] warning Field value processing of #ConfigurationProperty meta-data is not supported
[ant:iajc] warning Hibernate JPA 2 Static-Metamodel Generator 4.3.11.Final
[ant:iajc] error at (no source information available)
D:\work\proj\build\classes\java\main\com\abc\dao\entity\Channel_.java:0::0 Internal compiler error: java.lang.Exception: java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/metadata/JsonMarshaller at org.aspectj.org.eclipse.jdt.internal.compiler.apt.dispatch.RoundDispatcher.handleProcessor(RoundDispatcher.java:169)
If I remove that dependency, aspectj compiles ok, I get the jar file. But then when I run my code, I got this:
Caused by: org.springframework.aop.framework.AopConfigException: Advice must be declared inside an aspect type: Offending method 'public void com.proj.aop.AspectConfiguration.afterThrowing(org.aspectj.lang.JoinPoint,java.lang.Throwable)' in class [com.proj.aop.AspectConfiguration]
And this is my Advice class:
package com.proj.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration;
#Aspect
#Configuration
public class AspectConfiguration {
#AfterThrowing (pointcut="execution(* org.hibernate..*.*(..)) || execution(* com.proj..*.*(..))", throwing="excep")
public void afterThrowing(JoinPoint joinPoint, Throwable excep){
System.out.println("inafterthrowing");
}
}
and my appconfig has annotation #EnableAspectJAutoProxy added.
If I replace #Configuration with #Component in my Advice class, I can run my application but the afterthrowing method is not called. Same if I remove #Configuration.
So my questions are:
Why I get the java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/metadata/JsonMarshaller if I have spring-boot-configuration-processor as dependency when compiled by AspectJ?
What is the correct way to use AspectJ in spring boot application and build with gradle? (use #Configuration or #Component? and why my afterthrowing is not called if I use #Component or, why I get exception if I use #Configuration?)
Thanks

EnableLoadTimeWeaving Spring Boot Embedded Tomcat

Caching Aspects are not having any effects at runtime with Spring Boot and Embedded tomcat with LoadTimeWeaving enabled,but we are seeing the weaving is happening fine in the logs.
Below is the configuration, the LoadTimeWeaving is enabled along with the mode as AspectJ for Caching
#Configuration
#EnableConfigurationProperties
#EnableSpringConfigured
#EnableAspectJAutoProxy(proxyTargetClass = true)
#EnableLoadTimeWeaving
#EnableTransactionManagement
#EnableAsync
#EnableCaching(mode = AdviceMode.ASPECTJ)
public class AppConfig {
}
Spring Agent
-javaagent:../../../spring-instrument-4.3.3.RELEASE.jar
Logs
[RestartClassLoader#2aaae670] debug weaving 'uk.co.loyalty.iss.newpro.reporting.domain.refdata.gateway.RestReferenceDataGateway'
[RestartClassLoader#2aaae670] weaveinfo Join point 'method-execution(java.util.List uk.co.loyalty.iss.newpro.reporting.domain.refdata.gateway.RestReferenceDataGateway.getHierarchyLevelDefns())' in Type 'uk.co.loyalty.iss.newpro.reporting.domain.refdata.gateway.RestReferenceDataGateway' (RestReferenceDataGateway.java:118) advised by around advice from 'org.springframework.cache.aspectj.AnnotationCacheAspect' (AbstractCacheAspect.aj:64)
[RestartClassLoader#2aaae670] weaveinfo Join point 'method-execution(java.util.Map uk.co.loyalty.iss.newpro.reporting.domain.refdata.gateway.RestReferenceDataGateway.getHierarchyLevelDefinitionMap())' in Type 'uk.co.loyalty.iss.newpro.reporting.domain.refdata.gateway.RestReferenceDataGateway' (RestReferenceDataGateway.java:129) advised by around advice from '**org.springframework.cache.aspectj.AnnotationCacheAspect**' (AbstractCacheAspect.aj:64)
[RestartClassLoader#2aaae670] **debug generating class** 'uk.co.loyalty.iss.newpro.reporting.domain.refdata.gateway.RestReferenceDataGateway$AjcClosure1'
[RestartClassLoader#2aaae670] debug generating class 'uk.co.loyalty.iss.newpro.reporting.domain.refdata.gateway.RestReferenceDataGateway$AjcClosure3'
there are whole bunch of discussions around this. The weaving is happening on the RestartClassLoader, not sure is it something to do with the class loader. Have also tried adding the below,
#Bean
public LoadTimeWeaver loadTimeWeaver() throws Throwable {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
Please provide your suggestions.
Edit
We need Aspectj mode as we are using caching on private methods. I removed the EnableAspectJAutoProxy but still that does not help.
On further analysis on the load time weaving, I noticed the below behaviour.
I profile the application and investigated on the class loaders to see the weaving is done correct for the caching annotation to work(classes are trasformed). I noticed for some classes in the classloader ,we have a class with suffix($AjcClosure and those are transformed classes after weaving is done). So, if cachinng annotations is part of those weaved classes, then it works fine.
Then I closely looked in to the classes why some classes are weaved correctly and some are not. Then I noticed that if classes are loaded already to the class-loader before weaving happens, then that is where the weaving is not happening.
#Bean
public IAService aService(){
return new AServiceImpl();
}
In the above case, the class is AServiceImpl is loaded to the class loader only when this instance is needed (after load time weaving and caching works perfectly).
But if the same class is being initialised using #Component then it is not getting weaved.
#Service
public class AServiceImpl{
}
I think, in the above case, the class AServiceImpl is loaded to the class loader while the spring container initialises and load time weaving is trying to weave after that).
I verified this behavior again in class loader as well. So, is it an issue if aspectj tries to weave a class that was already loaded. the same problem was raised in the Spring Jira as well in the below link.
https://jira.spring.io/browse/SPR-13786
As mentioned in the above link, if I pass the aspectj weaver as java agent like the below, then all the classes are being weaved correctly. So, is it required to have two agents or do we have any other option for this.
-javaagent:../../../aspectjweaver-1.6.1.jar
-javaagent:../../../spring-instrument-4.3.3.RELEASE.jar
Yes, the weaver needs to be active before the weaving targets are loaded by the classloader.
Now, I am an AspectJ geek but not a container geek, I mainly work with Java SE and no containers. Please try to also add
-javaagent:path/to/aspectjweaver.jar
to your command line and see if it helps.

Gradle compilation ordering issue with mixed Java/Groovy source

I'm having an issue with compilation ordering in a mixed Java/Groovy environment. We're using Gradle 2.1, JDK 7, and Groovy 2.3. The code compiles fine in STS (Spring Tool Suite), using the Gradle plugin and the same build.gradle files, but fails when the build is run on the command line. STS is configured to use the Groovy Eclipse plugin, which if I understand things correctly, uses its own compiler. So I think this problem stems from a compilation ordering problem when we use the Groovy compiler from Gradle's Groovy plugin. This is the Groovy class:
#Component
#ToString(includeNames = true, includePackage = false)
class ManagedCloseableHttpClientFactory implements ClientHttpRequestFactory {
#Delegate
HttpComponentsClientHttpRequestFactory factory
...
}
The ClientHttpRequestFactory is a Spring interface that is implemented by the Spring class HttpComponentsClientHttpRequestFactory. Somewhere else in the system, we have a Java class annotated with #Configuration, where the ManagedCloseableHttpClientFactory is injected using #Autowired. Like this:
#Configuration
public class FooConfiguration {
#Autowired
private ManagedCloseableHttpClientFactory httpClientFactory;
...
}
When the build is run from the command line, we get the following error message: /Users/xyz/source/prj/common/build/tmp/compileGroovy/groovy-java-stubs/common/web/client/ManagedCloseableHttpClientFactory.java:10: error: ManagedCloseableHttpClientFactory is not abstract and does not override abstract method createRequest(URI,HttpMethod) in ClientHttpRequestFactory. If we move the field marked with #Autowired to a Groovy class that is annotated with #Configuration, everything works, but not when it's declared inside a Java class. I'm guessing that this is a compilation ordering issue. In our Gradle files, we're using the groovy plugin, and have modified the source directories as follows:
project.sourceSets.main.java.srcDirs = []
project.sourceSets.test.java.srcDirs = []
project.sourceSets.main.groovy.srcDirs = ["src/main/java", "src/main/groovy"]
project.sourceSets.main.resources.srcDirs += ["config"]
project.sourceSets.test.groovy.srcDirs += ["src/test/java","src/test/groovy"]
What's the best approach here? Thanks.
The Groovy compiler's stub generator has some limitations. My best guess is that you can't have Java call a Groovy method materialized by #Delegate. I'd try to get rid of this particular Java->Groovy dependency or this particular usage of #Delegate (i.e. implement the delegation by hand).
If possible inject the interface instead of the concrete class. Since the injection happens on run time the class will be full created then, and in compile time compiler will recognize the interface as having all the required fields.
#Configuration
public class FooConfiguration {
#Autowired
private ClientHttpRequestFactory httpClientFactory;
...
}

Spring Transaction with AspectJ

I'm having a problem with #Transaction in Spring.
Basically, no transaction is created with the following message:
delaying identity-insert due to no transaction in progress
I posetd a full description of the problen in the Spring AOP forum
http://forum.springsource.org/showthread.php?132612-Transaction-management
Any suggestion would be appreciated!
Stefano
in your code you have defined the service like this:
#Service
#Configurable
public class ServiceImpl<T> implements Service<T> {
#Override
#Transactional
public T save(T entity) {
....
}
}
I do not know why you use the #Configurable annotation. If you do not need them (that is if you do not create an instance of this service via new) , I would remove them.
The reason is that I remember that spring docu say that #Configurable enable injection, but it does not say anything about load time weaving support enabled by #Configurable
Found the solution.
The problem was in the configuratoin. I added two elements context:spring-configured and context:load-time-weaver that mean two different things. The first one activate AspectJ compile time weaving (which I didn't understand), the second one activate AspectJ load time weaving. I think that these two elements don't work well together.
I decided to use compile time weaver and (after struggling a little bit...) I found that (obviously) external jars are not weaved with this configuration, simply because they have yet been built.
The easiest way to solve is to modify the configuration of the aspectj-maven-plugin (in POM.xml) adding under the configuration node:
<weaveDependencies>
<weaveDependency>
<groupId>GROUP-ID</groupId>
<artifactId>ARTIFACT-ID</artifactId>
</weaveDependency>
</weaveDependencies>
for every artifact you need to weave.
Now transactions work fine!
#Ralph: many thanks for your time!
Regards,
Stefano

Resources