[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Add my aspect to different projects

I think you are over-engineering a bit with your helper classes (StackTraceHelper, Access, DeprecatedMethodData) and your complex aspect code. Keep it simple! How about just something like this?


    package com.google.common.annotations;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    import java.lang.annotation.Retention;
    public @interface Beta {}

    package de.scrum_master.app;
    import java.util.Date;
    import com.google.common.annotations.Beta;
    public class Application {
      public void doSomething() {
        new Date(2018, 5, 5);
      public void doSomethingDeprecated() {}
      public void doSomethingBeta() {
      public void doSomethingDeprecatedBeta() {}
      public static void main(String[] args) {
        Application application = new Application();

    package de.scrum_master.aspect;
    public aspect DeprecatedMethodLogger {
      pointcut deprecated() :
        @annotation(Deprecated) &&
        (call(public * de.scrum_master..*(..)) || call(public de.scrum_master..new(..)));
      pointcut beta() :
      pointcut deprecatedMethods() :
        deprecated() && !beta();
      declare warning : deprecatedMethods() :
        "Deprecated method called, please refactor";
      before() : deprecatedMethods() {
          "Deprecated method " + thisJoinPoint.getSignature() +
          " called by " + thisEnclosingJoinPointStaticPart.getSignature()

Now you have both compiler warnings and runtime logging. If you prefer compiler errors, just change "declare warning" to "declare error". BTW, I have also included deprecated constructor calls. If you like you can also expand the pointcut to include deprecated classes.

The console log looks like this:

Deprecated method void de.scrum_master.app.Application.doSomethingDeprecated() called by void de.scrum_master.app.Application.doSomethingBeta()
Deprecated method void de.scrum_master.app.Application.doSomethingDeprecated() called by void de.scrum_master.app.Application.main(String[])
Deprecated method void de.scrum_master.app.Application.doSomethingDeprecated() called by void de.scrum_master.app.Application.doSomethingBeta()

In Eclipse with AJDT it looks like this (please note that there is no warning for the deprecated JDK Date constructor call because you said you only want to target your own companie's classes):



Alexander Kriegisch


Mikael Petterson schrieb am 16.03.2018 13:55:

Thanks for reply Alexander. I try to answer your questions:
          [Mike] currently we use ajc and weave it into our product at compile time. But I want to have a separate jar so I can use it with other products.
Sample code:
package com.company.aspect;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
 * Helper class for stacktraces
class StackTraceHelper {
    private ListIterator<StackTraceElement> iterator = null;
    private StringBuilder builder = null;
    private final List<String> excludedPackages = new ArrayList<>();
    public StackTraceHelper(List<StackTraceElement> stackTraceElements) {
        this.iterator = stackTraceElements.listIterator();
     * Find matching stack trace element and set iterator.
     * @param className
     * @return {@link StackTraceElement} matching className
    public StackTraceElement matchClassName(String className) {
        while (iterator.hasNext()) {
            StackTraceElement ste = iterator.next();
            if (className.equals(ste.getClassName())) {
                return ste;
        //TODO: warn that no StackTraceElement was found for Name.
        return null;
    public StackTraceElement next() {
        return iterator.next();
    public boolean hasNext() {
        return iterator.hasNext();
    public boolean hasPrevious() {
        return iterator.hasPrevious();
    public StackTraceElement previous() {
        return iterator.previous();
    public String toString() {
        return builder.toString();
    DeprecatedMethodData extractData(String targetClass) {
        DeprecatedMethodData dmd = new DeprecatedMethodData();
        //This is the called  class so we need to make sure that next class is a test class
        //otherwise we are not interested.
        StackTraceElement steTarget = this.matchClassName(targetClass);
        if (steTarget != null) {
            //we have a match of target in stack trace
            while (this.hasNext()) {
                StackTraceElement ste = this.next();
                String clazzName = ste.getClassName();
                String methodName = ste.getMethodName();
                if (this.isTestClass(clazzName) && !this.isExternalFramework(clazzName)) {
                //if (this.isTestClass(clazzName)) {//TODO: Fix
        //Add complete stacktrace to find problems with current algorithm.
        return dmd;
     * Must be called first thing since next operations
     * will affect this.
    private void stackTraceToString(List<StackTraceElement> stackTraceElements) {
        final ListIterator<StackTraceElement> iter = stackTraceElements.listIterator();
        builder = new StringBuilder();
        while (iter.hasNext()) {
    public boolean isInternal(String clazz) {
        if (clazz
                        + "com.company.actions|com.company.configuration|"
                        + "com.company.demo).*")) {
            //LogerHelper.log("internal class:" + clazz);
            return true;
        return false;
    public boolean isJava(String clazz) {
        if (clazz.startsWith("sun") ||
                clazz.startsWith("java")) {
            //LogerHelper.log("java class:" + clazz);
            return true;
        return false;
    public boolean isTestClass(String clazz) {
        if (isInternal(clazz) || isJava(clazz)) {
            return false;
        return true;
    public boolean isExternalFramework(String clazz) {
        if (clazz.startsWith("org.testng") || clazz.startsWith("org.apache.maven.surefire")) {
            return true;
        return false;
    //TODO: Not ready yet.
//    public void excludePackages(List<String> packageNames) {
//        excludedPackages.addAll(packageNames);
//    }
//    boolean exclude(String clazz) {
//        for (String exclude : excludedPackages) {
//            if (clazz
//                    .matches(
//                    "^(" + exclude + ").*")) {
//                return true;
//            }
//        }
//        return false;
//    }
//    boolean isTestClass2(String clazz) {
//        return exclude(clazz);
//    }




Från: aspectj-users-bounces@xxxxxxxxxxx <aspectj-users-bounces@xxxxxxxxxxx> för Mikael Petterson <mikaelpetterson@xxxxxxxxxxx>
Skickat: den 15 mars 2018 14:35
Till: aspectj-users@xxxxxxxxxxx
Ämne: [aspectj-users] Add my aspect to different projects

I have created an aspect that can be used to track calls to deprecated methods in your product. It is currently implemented in "our product" but I want to make a library out of it so we can use it for other products.

The aspect currently looks something like:
aspect DeprecatedMethodLogger {
    pointcut includeDeprecated():execution(public  * *.*(..)) && @annotation(Deprecated);
    pointcut excludeBeta():execution(public  * *.*(..)) && !@annotation(com.google.common.annotations.Beta);
    pointcut deprecatedMethods():  includeDeprecated() && excludeBeta();
    before() :deprecatedMethods()  {
        if (thisJoinPoint.getTarget() != null) {
            String targetClass = thisJoinPoint.getTarget().getClass().getName();
            List<StackTraceElement> stackTraceElements = Arrays.asList(Thread.currentThread().getStackTrace());
            StackTraceHelper stackTraceHelper = new StackTraceHelper(stackTraceElements);
            DeprecatedMethodData deprecatedMethodData = stackTraceHelper.extractData(targetClass);
 //There is also some additional connections to db and other tools here.



In stackTraceHelper there are a number of settings that can be done what is relevant in the trace when we try to find the calling class.

These settings I want to to publish so they can be set for each product using this library.


So question is if I in all products using it need to create another aspect that inherits this one and can set the relevant properties.



so my aspect above would have:


aspect DeprecatedMethodLogger implements DeprecatedMethodLoggerApi {




DeprecatedMethodLoggerApi contains setting that can be done.


Then in the products I create:


aspect MyDepreactedMethodLogger extends DeprecatedMethodLogger {




Or is there a better way? Suggestions welcome.









PNG image