How to hijacked/intercept method of a class which from third party(EclipseLink) jar or even JDK? - spring

I try to hijack/intercept a method of a class in EclipseLink. I had tried Spring AOP and AspectJ and I failed. I want to do something when class org.eclipse.persistence.internal.localization.i18n.TraceLocalizationResource throw exception while calling method getString(..); My implementation as below:
#AfterThrowing(pointcut = "execution(* org.eclipse.persistence.internal.localization.i18n.TraceLocalizationResource.getString(..))",throwing="error")
public void logAfterThrowing(JoinPoint joinPoint,Throwable error) {
....
}
And calssTraceLocalizationResource was called (I debug into it). But the hijack method wasn't called.
MY questions:
Was I doing it in the wrong way ?
The target class we want to hijack or intercept must be self-define type?
What if I want to hijack a class in JDK like java.lang.String ?

Basically the syntax looks okay, but I have not tried to replicate a
full aspect from your code snippet here. Furthermore, I only use
native AspectJ syntax and am not quite familiar with
annotation-based syntax, so if there is a problem there I might not
have seen it.
No, but if you want to weave a library (JAR or unpacked into the file system) used by your main application, you must make sure that it is in the in-path for the weaver. Please consult AspectJ documentation for the syntax. Edit: I posted some helpful links in another answer earlier today.
By default, packages org.aspectj, java and javax are excluded from weaving. For the latter two, there are command line switches to enable weaving. But LTW will be tricky at best and a pain in the a** (next to impossible) at worst because you have a hen-and-egg problem there: The AspectJ weaver runtime classes need the JDK, and JDK bootstrapping happens before any Java agent like the weaver is attached. So your best bet is compile-time weaving for JDK classes and then using the woven rt.jar later in your application. Even with compile-time weaving you might run into issues if your advice use JDK woven classes themselves. You want to make sure to avoid infinite recursions there. But it is possible.
Update: Another hint which sometimes seems too simple to mention for someone who has used AspectJ for a while: Instead of an execution pointcut which makes it necessary to weave the target class, you may just use a call pointcut which intercepts (as the name implies) calls to the target everywhere in your client classes. It might be a little less efficient, but maybe your best and easiest bet unless you really want to take the trouble of weaving the JDK.

It is possible to weave third party libraries but you must configure the aspectj-maven-plugin plugin:
<project>
...
<dependencies>
...
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.agroup</groupId>
<artifactId>to-weave</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.anothergroup</groupId>
<artifactId>gen</artifactId>
<version>1.0</version>
</dependency>
...
</dependencies>
...
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.9</version>
<configuration>
<weaveDependencies>
<weaveDependency>
<groupId>org.agroup</groupId>
<artifactId>to-weave</artifactId>
</weaveDependency>
<weaveDependency>
<groupId>org.anothergroup</groupId>
<artifactId>gen</artifactId>
</weaveDependency>
</weaveDependencies>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
<build>
...
</project>
Source: http://www.mojohaus.org/aspectj-maven-plugin/examples/weaveJars.html

Related

Spring 4 Java Config Transactions Proxy and Aspecj

