AspectJ Pointcut用于获取Serializable或基本类型的任何数字参数的方法

时间:2016-03-06 09:54:31

标签: java aspectj pointcut

如何为采用任意数量的参数实现Serializable或基本类型的方法编写Pointcut?

E.g。切入点应匹配:

methodA(String str, int i)
methodB(String str, String str2, List<String> list)

但不是

methodC(String str, DataX data)

其中DataX不可序列化

1 个答案:

答案 0 :(得分:1)

我不知道在切入点中指定那种条件,所以我唯一拥有的东西是非常昂贵的,因为它涉及运行时检查 - 但它可以做你想要的:

驱动程序应用程序:

package de.scrum_master.app;

import java.io.Serializable;

public class Application {
    public static class MyNonSerializable {}

    public static class MySerializable implements Serializable {
        private static final long serialVersionUID = 1L;
    }

    private static MyNonSerializable one() {
        return new MyNonSerializable();
    }

    static MySerializable two(int i, String string) {
        return new MySerializable();

    }

    static String three(int i, String string, MyNonSerializable myNonSerializable) {
        return "foo";
    }

    static MyNonSerializable four(int i, String string, MySerializable mySerializable) {
        return new MyNonSerializable();
    }

    static void five(MyNonSerializable myNonSerializable) {
    }

    static int six(MySerializable mySerializable) {
        return 11;
    }

    public static void main(String[] args) {
        one();
        two(11, "foo");
        three(11, "foo", new MyNonSerializable());
        four(11, "foo", new MySerializable());
        five(new MyNonSerializable());
        six(new MySerializable());
    }
}

现在,无论返回类型如何,我们都希望使用零参数或任意数量的Serializable参数来拦截执行。符合此条件的方法为mainonetwofoursix

运行时类型检查的方面:

package de.scrum_master.aspect;

import java.io.Serializable;

public aspect MethodsWithSerializableArgumentsAspect {
    before() : execution(* *(..)) {
        boolean nonSerializableArgumentFound = false;
        for (Object arg : thisJoinPoint.getArgs()) {
            if (!(arg == null || arg instanceof Serializable)) {
                nonSerializableArgumentFound = true;
                break;
            }
        }
        if (nonSerializableArgumentFound)
            return;
        System.out.println(thisJoinPoint);
    }
}

控制台日志:

execution(void de.scrum_master.app.Application.main(String[]))
execution(Application.MyNonSerializable de.scrum_master.app.Application.one())
execution(Application.MySerializable de.scrum_master.app.Application.two(int, String))
execution(Application.MyNonSerializable de.scrum_master.app.Application.four(int, String, Application.MySerializable))
execution(int de.scrum_master.app.Application.six(Application.MySerializable))

Tadaa! :-)

现在,如果您还要排除返回不可序列化对象的方法,则应将输出限制为maintwosix。你可以这样做:

package de.scrum_master.aspect;

import java.io.Serializable;

public aspect MethodsWithSerializableArgumentsAspect {
    Object around() : execution(* *(..)) {
        boolean nonSerializableArgumentFound = false;
        for (Object arg : thisJoinPoint.getArgs()) {
            if (!(arg instanceof Serializable)) {
                nonSerializableArgumentFound = true;
                break;
            }
        }
        Object result = proceed();
        if ((result == null || result instanceof Serializable) && !nonSerializableArgumentFound)
            System.out.println(thisJoinPoint);
        return result;
    }
}

控制台日志:

execution(Application.MySerializable de.scrum_master.app.Application.two(int, String))
execution(int de.scrum_master.app.Application.six(Application.MySerializable))
execution(void de.scrum_master.app.Application.main(String[]))

请注意,为了对返回值进行运行时检查,我们只能在方法终止后打印结果。因此,main位于日志输出的末尾,而不是第一个解决方案中的开头。

更新:我忘了解释为什么我们需要检查广告并返回null的值。这是因为我们希望接受nullvoid作为Serializable,但实际上null instanceof Serializable是假的。

更新2 - 没有运行时类型检查的静态切入点解决方案:

好吧,我只是在吃一个苹果(不,它没有掉到我的头上),突然有了这个想法。它实际上工作得很好,正是你想要的:

package de.scrum_master.aspect;

import java.io.Serializable;

public aspect MethodsWithSerializableArgumentsAspect {
    pointcut returnsSerializable() :
        execution((Serializable+ || byte || short || int || long || float || double || char || boolean || void) *(..));

    pointcut hasNonSerializableArguments() :
        execution(* *(.., !(Serializable+ || byte || short || int || long || float || double || char || boolean || void), ..));

    before() : returnsSerializable() && !hasNonSerializableArguments() {
        System.out.println(thisJoinPoint);
    }
}

BTW,Serializable+表示“Serializable及其所有子类或实现类”。

享受!