Search code examples
javaspringaopaspectjspring-aop

AspectJ doesnt work fine in Eclipse


I tried to create a simple program in java.

In the program I have:

1) Person class - with annotated methods

2) Aspect Class.

Now what I'm trying to do is before the person name is setted, to print some data to a log file and to the console.

So this is what I did:

Person Class

package pack.bl;

import org.springframework.stereotype.Component;
import pack.aop.LogLevel;
import pack.aop.TestAnnotation;

@Component
public class Person {

private String name,dest;
public Person(String name,String dest)
{
    this.setName(name);
    this.setDest(dest);
}

public String getName() {
    return name;
}

@TestAnnotation(value=LogLevel.INFO)
public void setName(String name) {
    this.name = name;
    System.out.println("Im " + this.toString() + " My name was changed to " + name);
}

public String getDest() {
    return dest;
}

@TestAnnotation(value=LogLevel.INFO)
public void setDest(String dest) {
    this.dest = dest;
}

@Override
public String toString()
{
    return this.name + "\n";
}

public static void main(String[] args) {
    Person p = new Person("Person1","Kripton");
    p.setName("Person2");
}

}

Aspect Class

package pack.aop;

import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.test.context.ContextConfiguration;


@Aspect
@ContextConfiguration(locations = {
        "applicationContext.xml"})

public class BeforeAdvice {

private Log logger = LogFactory.getLog("Logger");

@Before("@annotation(testAnnotation)")
public void myBeforeLogger(JoinPoint joinPoint,TestAnnotation testAnnotation)
{
    System.out.println("Okay - we're in the before handler...");
    System.out.println("The test annotation value is: " + testAnnotation.value());
    Signature signature = joinPoint.getSignature();
    String methodName = signature.getName();
    String stuff = signature.toString();
    String arguments = Arrays.toString(joinPoint.getArgs());
    logger.info("Write something in the log... We are just about to call method: "
    + methodName + " with arguments " + arguments + "\nand the full toString: "
    + stuff);
}

}

ApplicationContext.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"    
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
    http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context.xsd">

<aop:aspectj-autoproxy/>

<context:component-scan base-package="pack.bl.Person"/>

*NOTE: The LogLevel is an enum. so it need to work like that, when I'm running the program and set the person name, first it's need to go to the 'BeforeAdvice' (because the setName, is annotated with @testAnnotation) method in the Aspect class, and execute this method.. after that it's need to comeback to the setName method and set the person name.*

and one more thing, the testAnnotation is an Annotation that I created


Solution

  • You haven't mentioned anything about how you weave in your question. From what I can see, it looks like you delegate the job to the Spring container. But then you're using Spring AOP and not AspectJ. Although you can use AspectJ annotations also with Spring AOP.

    My suggestion is that you divide it into two cases. First ensure that the AspectJ aspect is weaved and use a simpe advice method that only use System.out.println(..), then ensure that the Spring configuration integrates with your aspect and Log enum.

    Wevaing with the AJDT Eclipse plugin

    To enable AspectJ weaving, the easiest alternative is to use the AspectJ plugin and use compile-time weaving. After you have right-clicked on your project and enabled AspectJ nature, you will see orange arrows in your code where the advices are weaved in. See picture below for an example.

    I'm not sure if your pointcut works. If your advice isn't weaved in any places, you should try this pointcut instead:

    @Pointcut("execution(@pack.aop.TestAnnotation * *(..)) ")
    public void logMethod() {}
    

    And advice it like this:

    @Before("logMethod()")
    public void beforeLogMethod(JoinPoint joinPoint) {
        System.out.println("Logging..");
    }
    

    Integrate aspect and enum with Spring container

    Second,since the aspect is created before the Spring container, you have to retrieve the aspect from the Aspect's factory method Aspects.aspectOf(pack.aop.BeforeAdvice.class) or use a factory-method in the Spring configuration.

    From the Spring XML configuration, you can retrieve the aspect (object) like this:

    <bean id="beforeAdvice" class="apack.aop.BeforeAdvice"
        factory-method="aspectOf" />
    

    You must also use a factory-method to retrieve the logger that is created outside the Spring container.

    I have written a relevant blog post that explains with an example most of your problems and a picture of how elegant the AJDT Eclipse plugin works.

    enter image description here

    The image shows two arrows that illustrates an after advice and the last arrow illustrates an around advice.