Hot questions for Using AspectJ in eclipse

Question:

I have a project that uses aspectj-maven-plugin:

org.codehaus.mojo aspectj-maven-plugin 1.8

In eclipse(mars) I try to import the project as a maven project but I get error below.

problem was encountered while building the effective model for org.codehaus.mojo:aspectj-maven-plugin:1.8 [ERROR] 'dependencies.dependency.systemPath' for com.sun:tools:jar must specify an absolute path but is ${toolsjarSystemPath} @

I have tried adding toolsjarSystemPath to my properties in my Settings.xml. No luck. I have tried adding "-vm C:\Program Files\Java\jdk1.7.0_79\lib" to eclipse.ini. Again, no luck. Does anyone know any other solutions for this problem? I have set my JAVA_HOME to: "C:\Program Files\Java\jdk1.7.0_79"

I have no clue anymore... The solutions of [error upgrading aspectj-maven-plugin v1.8

[1]: error upgrading aspectj-maven-plugin v1.8 don't work


Answer:

As I already wrote in another answer (but StackOverflow answers which are just links get deleted, so I repeat myself here):

I found a problem in AspectJ Maven plugin and fixed it. My pull request was finally merged and is contained in the new plugin version 1.9. Just upgrade your POM and enjoy.

P.S.: The real problem is in Eclipse, but it was easier to put a workaround into the Maven plugin than to get it fixed upstream.

Question:

I have quite annoying problem with Eclipse and AspectJ. After each change in class that is under effect of aspect I need to do a full project rebuild (clean). Anyone have an idea how can I avoid that?

package pl.xxx.infrastructure.jdbc;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareParents;
import org.aspectj.lang.annotation.Pointcut;

import pl.xxx.infrastructure.jdbc.common.UpdateEntityInterface;

@Aspect
public class UpdateEntityAspect {

    /**
     * Wyszukiwanie wszystkich klas z adnotacją Entity
     */
    @Pointcut("within(@javax.persistence.Entity pl.xxx..*)")
    public void beanAnnotatedWithEntity() {
    }

    /**
     * Wyszukiwanie wszystkich metod z nazwą rozpoczynającą się od set
     */
    @Pointcut("execution(public * set*(..))")
    public void setMethod() {
    }

    /**
     * Wyszukiwanie wszystkich pol w momencie zmodyfikacji ich stanu
     */
    @Pointcut("set(private * *)")
    public void privateField() {
    }

    /**
     * Nadawanie encji dodatkowego interfejsu / wstrzykiwanie dodatkowych pol
     */
    @DeclareParents(value = "@javax.persistence.Entity pl.xxx..*", defaultImpl = UpdateEntityInterface.UpdateEntityInterfaceImpl.class)
    UpdateEntityInterface updateEntityInterface;

    /**
     * Kod wstrzykiwany podczas modyfikowania pola encji
     * 
     * @param joinPoint
     * @param entity
     */
    @Before("beanAnnotatedWithEntity() && privateField() && target(entity)")
    public void onSetExecuted(JoinPoint joinPoint, Object entity) {
        if (entity instanceof UpdateEntityInterface) {
            UpdateEntityInterface updateEntityInterface = (UpdateEntityInterface) entity;
            updateEntityInterface._markUpdated(joinPoint.getSignature().getName());
        }
    }

}

Class under Aspect infuence:

package pl.xxx.model.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.lang3.StringUtils;

@Entity
@Table(name="CUSTOMER")
public class Customer implements Serializable {

    private static final long serialVersionUID = 9128787620983157104L;

    @Id
    @SequenceGenerator(name="IdGenerator", sequenceName="SEQ_CUSTOMER", allocationSize=1)
    @Column(name="ID", unique=true, nullable=false, precision=15, scale=0)  
    protected Long id;

    @Column(name="FILE_TYPE", length=3)
    @CorelatedEnum(IncomingFileType.class)
    private String fileType;
}

Error: The type Customer must implement the inherited abstract method UpdateEntityInterface._getUpdatedFields() Customer.java line 17 Java Problem


Answer:

  1. Use Andy Clement solution - DeclareMixin instead of DeclareParents
  2. Try to put your aspect classes into other lib (project) as default spring aspects. If you hava maven project you can add them as follows

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <configuration>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>...</groupId>
                        <artifactId>...</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
        </plugin>
    

Question:

I'm trying to get started with aspect oriented programming. I'm using latest eclipse (currently 12-2019)

public aspect Observer {

}

This Results in an error Syntax error on token "aspect", interface expected

According to https://www.eclipse.org/ajdt/downloads

I added http://download.eclipse.org/tools/ajdt/43/update

as an update site to eclipse

However eclipse tells me that some parts could not be installed

It looks Like some parts are missing

Cannot complete the install because one or more required items could not be found. Software being installed: AspectJ Development Tools 2.2.3.e43x-RELEASE-20130627-0800 (org.eclipse.ajdt.feature.group 2.2.3.e43x-RELEASE-20130627-0800) Missing requirement: AspectJ 1.7.3.20130613144500-a (org.aspectj.ajde 1.7.3.20130613144500-a) requires 'osgi.bundle; org.eclipse.core.runtime.compatibility 0.0.0' but it could not be found Cannot satisfy dependency: From: AspectJ Compiler 1.7.3.20130613144500-a (org.aspectj.feature.group 1.7.3.20130613144500-a) To: org.eclipse.equinox.p2.iu; org.aspectj.ajde [1.7.3.20130613144500-a,1.7.3.20130613144500-a] Cannot satisfy dependency: From: AspectJ Development Tools 2.2.3.e43x-RELEASE-20130627-0800 (org.eclipse.ajdt.feature.group 2.2.3.e43x-RELEASE-20130627-0800) To: org.eclipse.equinox.p2.iu; org.aspectj.feature.group [1.7.3.20130613144500-a,1.7.3.20130613144500-a]

How could I Get Aspects to run in Eclipse? Could you help me out?


Answer:

Your problem caused by the removal of org.eclipse.core.runtime.compatibility plugin from Eclipse 4.6 .

Read more about this problem here.

The correct solution is to:

Install AspectJ from the correct download link.

The most updated to Eclipse 4.10 is: http://download.eclipse.org/tools/ajdt/410/dev/update

Another solution is to:

  1. Uninstall Eclipse.

  2. Install Eclipse 4.3 (matching your AspectJ version) .

  3. Retry AspectJ install.

The more complex solution is:

  1. Locate and build/extract org.eclipse.core.runtime.compatibility jar file from Maven repository.

  2. Put org.eclipse.core.runtime.compatibility jar file into Eclipse plugins directory.

  3. Run eclipse in --clean mode to rebuild and register the added plugin.

  4. Retry AspectJ install.

You might encounter more missing dependencies for org.eclipse.core.runtime.compatibility, eventually will have to load all the related plugins (long effort).

Question:

I want to do specific action when System.currentTimeMillis() is called. I use AspectJ as below to do that.

public aspect CurrentTimeInMillisMethodCallChanger {
    long around(): 
    call(public static native long java.lang.System.currentTimeMillis()) {
        //provide my own implementation 
    }
}

This program works fine when System.currentTimeMillis() is called in any method of the application.

However, when System.currentTimeMillis() is called from method inside a jar file then around is not executed. I used within(packageofJarFile.*), but it does not work.

I am using Eclipse.

Please let me know what I need to add to the above code to support call from (specific) jar file as well ?


Answer:

You need to set up the AspectJ plugin for Eclipse (AJDT), so that it weaves library code as well, not just your own class files. You can do this by going to Project Properties -> AspectJ Build -> Inpath tab and add the jar files you want to be weaved by your aspects. Here is a screenshot of the dialog: The library classes weaved like this will be dumped in your output classes folder unless you set up an Output jar on the third tab of the same properties page.

Question:

I've developed a nice Spring Aspect which I can use to monitor my service operations performance. If some operations are taking a long time to execute, it logs them.

@Aspect
public class PerformanceMonitorAspect {

    private Logger logger = LoggerFactory.getLogger("performance");

    @Pointcut("execution(* com.company.MyService+.*(..))")
    public void pointCut(){

    }

    @Around("pointCut()")
    public Object profileServiceMethods(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        MethodSignature ms = (MethodSignature) thisJoinPoint.getSignature();
        Method m = ms.getMethod();
        long t1 = System.nanoTime();
        Object result = thisJoinPoint.proceed();
        long t2 = System.nanoTime();
        long millis = TimeUnit.NANOSECONDS.toMillis(t2 - t1);
        if (millis < 1000) {
            logger.trace("Execution time for {}: {} ms", m.getName(), millis);
        } else {
            logger.warn("Substantial execution time for {}: {} ms", m.getName(),
                    millis);
        }
        return result;
    }

}

However, as it's an @Around Advice, Spring takes control of all my method calls in order to profile them. That's a bit uncomfortable while debugging (it even misleads Eclipse itself), so I would like the Pointcut to be executed only when my application is at production stage. Can I configure the Pointcut to be conditionally executed depending on a an enviroment variable, Java property or similars?

Documentation only refers to method variable conditions... Thanks in advance!

EDIT

As of @DavidL's suggestion, I changed my pointcut to this:

@Pointcut("execution(* com.tadic.module.TadicModuleGeneric+.*(..)) && if()")
public static boolean pointCut() {
    return true;
}

That's the way Eclipse doesn't warn about anything. However, I get this at runtime:

GRAVE: Critical error during deployment: 
java.lang.VerifyError: Expecting a stackmap frame at branch target 7
Exception Details:
  Location:
    com/mycompany/aspects/AuditAspect.<clinit>()V @1: invokestatic
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0000000: 00b8 0134 a700 084b 2ab3 012f b1       
  Exception Handler Table:
    bci [1, 7] => handler: 7

    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2615)
    at java.lang.Class.getDeclaredMethods(Class.java:1860)
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:474)
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:458)
    at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:518)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:639)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:575)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1350)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:355)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:326)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:434)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:624)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:461)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4973)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

