Tag Archives: AspectJ

Gradle + Eclipse plugin: Add AspectJ nature into projects

I have found nice script for adding AspectJ nature into Eclipse project using Gradle. See https://github.com/breskeby/gradleplugins/blob/0.9-upgrade/aspectjPlugin/aspectJ.gradle#L29 . Unfortunately each run of ‘gradle eclipse’ adds new nodes into project XML. Here is my fix of that issue:


eclipse.project.file.withXml { xmlProvider->
  def projectDescription = xmlProvider.asNode()
  def xmlparser = new XmlParser()

  def builders = projectDescription.buildSpec[0]

  if (!builders.buildCommand.any {it.name[0].value()=='org.eclipse.ajdt.core.ajbuilder'}) {
    def ajbuilder = xmlparser.createNode(builders, 'buildCommand', [:])
    xmlparser.createNode(ajbuilder, 'name', [:]).setValue('org.eclipse.ajdt.core.ajbuilder')
    xmlparser.createNode(ajbuilder, 'arguments', [:]);
  }

  def natures = projectDescription.natures[0]

  if (!natures.nature.any {it.value()=='org.eclipse.ajdt.ui.ajnature'}) {
    def ajnature = xmlparser.createNode(null, 'nature', [:])
    ajnature.setValue('org.eclipse.ajdt.ui.ajnature');
    natures.children().add(0, ajnature)
  }
}

Then all nodes are created only once.

Advertisements

Ultimate AspectJ method tracing

In last post and previous one I had shown how to setup AspectJ waving. There were also sample of simple method tracing. Here goes ultimate version:


package com.sample.utils;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Aspect
public class MyLogger {

private static final Logger logger = LoggerFactory.getLogger(MyLogger.class);

public MyLogger() {
}

@Before("execution(* com.klasses..*(..))")
public void logBefore(JoinPoint point) {
logger.trace("Autotrace entry {}.{}({})", point.getSignature().getDeclaringTypeName(), point.getSignature()
.getName(), point.getArgs());
}

@AfterReturning(pointcut = "execution(* com.klasses..*(..))", returning = "result")
public void logAfter(JoinPoint point, Object result) {

boolean hasReturnValue = true;

if (point.getSignature() instanceof MethodSignature) {
hasReturnValue = !((MethodSignature) point.getSignature()).getReturnType().getCanonicalName().equals("void");
}

if (hasReturnValue) {
logger.trace("Autotrace exit {}.{}({}) returned {}", point.getSignature().getDeclaringTypeName(), point
.getSignature().getName(), point.getArgs(), result);
}
else {
logger.trace("Autotrace exit {}.{}({})", point.getSignature().getDeclaringTypeName(), point.getSignature()
.getName(), point.getArgs());
}

}

@AfterThrowing(pointcut = "execution(* com.klasses..*(..))", throwing = "error")
public void logThrow(JoinPoint point, Throwable error) {
logger.trace("Autotrace exit {}.{}({}) throwed {}", point.getSignature().getDeclaringTypeName(), point
.getSignature().getName(), point.getArgs(), error);
}
}

AspectJ and Gradle

In recent post I have described dynamical way of AspectJ waving. Today I have tried compile time way. So no JAVA_TOOL_OPTIONS is necessary.

Gradle build

See https://github.com/eveoh/gradle-aspectj for details:


buildscript {
repositories {
maven {
url "https://maven.eveoh.nl/content/repositories/releases"
}
}

dependencies {
classpath "nl.eveoh:gradle-aspectj:1.5"
}
}

project.ext {
aspectjVersion = '1.8.6'
}

apply plugin: 'java'

//eclipse support
apply plugin: 'eclipse'
apply plugin: 'eclipse-wtp'

apply plugin: 'aspectj'

Eclipse build

In Eclipse install through Help->Eclipse Marketplace plugin “AspectJ Development tools”. Then add into Gradle (adjusted version of https://github.com/breskeby/gradleplugins/blob/0.9-upgrade/aspectjPlugin/aspectJ.gradle#L29):


eclipse.project.file.withXml { xmlProvider->
def projectDescription = xmlProvider.asNode()
def xmlparser = new XmlParser()

def builders = projectDescription.buildSpec[0]
def ajbuilder = xmlparser.createNode(builders, 'buildCommand', [:])
xmlparser.createNode(ajbuilder, 'name', [:]).setValue('org.eclipse.ajdt.core.ajbuilder')
xmlparser.createNode(ajbuilder, 'arguments', [:]);

def natures = projectDescription.natures[0]
def ajnature = xmlparser.createNode(null, 'nature', [:])
ajnature.setValue('org.eclipse.ajdt.ui.ajnature');
natures.children().add(0, ajnature)
}

Then execute gradle eclipse, refresh workspace and run Project->Clean->All projects. Then start your project and waving should be already done. You can check existence of AspectJ builder in context menu of project, Properties->Builders->AspectJ Builder.

AspectJ LTW + Tomcat 8 + Eclipse + OpenJDK 8

Recently I was trying to get working AspectJ on Tomcat 8 using OpenJDK 8. I had selected LTW (Load-Time Waving) approach. Waving is modification of bytecode so that aspect methods may be called.

My intention was to create simple logging aspect that will log traces of all method in certain package. I spent terrible, hot day on it. Coding was simple:

package com.myutils;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Aspect
public class MyLogger {

 private static final Logger logger = LoggerFactory.getLogger(MyLogger.class);

 @Before("execution(* com.mypackage..*(..))")
 public void log(JoinPoint point) {
 logger.trace("Autotrace {}.{}({})", point.getSignature().getDeclaringTypeName(), point.getSignature().getName(),
 point.getArgs());
 }

}

Here goes some memo which will maybe help you:

Dependencies

We use Gradle:

compile("org.aspectj:aspectjrt:1.8.6")
compile("org.aspectj:aspectjweaver:1.8.6")

Tomcat 8

Tomcat must be launched with -javaagent property. This agent is responsible for on-the-fly waving.

-javaagent:/home/my/path/aspectjweaver-1.8.6.jar

Best is to put it into “JAVA_TOOL_OPTIONS” before starting Tomcat. In Eclipse you can set this variable into Run configuration->Environment.

Configuration

It is absolutely crucial to have aop.xml on classpath. The path must be exactly “META-INF/aop.xml“. So for my .war project it was not enough to put it into /src/webapp/META-INF/aop.xml because that is not on classpath. I have put it into /src/resources/META-INF/aop.xml and Voila! If this file is not presented, no exception or warning is shown.

Scope of Waving

It is crucial to have Aspect classes as part of Waving. Otherwise error “java.lang.NoSuchMethodError: com.myutils.MyLogger.aspectOf()” is generated.

<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>

 <!-- -verbose -debug -->
 <weaver options="-showWeaveInfo">
 <include within="com.mypackage.*" />
 <include within="com.myutils.*" />
 </weaver>
 <aspects>
 <aspect name="com.myutils.MyLogger" />
 </aspects>
</aspectj>

Compilation

Code must be compiled with debug symbols (javac -g) otherwise LTW won’t work. In Eclipse that means to run it in debug mode.

Conclusion

For beginner in AspectJ it was terribly hard to get working solution. One of path I tried was through Spring AOC, but it does not helped because Spring AOC is basically just wrapper of AspectJ waving tooling.

Please note this post is based on 1 day experience with AspectJ 😉 I hope this helps you not to waste time on same pitfalls as I did!