I am creating a new project that uses aspectj transactions. It also uses legacy jars that contain services that are using the proxy method where an interface is required.
I am using java config and when I set
#EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
Then I get the following exception thrown with accessing the proxy style services from the legacy libs:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
If I change to:
#EnableTransactionManagement(mode=AdviceMode.PROXY)
Then I don't get the problem but I can't then use the aspectj style transactions in my new project.
I've tried adding two #EnableTransactionManagement annotations with each adviceMode, but that is not allowed.
Here is the annotated class
#EnableWebMvc
#Configuration
#ComponentScan("com.mydomain")
#EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
public class ApplicationConfig extends WebMvcConfigurerAdapter {
...
I've also added the aspectj maven plugin to the legacy project in the hope that it would handle the weaving at compile time and thus aspectj transactions would work. But this has not solved the problem.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
Is it possible to have spring deal with both advice modes? How would I do this?
Or is there another way around this problem.
The problem was with the aspectj config on the legacy project.
When I ran mvn compile it became apparent. I had to add the dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
That got it working when compiled using maven, but I it would still not work in eclipse. I had to right click on the legacy project in eclipse:
Configure>Convert to Aspectj Project
Then I could deploy from eclipse and I had aspectj transactional support in the legacy jars.

aop performance on spring (idk, aspectj)

I tried to test the performance of AOP on Spring framework 4.1.6 and
AOP methods were clean, jdk dynamic proxy and aspectJ.
I made one to five simple advices to them and checked elapsed time for each.
result:
jdk dynamic proxy:
aspect1: 2.499 sec.
aspect2: 2.574
aspect3: 2.466
aspect4: 2.436
aspect5: 2.563
aspectJ (ctw):
aspect1: 2.648
aspect2: 2.562
aspect3: 2.635
aspect4: 2.520
aspect5: 2.574
clean (no aspect):
aspect1: 2.699
aspect2: 2.513
aspect3: 2.527
aspect4: 2.458
aspect5: 2.402
Before testing them, I expected AspectJ (ctw) will be faster than Jdk dynamic proxy because AspectJ modified bytecode. But it was wrong even there was no performance difference among them.
So, I checked the target class(.class) modified to recognise that AspectJ Compiler used and found bytecode modified.
Here, I have question:
Is there any performance difference among them? (idk dynamic proxy, aspectj, no aop)
My code:
public class HelloAOP {
public static void main(String [] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/application-context.xml");
Order order = (Order) ctx.getBean("orderImpl");
SimpleDateFormat format = new SimpleDateFormat("mm:ss.SSS");
StopWatch watch = new StopWatch();
watch.start();
order.placeOrder();
watch.stop();
System.out.println("Elapsed: " + format.format(watch.getTotalTimeMillis()));
}
}
target:
#Service
public class OrderImpl implements Order {
public void placeOrder() {
System.out.println("::Target Object");
for(long i = 0; i < 5000000000L; i++);
}
}
aspect:
#Aspect
#Component
public class Aspect1 {
#Before("execution(* com.cafe.beans.impl.OrderImpl.placeOrder())")
public void aspect() {
System.out.println("Aspect 1 *");
}
}
pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.6</version>
</dependency>
<build>
<finalName>testAop</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>3.3</source>
<target>3.3</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<complianceLevel>1.8</complianceLevel>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
You should not be surprised not to see any difference because you are just measuring one single method call. 99.9% of the time measured is the loop inside your method. Ergo you are not measuring the right thing. You should do it the other way around, maybe similar to what I did here:
The method should do nothing or next to nothing and print nothing.
You should measure the overall time of repeatedly calling an aspect-advised method because you want to find out about the overhead of applying an aspect, not about method body runtime (the method body remains unchanged by your aspect).
Now you can compare Spring AOP to AspectJ performance and should see that AspectJ is superior. A few caveats:
I hope you know that you need to change the Spring configuration so as to switch from Spring AOP to AspectJ and vice versa. E.g. if you use the AspectJ Maven Plugin all the time for your builds, you will use compile-time AspectJ weaving, no matter if you configure Spring to use Spring AOP or AspectJ via load-time weaving as described in the Spring manual, section 10.8 Using AspectJ with Spring applications.
You should measure different types of pointcuts and advice, e.g. #Before/#After vs. #Around, (not) using parameter binding via this(), target() or args() etc.
Please also note that your sample code uses a pointcut on a class rather than an interface. JDK dynamic proxies do not work directly on classes, though, only on interfaces. In order to apply Spring AOP on classes, you need CGLIB as a dependency in Spring, otherwise it simply will not work. Edit: Okay, your class implements the Order interface, so it might still work with JDK dynamic proxies.

JUnit tests fail with Java error when using IntelliJ within maven module after adding Hibernate Metamodel classes

On my project we've used Hibernate's (JPA) Metamodel Generator to make our Criteria queries type safe. It all works great within our app, however, when we run the JUnit tests within that Maven module using our IDE they now fail with the following error:-
Error:java: Annotation processor 'org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor' not found
Which I guess is due to the following in our generated classes:-
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(MyEntity.class)
When Maven runs the tests as part of our build process then they run with no problems at all.
I suspect I'm missing something within the set up of my IDE, which is IntelliJ IDEA 14. Any ideas what this might be? Or have I done something wrong within Maven? :-
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>2.1.0</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>4.3.4.Final</version>
<optional>true</optional>
</dependency>
</dependencies>
</plugin>
I had a similar problem after I upgraded to IntelliJ IDEA 14.1.2. For me the following action resolved the problem:
Go to Settings > Build, Execution, Deployment > Compiler > Annotation Processors.
On the left of this configuration panel I have an Annotation profile for every maven module in my project. I did not set up these profiles myself: maybe they where inferred by the IDE. I don't know, but in some of these annotation profiles, the enable annotation processing flag was enabled. Moreover, in some cases, the JPAMetaModelEntityProcessor was explicitly listed here as an annotation processor. After removing the annotation processor from the profile and disabling the checkbox, the error disappeared and my test ran successfully.
The answer by #Jeroen Noels disables annotation processing in IDEA.
To keep it enabled I've added
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>4.3.4.Final</version>
<scope>provided</scope>
</dependency>
to the Maven dependencies, i.e. to the classpath. Note that the scope is provided!

How to pass dependencies for JSR-269 processor to maven-compiler-plugin

I have a JSR-269 annotation processor that I am attempting to invoke from within a Maven build using the maven-compiler-plugin. The processor has a dependency on the SLF4J library, but I cannot figure out how to pass it properly to the compiler plugin so the processor can find it. AS a consequence I am getting the standard SLF4J error when it cannot find a logging binding.
Currently my plugin definition looks like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessors>
<annotationProcessor>com.mycompany.MyProcessor</annotationProcessor>
</annotationProcessors>
<proc>only</proc>
</configuration>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
</plugin>
Anyone know how to do this?
I think adding slf4j as normal project dependency instead as plug-in dependency should work in your set-up. Alternatively you could use the Maven Annotation Plug-in which allows to specify annotation processors (and their dependencies) as plug-in dependency.

Can ApacheCXF generate full constructors when using the cxf-codegen-plugin for Maven?

I generate server/client from my wsdl/xsd's using the cxf-codegen-plugin for Maven. All the types created have default no-arg-constructors, which makes them a pain to work with.
Is there any way to make Apache CXF generate a full constructor aswell, with all the members of the class as arguments?
This plugin is just a fancy wrapper around xjc.
There are two xjc plugins that address your problem space:
Value-constructor exactly what you are looking for.
Fluent-api not exactly what you are looking for, but many prefer a fluent api to value constructors.
You need to add the required dependencies and then configure the plugin to enable those plugins in xjc, e.g.
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<configuration>
<defaultOptions>
<extraargs>
<extraarg>-xjc-Xvalue-constructor</extraarg>
</extraargs>
</defaultOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-value-constructor</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.6.4</version>
</dependency>
</dependencies>
</plugin>
Note: the above makes this a default for all executions, if you want to enable those options for a specific execution only, then just add the <configuration> bit into that specific execution.

Resources