So it seems the weaver isn't doing it properly. Any suggestions?

EDIT 2 This issue happens when I use AspectJ via Spring AOP proxy-based aspects. I'm using Maven to build the project and Eclipse AspectJ plugin to integrate it in my workspace. AspectJ version is 1.8.2, Spring-AOP version is 3.2.8.RELEASE and I'm building it with the Java 7.0.75 JDK.

Here it is a sample of the POM being used:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tesicnor.test</groupId>
    <artifactId>aspect-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>aspect-test</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <aspectj.version>1.8.2</aspectj.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.7</version>
                <configuration>
                    <complianceLevel>1.7</complianceLevel>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>3.2.8.RELEASE</version>
        </dependency>
    </dependencies>


</project>

This POM is the one for a functional testcase I created. My current project is huge and seems that there's other dependency causing the trouble.


Answer:

You can get a reference to the attribute (probably in a static way) which represent your current stage. Depending on it value, you can bypass the code inside the profileServiceMethods method (early return).

In a less esthetically way, you can declare a boolean var in your aspect for the same purpose:

if(!logActivated)
    return null;
else
    <your code here>

EDIT:

Just take a look at the doc. Maybe you can do it this way:

@Pointcut("execution(* com.company.MyService+.*(..)) && args(i) && if()")
public static boolean pointCut(int i) {
    return i == State.PRODUCTION_STAGE ;
}

