Develop AspectJ Library

AspectJ is an aspect-oriented programming (AOP) extension created at PARC for the Java programming language. – Wikipedia

In fact, things like Servlet Filters, EJB interceptors, or even database triggers are all sharing the concept of AOP. This article will focus on AspectJ in particular. Personally, I feel AspectJ gives a every different view on how software can be written. A weird thing that I found was most AspectJ related documentations were quite old. But, since it’s popular in many mordern frameworks such as Spring, I guess it’s worth to learn.

How is an AspectJ project used by other projects as a library?

To develop an AspectJ project and make other projects to use it, you have to know how the aspects are applied to the targeted components. AspectJ uses bytecode manipulation mechanism to intervene certain life cycle events of java classes at compile time. Because of that, it wouldn’t work if an AspectJ project is just being imported normally. Instead, it must be picked up at compile time to manipulate the bytecode when the targeted classes are generated. In fact, AspectJ has its own compiler, which could either be used standalone or work together with your chosen javac for jdk version control purposes.
To prepare for the practice in the rest sections, you need to have AspectJ Development Tools (AJDT) installed on your Eclipse. Although, I’ll introduce based on Eclipse, you can also develop AspectJ project with Intellij and NetBeans.

Eclipse plugin

AJDT is an eclipse plugin. You can find multiple versions of it. The latest one is 4.6 (copy the url as an Eclipse repository to install).

Intellij setup

You can find an introduction of how to set up your Intellij to work with AspectJ.

NetBeans plugin

There is a third party plugin called AspectJ-for-NetBeans developed quite a while ago (I heard it was developed by one person, which is very impresive).

Build an AspectJ project

There are various ways to create an AspectJ project: you can simply create an AspectJ project from scratch; you can have an existing Java project to convert to an AspectJ project. The way I’m going to do it is to create a Maven AspectJ project. By doing so, I would be able to just install my project to a local or remote repository. When it turns to that other project needs to import this AspectJ project, it can be done by just configuring the Maven configurations.

Create a Maven AspectJ project

A Maven AspectJ project is a maven project with a few AspectJ related configurations to assist while going through compile phase. Therefore, a simple Maven project is good to go for this practice.
Here is the initial pom.xml file I have (really nothing more than a simple initial pom file):
<project xmlns="http://ift.tt/IH78KX"
    xmlns:xsi="http://ift.tt/ra1lAU"
    xsi:schemaLocation="http://ift.tt/IH78KX http://ift.tt/VE5zRx">
    <modelVersion>4.0.0</modelVersion>
    <groupId>ca.ljz</groupId>
    <artifactId>special-logger</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</project>
By default, this project would not compile with AspectJ. To do that, we need to add:
  1. aspectj-maven-plugin
  2. aspectjrt (AspectJ run time dependency)
Optional: properties are optional. I added the above plugins and dependencies in <pluginManagement> and <dependencyManagement> first, which can be added to <plugins> and <dependencies> directly.
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.source-target.version>1.8</java.source-target.version>
    <aspectj.version>1.8.7</aspectj.version>
</properties>
<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>${java.source-target.version}</source>
                    <target>${java.source-target.version}</target>
                    <!-- IMPORTANT -->
                    <useIncrementalCompilation>false</useIncrementalCompilation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.7</version>
                <configuration>
                    <!-- OPTIONAL
                    <showWeaveInfo>true</showWeaveInfo>
                    -->
                    <source>${java.source-target.version}</source>
                    <target>${java.source-target.version}</target>
                    <Xlint>ignore</Xlint>
                    <complianceLevel>${java.source-target.version}</complianceLevel>
                    <encoding>${project.build.sourceEncoding}</encoding>
                    <!-- OPTIONAL
                    <verbose>true</verbose>
                    -->
                    <!-- OPTIONAL
                    <warn>
                        constructorName,
                        packageDefaultMethod,
                        deprecation,
                        maskedCatchBlocks,
                        unusedLocals,
                        unusedArguments,
                        unusedImport
                    </warn>
                    -->
                </configuration>
                <executions>
                    <execution>
                        <!-- IMPORTANT -->
                        <phase>process-sources</phase>
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
        </plugin>
        <!-- OPTIONAL
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
        </plugin>
        -->
    </plugins>
