Jonas P
Jonas P

Reputation: 1

Load-time weaving with AspectJ in the Spring Framework Private methods

I have built an application to test injecting log information (Entering and Exiting) around classes. I have built it using spring and used the following example for building it.

http://static.springsource.org/spring/docs/2.5.5/reference/aop.html#aop-aj-ltw

It works great now but I have 2 issues:

Below I have included all code and xml that is used. As I said all is working fine except the 2 issues above. Please assist me.

app.java

package se.jpab.application;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

@Service
public class App 
{
    public static void main( String[] args )
    {
        ApplicationContext appContext = new ClassPathXmlApplicationContext( new String[] { "spring.xml" });
        Client client = (Client) appContext.getBean("client");   
        Location clientLocation = (Location) appContext.getBean("location");        

//      Set all values
        clientLocation.setAdress1("Adress 1");
        clientLocation.setAdress2("Adress 2");
        clientLocation.setBox("N/A");
        clientLocation.setCity("City of Dallas");

        client.setName("John Doe");
        client.setUrl("http://www.url.com"); 
        client.setLocation(clientLocation);


 //     Print out all values        

        System.out.println(client.getName());        
        System.out.println(client.getUrl());
        System.out.println(client.getLocation().getAdress1());
        System.out.println(client.getLocation().getAdress2() + " " + client.getLocation().getCity());

    }
}

Client.java package se.jpab.application;

import org.springframework.stereotype.Service;

@Service
public class Client {

    String name;
    String url;
    Location location;
    //Constructors
    public Client(String custName, String custUrl, Location custLocation){
        name = custName;
        url = custUrl;  
        location = custLocation;
    }

    public Location getLocation() {
        return location;
    }

    public void setLocation(Location location) {
        this.location = location;
    }

    public Client(){

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {      
        this.name = name;
        printThis(name);

    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void printThis(String inStr) {
        System.out.println("PRIVAT METOD");
        System.out.println("Inkommand sträng --> " + inStr);
    }   


}

Location.java

package se.jpab.application;

import org.springframework.stereotype.Service;

@Service
public class Location {

    String city;
    String adress1;
    String adress2;
    String box;

    //Constructors  
public Location (String city, String adress1, String adress2, String box){

    this.city = city;
    this.adress1 = adress1;
    this.adress2 = adress2;
    this.box = box; 

}
public Location (){

}
public String getCity() {
    return city;
}
public void setCity(String city) {
    this.city = city;
}
public String getAdress1() {
    return adress1;
}
public void setAdress1(String adress1) {
    this.adress1 = adress1;
}
public String getAdress2() {
    return adress2;
}
public void setAdress2(String adress2) {
    this.adress2 = adress2;
}
public String getBox() {
    return box;
}
public void setBox(String box) {
    this.box = box;
}   
}

aop.xml

    <!DOCTYPE aspectj PUBLIC
        "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
    <weaver options=" -showWeaveInfo">
        <!-- only weave classes in our application-specific packages -->        
        <include within="se.jpab.application.*"/>
        <include within="se.jpab.aspect.*"/>
    </weaver>

    <aspects>
        <!-- weave in just this aspect -->        
        <aspect name="se.jpab.aspect.InjectLogg"/>
    </aspects>
</aspectj>

Aspect

package se.jpab.aspect;

import java.util.Arrays;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class InjectLogg {

    private static final Log fallbackLogger = LogFactory.getLog(InjectLogg.class);

    @Around("execution(public * se.jpab.application..*.*(..))")
    public Object profile(ProceedingJoinPoint pjp) throws Throwable {
                Object invoker = pjp.getThis();
                Log logger;

                logger = LogFactory.getLog(getClassNameFrom(invoker.getClass()));

                // Start injecting logg messages on entering a method.
                logger.info("ENTERING: (" + pjp.getSignature().getName() + ")");
                try {
                    logger.info("ARGUMENTS: " + Arrays.toString(pjp.getArgs()) + ")");
                } catch (NullPointerException e) {
                    logger.info("ARGUMENTS: No arguments");
                }

                try {
                    // proceed to original method call
                    Object result = pjp.proceed();

                    // Injecting exiting messages after method is finished
                    logger.info("RESULT: " + result);
                    logger.info("EXITING: (" + pjp.getSignature().getName() + ")");

                    // Return the result of the method we are logging
                    return result;

                } catch (IllegalArgumentException e) {
                    // same with ThrowsAdvice
                    logger.info("Exception. Throws IllegalArgumentException");
                    throw e;
                }

    }

    private String getClassNameFrom(Class invokerClassName) {
        // Function that ....... To be continued JP

        // Add check for that string contains $$ and se.goteborg if not then
        // return fallback logger class.

        String[] classNameParts = invokerClassName.getName().split("$$");
        int positionOfPackageName = classNameParts[0].indexOf("se.jpab");
        String className = classNameParts[0].substring(positionOfPackageName);

        return className;
    }
}

Spring configuration (spring.xml)

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


 <aop:aspectj-autoproxy proxy-target-class="true"/>
 <context:load-time-weaver/>
 <context:annotation-config />
 <context:component-scan base-package="se.jpab"/>


</beans>

Upvotes: 0

Views: 4807

Answers (1)

kriegaex
kriegaex

Reputation: 67287

Your first question:

Private methods are not included when the log is weaved around the method. Is there a setting in the xml settings for spring to allow private methods to be weaved or is there another way around this?

If you want to weave private methods, use full AspectJ and therein a privileged aspect, not Spring AOP. The Spring manual says:

If your interception needs include protected/private methods or even constructors, consider the use of Spring-driven native AspectJ weaving instead of Spring's proxy-based AOP framework. This constitutes a different mode of AOP usage with different characteristics, so be sure to make yourself familiar with weaving first before making a decision.

Your second question:

I have to include all packages that are to be weaved in the META-INF/aop.xml for this to be able to work. Is there a setting to be used so that the log information can be weaved for all classes created in the project without having to add the package name to the aop.xml.

You can catch a package an all its subpackages with the .. syntax, e.g. se.jpab.application..* or even se.jpab..*. You can also combine several conditions with boolean operators. See the AspectJ documentation for examples.

Upvotes: 2

Related Questions