Question:

I am trying to create a sample maven project with aspectj in Eclipse Neon. However, aspects are not weaving/working (see output below). I tried looking into lots of causes and solutions but none worked (see related questions below). Any help/insights would be very much appreciated. Thanks!

Technologies used:

  • Java jdk-1.8
  • Eclipse (Java EE) Neon 3
  • Apache Maven 3.5.0
  • junit-4.5 (included through maven)
  • aspectjrt-1.8.9 (included through maven)

(I also installed the AJDT plugin to my Eclipse installation for a separate project -- not sure if this inhibits the maven repository version of aspectj)

Directory:

$ tree .
.
├── pom.xml
└── src
    ├── main
    |   └── java
    |       └── com
    |           └── hellomaven
    |               └── quickstart
    |                   ├── App.java
    |                   └── AppAspect.java
    └── test
        └── java
            └── com
                └── hellomaven
                    └── quickstart
                        └── AppTest.java

App.java

package com.hellomaven.quickstart;

public class App {
    public static void main(String[] args) {
        System.out.println("Hello World!");
        say("billy", "Nice to meet you");
        Dog d = new Dog();
        d.bark(2);
    }

    public static void say(String name, String word) {
        System.out.println(name.toUpperCase() + " says " + word.toLowerCase() + "!");
    }
}