</build>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
    </dependency>
</dependencies>
The Maven AspectJ project now is created. As we mentioned above, the project needs to be compiled with either ajc (AspectJ compiler) or both ajc and javac. Please refer to the comments in the above pom settings to figure out how to do it in either way.

Create an annotation (optional)

Creating an annotation is not a must. But since it’s a common practice, I just want to show how to work with annotations in AspectJ. So, create an annotation first. It can be something like this:

package ca.ljz.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(java.lang.annotation.ElementType.METHOD)
public @interface Log{
    String prefix() default "";
}

The purpose of this annotation is to let user place it on a specific method to log. It doesn’t sound like how most loggers work, but it’s good for this example.
Other than using an annotation, AspectJ can also catch a predefined signature pattern, e.g. a method signature pattern such as set* or get* etc. But, when programming a library, it’s very unlikely to use pattern matches in most case. The exceptions are setters and getters, etc.

Create an aspect

In AspectJ, an aspect is a special entity contains the descriptions of when and how to deal with life cycle events of targeted java classes. The following code stub describes a log aspect for what we are doing:

package ca.ljz.aspects;

import ca.ljz.annotations.Log;
import org.aspectj.lang.reflect.MethodSignature;

public aspect LogAspect {

    pointcut log() : execution(* *(..)) && @annotation(Log);

    before() : log() {
        System.out.println("enter "
            + ((MethodSignature) thisJoinPoint.getSignature()).
                getMethod().getAnnotation(Log.class).prefix()
            + thisJoinPoint.getSignature());
    }

    after() : log() {
        System.out.println("exit "
            + ((MethodSignature) thisJoinPoint.getSignature()).
                getMethod().getAnnotation(Log.class).prefix()
            + thisJoinPoint.getSignature());
    }
}
Here is a list of the meanings of each part of the pointcut declaration.

  • log(): the identifier of this pointcut, which can be referred in advices
  • execution: the action of the target to be intercepted
  • 1st *: this star indicate that the return type can be anything
  • 2nd *: this is the name pattern of methods, which in this case, means any name
  • (..): this refers to the parameter pattern, which in this case, means any parameter(s)
  • &&: this is an logic operator, which indicates both sides condition must satisfied
  • @annotation(Log): this means that there must be a Log annotation

before() and after() are the time points to indicate when the advice should be executed.
To know more about AspectJ syntax, here are some useful links:

Install the library

There are several types of places you can install your library. Just to keep things as simple as possible, I’m just going to run a built-in maven phase: install. You can easily find it by right click on the project, and it’s in Run As sub menu.

Import an AspectJ project

Like building an AspectJ project, to import an AspectJ project also requires to add/change to the AspectJ compiler. Depending on how you build your project, there are different ways to accomplish this.

Non-maven project

For a non-maven project, you need to:

  1. Convert the Java project to AspectJ project (right click project -> configure);
  2. Add the library into Project Build
  3. Add the library into AspectJ Build Inpath (project properties -> AspectJ Build);

Maven project

For a maven project, you need to:

  1. Configure the project into a Maven AspectJ project (see Create a Maven AspectJ project section);
  2. Add the library as a dependency;
  3. Add the library as an <aspectLibrary> into <configuration> in aspectj-maven-plugin
To add the library into aspectj-maven-plugin <configuration>, it needs to include <groupId> and <artifactId>. The aspect library is something like this:

<aspectLibraries>
    <aspectLibrary>
        <groupId>ca.ljz</groupId>
        <artifactId>special-logger</artifactId>
    </aspectLibrary>
</aspectLibraries>

In particular, to use this library, you just need to add @Log on any method. The project to import AspectJ library project can be either a jar or a war project.

This blog may not be up to date. Please see the original post from Blogger http://ift.tt/2i8nNMm
via IFTTT.