class Dog {
    Dog() {
        System.out.println("..Dog init code..");
    }

    public void bark(int n) {
        for (int i = 0; i < n; i++) {
            System.out.print("bark ");
        }
        System.out.println("!");
    }

}

AppAspect.java

package com.hellomaven.quickstart;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class AppAspect {
    @Before("execution(public static * *(..))")
    public void testAspectBefore() {
        System.out.println("Before Okay");
    }

    @Pointcut("execution(* *(..))")
    public void testAspectPointcut() {
        System.out.println("Pointcut Okay");
    }

    @After("execution(* *(..))")
    public void testAspectAfter() {
        System.out.println("After Okay");
    }

    @Around("execution(* *(..))")
    public void testAspectAround() {
        System.out.println("Around Okay");
    }
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hellomaven</groupId>
    <artifactId>quickstart</artifactId>
    <packaging>jar</packaging>
    <version>0.0.1-SNAPSHOT</version>

    <name>quickstart</name>
    <url>http://maven.apache.org</url>

    <properties>
        <java.version>1.8</java.version>
        <aspectj.version>1.8.9</aspectj.version>
        <junit.version>4.5</junit.version>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.6.0</version>
                    <configuration>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                        <!-- IMPORTANT -->
                        <useIncrementalCompilation>false</useIncrementalCompilation>
                    </configuration>
                </plugin>

                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.9</version>
                    <configuration>
                        <showWeaveInfo>true</showWeaveInfo>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                        <Xlint>ignore</Xlint>
                        <complianceLevel>${java.version}</complianceLevel>
                        <encoding>UTF-8</encoding>
                        <verbose>true</verbose>
                    </configuration>
                    <executions>
                        <execution>
                            <phase>process-sources</phase>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                    <dependencies>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjrt</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjtools</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>

                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>1.3</version>
                    <configuration>
                        <mainClass>com.hellomaven.quickstart</mainClass>
                    </configuration>
                </plugin>

            </plugins>
        </pluginManagement>
    </build>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
    </dependencies>
</project>

output

<!-- language: lang-none -->
Hello World!
BILLY says nice to meet you!
..Dog init code..
bark bark !

Related questions I have tried and failed:

  • AspectJ in Maven project not working/weaving
  • Not able to integrate AspectJ with Maven
  • How to build AspectJ project using Maven
  • Maven + AspectJ - All steps to configure it
  • Maven: compile AspectJ project containing Java 1.6 source

Answer:

I am not sure why but after including an aspectjweaver-1.8.9 dependency, updating to junit-4.12 and changing the aspect code, the code works fine. Here is the updated aspect code (AppAspect.java):

package com.hellomaven.quickstart;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class AppAspect {

    @Pointcut("execution(* *(..))")
    public void defineEntryPoint() {
    }

    @Before("defineEntryPoint()")
    public void aaa(JoinPoint joinPoint) {
        System.out.println("aspect before");
    }

    @After("defineEntryPoint()")
    public void bbb(JoinPoint joinPoint) {
        System.out.println("aspect after");
    }
}

Here is the new dependencies:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
</dependencies>

Question:

I have a need to put the database connection and close methods to AspectJ class. Currently my add method looks like below:

public void addBookDetails(String name, String author, String publisher, int year, int price){

    Connection conn=null;
    DBConnection DBConn=new DBConnection();
    try {
        conn=DBConnection.createConnection();
        Statement statement=conn.createStatement();
        System.out.println("INSERT INTO Books " + "VALUES ('"+name+"', '"+author+"', '"+publisher+"', '"+year+"', '"+price+"')");
        statement.executeUpdate("INSERT INTO Books " + "VALUES ('"+name+"', '"+author+"', '"+publisher+"', '"+year+"', '"+price+"')");
        DBConn.closeConnection();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

How can I get this createConnection and closeConnection methods into as Aspect class? Because they dont belong to the scope of addBookDetails. Please advice. I dont understand how to use the "conn" object if I move this method. Because it will be needed for CreateStatement method in this class.


Answer:

Maybe you mean something like this?

Entity classes:

Here we have two classes, both with no-op addDetails(..) methods. We expect the aspect to intercept these methods whenever they are executed and magically create/execute SQL statements for them.

package de.scrum_master.app;

public class Book {
    public void addDetails(
        String name, String author, String publisher, int year, int price
    ) {}
}
package de.scrum_master.app;

public class Person {
    public void addDetails(
        String firstName, String lastName, int yearOfBirth
    ) {}
}

Now let us assume we can derive the SQL table name from the class name by just appending a plural "s" to it. This will become important later in the aspect doing the SQL magic.

DB connection mock-up class:

This class does nothing special except for returning objects expected by the application. I am posting it here for the sake of making this example compileable and runnable.

package de.scrum_master.app;

import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

public class DBConnection {
    public void closeConnection() {}

    public static Connection createConnection() { return new Connection() {
            @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; }
            @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; }
            @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException {}
            @Override public void setTransactionIsolation(int level) throws SQLException {}
            @Override public void setSchema(String schema) throws SQLException {}
            @Override public Savepoint setSavepoint(String name) throws SQLException { return null; }
            @Override public Savepoint setSavepoint() throws SQLException { return null; }
            @Override public void setReadOnly(boolean readOnly) throws SQLException {}
            @Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {}
            @Override public void setHoldability(int holdability) throws SQLException {}
            @Override public void setClientInfo(String name, String value) throws SQLClientInfoException {}
            @Override public void setClientInfo(Properties properties) throws SQLClientInfoException {}
            @Override public void setCatalog(String catalog) throws SQLException {}
            @Override public void setAutoCommit(boolean autoCommit) throws SQLException {}
            @Override public void rollback(Savepoint savepoint) throws SQLException {}
            @Override public void rollback() throws SQLException {}
            @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException {}
            @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return null; }
            @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return null; }
            @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { return null; }
            @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { return null; }
            @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { return null; }
            @Override public PreparedStatement prepareStatement(String sql) throws SQLException { return null; }
            @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return null; }
            @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return null; }
            @Override public CallableStatement prepareCall(String sql) throws SQLException { return null; }
            @Override public String nativeSQL(String sql) throws SQLException { return null; }
            @Override public boolean isValid(int timeout) throws SQLException { return false; }
            @Override public boolean isReadOnly() throws SQLException { return false; }
            @Override public boolean isClosed() throws SQLException { return false; }
            @Override public SQLWarning getWarnings() throws SQLException { return null; }
            @Override public Map<String, Class<?>> getTypeMap() throws SQLException { return null; }
            @Override public int getTransactionIsolation() throws SQLException { return 0; }
            @Override public String getSchema() throws SQLException { return null; }
            @Override public int getNetworkTimeout() throws SQLException { return 0; }
            @Override public DatabaseMetaData getMetaData() throws SQLException { return null; }
            @Override public int getHoldability() throws SQLException { return 0; }
            @Override public String getClientInfo(String name) throws SQLException { return null; }
            @Override public Properties getClientInfo() throws SQLException { return null; }
            @Override public String getCatalog() throws SQLException { return null; }
            @Override public boolean getAutoCommit() throws SQLException { return false; }
            @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { return null; }
            @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return null; }
            @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { return null; }
            @Override public Statement createStatement() throws SQLException { return new Statement() {
                    @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; }
                    @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; }
                    @Override public void setQueryTimeout(int seconds) throws SQLException {}
                    @Override public void setPoolable(boolean poolable) throws SQLException {}
                    @Override public void setMaxRows(int max) throws SQLException {}
                    @Override public void setMaxFieldSize(int max) throws SQLException {}
                    @Override public void setFetchSize(int rows) throws SQLException {}
                    @Override public void setFetchDirection(int direction) throws SQLException {}
                    @Override public void setEscapeProcessing(boolean enable) throws SQLException {}
                    @Override public void setCursorName(String name) throws SQLException {}
                    @Override public boolean isPoolable() throws SQLException { return false; }
                    @Override public boolean isClosed() throws SQLException { return false; }
                    @Override public boolean isCloseOnCompletion() throws SQLException { return false; }
                    @Override public SQLWarning getWarnings() throws SQLException { return null; }
                    @Override public int getUpdateCount() throws SQLException { return 0; }
                    @Override public int getResultSetType() throws SQLException { return 0; }
                    @Override public int getResultSetHoldability() throws SQLException { return 0; }
                    @Override public int getResultSetConcurrency() throws SQLException { return 0; }
                    @Override public ResultSet getResultSet() throws SQLException { return null; }
                    @Override public int getQueryTimeout() throws SQLException { return 0; }
                    @Override public boolean getMoreResults(int current) throws SQLException { return false; }
                    @Override public boolean getMoreResults() throws SQLException { return false; }
                    @Override public int getMaxRows() throws SQLException { return 0; }
                    @Override public int getMaxFieldSize() throws SQLException { return 0; }
                    @Override public ResultSet getGeneratedKeys() throws SQLException { return null; }
                    @Override public int getFetchSize() throws SQLException { return 0; }
                    @Override public int getFetchDirection() throws SQLException { return 0; }
                    @Override public Connection getConnection() throws SQLException { return null; }
                    @Override public int executeUpdate(String sql, String[] columnNames) throws SQLException { return 0; }
                    @Override public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { return 0; }
                    @Override public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { return 0; }
                    @Override public int executeUpdate(String sql) throws SQLException { return 0; }
                    @Override public ResultSet executeQuery(String sql) throws SQLException { return null; }
                    @Override public int[] executeBatch() throws SQLException { return null; }
                    @Override public boolean execute(String sql, String[] columnNames) throws SQLException { return false; }
                    @Override public boolean execute(String sql, int[] columnIndexes) throws SQLException { return false; }
                    @Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { return false; }
                    @Override public boolean execute(String sql) throws SQLException { return false; }
                    @Override public void closeOnCompletion() throws SQLException {}
                    @Override public void close() throws SQLException {}
                    @Override public void clearWarnings() throws SQLException {}
                    @Override public void clearBatch() throws SQLException {}
                    @Override public void cancel() throws SQLException {}
                    @Override public void addBatch(String sql) throws SQLException {}
                };
            }
            @Override public SQLXML createSQLXML() throws SQLException { return null; }
            @Override public NClob createNClob() throws SQLException { return null; }
            @Override public Clob createClob() throws SQLException { return null; }
            @Override public Blob createBlob() throws SQLException { return null; }
            @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { return null; }
            @Override public void commit() throws SQLException {}
            @Override public void close() throws SQLException {}
            @Override public void clearWarnings() throws SQLException {}
            @Override public void abort(Executor executor) throws SQLException {}
        };
    }
}

Driver application:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        new Book().addDetails("Gödel, Escher, Bach: An Eternal Golden Braid", "Douglas R. Hofstadter", "Basic Books", 1979, 990);
        new Book().addDetails("Cryptonomicon", "Neal Stephenson", "Avon", 1999, 990);
        new Person().addDetails("Albert", "Einstein", 1879);
        new Person().addDetails("Werner", "Heisenberg", 1901);
    }
}

Aspect:

The aspect has two helper methods taking care of

  • creating the SQL statement text and
  • opening a DB connection, executing the SQL statement, then closing the connection again.
package de.scrum_master.aspect;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import de.scrum_master.app.DBConnection;

public aspect SqlUpdater {
    void around() : execution(public void addDetails(..)) {
        System.out.println(thisJoinPoint);
        String sqlText = createSqlStatement(thisJoinPoint.getTarget().getClass(), thisJoinPoint.getArgs());
        System.out.println("  " + sqlText);
        connectToDbAndUpdate(sqlText);
        proceed();
    }

    private static String createSqlStatement(Class<?> targetClass, Object[] args) {
        StringBuilder sqlText = new StringBuilder("INSERT INTO ");
        sqlText.append(targetClass.getSimpleName() + "s ").append("VALUES (");
        int argSize = args == null ? 0 : args.length;
        int i = 0;
        for (Object arg : args) {
            i++;
            sqlText.append(arg instanceof String ? "'" : "").append(arg);
            if (i < argSize)
                sqlText.append(arg instanceof String ? "', " : ", ");
            else
                sqlText.append(arg instanceof String ? "'" : "");
        }
        sqlText.append(")");
        return sqlText.toString();
    }

    private static void connectToDbAndUpdate(String sqlText) {
        Connection sqlConnection = null;
        DBConnection dbConnection = new DBConnection();
        try {
            sqlConnection = DBConnection.createConnection();
            Statement sqlStatement = sqlConnection.createStatement();
            sqlStatement.executeUpdate(sqlText);
            dbConnection.closeConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Console output:

execution(void de.scrum_master.app.Book.addDetails(String, String, String, int, int))
  INSERT INTO Books VALUES ('Gödel, Escher, Bach: An Eternal Golden Braid', 'Douglas R. Hofstadter', 'Basic Books', 1979, 990)
execution(void de.scrum_master.app.Book.addDetails(String, String, String, int, int))
  INSERT INTO Books VALUES ('Cryptonomicon', 'Neal Stephenson', 'Avon', 1999, 990)
execution(void de.scrum_master.app.Person.addDetails(String, String, int))
  INSERT INTO Persons VALUES ('Albert', 'Einstein', 1879)
execution(void de.scrum_master.app.Person.addDetails(String, String, int))
  INSERT INTO Persons VALUES ('Werner', 'Heisenberg', 1901)

Feel free to ask follow-up questions if you do not understand the sample code.

Question:

I am trying to create an advice of a method of a project (test5) being called from another project (testMaven). I already included the project test5 as dependency in testMaven's pom.xml and set up an advice in testMaven's class but still it doesn't get executed. The calling of the method (dfg) is working just fine.

Here are the code for it:

MainApp.java (testMaven)

package testMaven;

import test5.yxc;

public class MainApp {

    public static void main(String[] args) {
        yxc b = new yxc();
        b.dfg(2);
    }
}

yxc.java (test5)

package test5;

public class yxc {

    public void dfg(int a){
        System.out.println(a);

    }
}

testAspect.java (testMaven)

package testMaven;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
import test5.yxc;

@Aspect
public class testAspect {

    @Before("execution(* test5.yxc.dfg(..))")
    public void testBefore(){
        System.out.println("yooi");
    }
}

pom.xml(testMaven)

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>testingMaven</groupId>
    <artifactId>testMaven</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <spring.version>4.2.5.RELEASE</spring.version>
        <java.version>1.8</java.version>
        <!-- Maven Plugin Versions -->
        <maven.compiler.plugin.version>3.2</maven.compiler.plugin.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.9</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>
        <dependency>
            <groupId>test5</groupId>
            <artifactId>test5</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

    </dependencies>

    <build>

        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.8</version>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.plugin.version}</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>

        </plugins>
    </build>
</project>

Could you help me what's wrong with this? Thanks


Answer:

Checked your code in testMaven and checked out the code and changed the POM as follows:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>testMaven</groupId>
<artifactId>testMaven</artifactId>
<version>0.0.1-SNAPSHOT</version>

<properties>

    <java.version>1.8</java.version>
    <aspectj.version>1.8.9</aspectj.version>
    <!-- Maven Plugin Versions -->
    <maven.compiler.plugin.version>3.2</maven.compiler.plugin.version>

</properties>

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjtools</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
</dependencies>

<build>

    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.8</version>
            <configuration>
                <complianceLevel>${java.version}</complianceLevel>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <showWeaveInfo>true</showWeaveInfo>
            </configuration>
            <executions>
                <execution>
                    <id>AspectJ-Classes</id>
                    <phase>process-classes</phase>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
                <execution>
                    <id>AspectJ-Test-Classes</id>
                    <phase>process-test-classes</phase>
                    <goals>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjrt</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
            </dependencies>
        </plugin>

        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

    </plugins>

</build>

NOTE: Added assembly plugin to make testing/verifying for myself easier.

When I compile the project I see within the maven logs the following entry:

[INFO] --- aspectj-maven-plugin:1.8:compile (AspectJ-Classes) @ testMaven ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] Join point 'method-execution(void testMaven.aaaa.aa(int))' in Type 'testMaven.aaaa' (aaaa.java:5) advised by before advice from 'testMaven.aspecter' (aspecter.java:10)

When I now execute the jar as follows I see the following result:

...>java -cp target/testMaven-0.0.1-SNAPSHOT-jar-with-dependencies.jar testMaven/MainApp
yooi
2

Given the MainApp is as follows:

package testMaven;

public class MainApp {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        aaaa a = new aaaa();
        a.aa(2);
    }

}

The class that is initiated prints the passed argument

package testMaven;

public class aaaa {

    public void aa(int a){
        System.out.println(a);
    }
}

And the interceptor as follows

package testMaven;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;


@Aspect
public class aspecter {
    @Before("execution(*  testMaven.aaaa.aa(..))")
    public void testBefore(){
        System.out.println("yooi");
    }
}

I would say it works :)

Question:

I created an Aspectj project and added .aj files and java files. While compiling(Load-time) it shows the error

"Error: Could not find or load main class javaagent:path/aspectjweaver-1.8.2.jar"

I compiled it in eclipse by creating Load time configuration file. Can any one tell me why


Answer:

Very simple: Probably you should provide a real file system path instead of the place holder path. Also be sure to use -javaagent:... (note the dash character) instead of something like javaagent:....

Question:

Hi I am new to aspectj and after several hours of browsing around the internet I came to know something about aspectj. And also I had one doubt is this similar to immediate window in visual studio as in the aspectj in which we doing manually checking joint points...In immediate window if we type any variable it returns its value in current method. Likewise, in aspectj we are declaring manually that after calling specified function and returing variable values inside that method using system.out.println(). Is that right? if it is wrong...correct me


Answer:

From the wikipeida article: AOP is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns

Think about caching.... that is a concern that cuts across other concerns, like reading from a datastore. You can create a point cut to cache values being written to datastore and one to read from cache when the datastore is being accessed. Here is a link to a question specifically about AOP use cases: AOP use cases?

If you want to use AOP to "watch" a variable, to short answer is you can't. Pointcuts can only be applied methods

Question:

I have several Java Maven projects built over the years that leverage AspectJ.

All projects compile correctly on both Eclipse Neon and Maven command line.

On Photon, however, I receive lots of error messages all originating from the inability to compile the AspecJ code. For example:

pointcut test() : execution(@org.junit.Test * *(..));

causes

pointcut cannot be resolved to a type

and

before() : test() {
    localLog(thisJoinPoint).info(format("*** Test execution @ %s", describe(thisJoinPointStaticPart)));
}

causes the errors:

thisJoinPoint cannot be resolved to a variable

and

thisJoinPointStaticPart cannot be resolved to a variable

Can anyone tell me how to fix the compilation on Photon?


Answer:

You need to install a version of AJDT compatible with Photon. I am still on Oxygen.2, have not tried Photon yet, but obviously there is no official AJDT release for Photon yet.

Next time maybe check plugin availability before you update. What I am seeing on the download page is only a development build for Eclipse 4.8 with the update site

http://download.eclipse.org/tools/ajdt/48/dev/update

Good luck!

Question:

I am having an old java project with lombok annotationsin eclipse. Out of curiosity, i have modified this project into AspectJ project by adding necessary plugins and (configure -> convert to aspectJ). Now there are error shown everywhere in my project especially in using the getters generated by lombok.

I like to revert it back and convert aspectj to java project. Your help is highly appreciated.


Answer:

  • Right-click on project in order to open pop-up context menu
  • Open sub-menu "AspectJ Tools"
  • Select "Remove AspectJ Capability"