Using aspectj to intercept an assignment with refl

2019-09-15 23:32发布

When I run the application with tomcat it says that the advices has not been aplied, so my aspects won't work. Do I have to configure that anywhere? I haven't done anything about it, so I don't know what code might be useful.

Thank you!

EDIT

I've just found out how to fix that, and even when it says that the aspect has not been applied, when I call the setter it works, but I have a problem when using reflection for that.

I have an aspect which intercept a setter to a field which works well, but when the value is assigned from Gson library por example, it doesn't work.

This is the aspect:

public aspect AnnotationAspect {

    pointcut hasAnnotation(Annotation annotation) : @annotation(annotation);

    Object around(Annotation annotation, String word) : hasAnnotation(annotation) && set(String *) && args(word) {
        Object result = null;
        try {
            result = proceed(annotation, "intercepted");
        } catch (RuntimeException ex) {
            throw ex;
        }
        return result;
    }
}

And I have this class:

public class JavaEntity {

    @Annotation
    public String name;

    public String getName() {
        return name;
    }

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

When I do something like this it does not intercept the assignment:

JavaEntity entity = new Gson().fromJson("{\"name\":\"name\"}", JavaEntity.class);

Is there anyway to intercept that? Thank you!

1条回答
仙女界的扛把子
2楼-- · 2019-09-16 00:20

Reflective field access cannot be directly intercepted by AspectJ. You could only work around it by fighting fire with fire, i.e. also using reflection:

  • Make sure Gson is on the inpath for the AspectJ compiler (i.e. a weave dependency for AspectJ Maven plugin) so as to be able to weave into its code.
  • Intercept calls to Field.set(..).
  • In the intercepting advice check which field is to be set, look up its annotations via reflection in order to emulate @annotation(blah), decide whether to modify its value or not.

This is not exactly the usual AspectJ use case, but possible.

BTW, you do not have this kind of problem with execution() joinpoints because they are also triggered when a method is called reflectively. You would have the problem with call(), though. But this is just for your information, not directly related to this specific case.


Update: I mean something like this:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <configuration>
        <weaveDependencies>
            <weaveDependency>
                <groupId>Group</groupId>
                <artifactId>model</artifactId>
            </weaveDependency>
            <weaveDependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
            </weaveDependency>
        </weaveDependencies>
    </configuration>
</plugin>
@Test
public void testingInterceptWithJavaGson(){
    javaEntity = new Gson().fromJson("{\"name\":\"newName\"}", JavaEntity.class);
    Assert.assertEquals("intercepted", javaEntity.getName());
}
Object around(Field field, Object obj, Object value) :
    within(com.google.gson..*) &&
    call(public void Field.set(Object, Object)) &&
    target(field) &&
    args(obj, value)
{
    Object result = null;
    System.out.println(thisJoinPoint);
    System.out.println("  " + field + " -> " + field.getAnnotation(Annotation.class));
    System.out.println("  " + obj);
    System.out.println("  " + value);
    try {
        if (field.getAnnotation(Annotation.class) != null && field.getType() == String.class)
            result = proceed(field, obj, "intercepted");
        else
            result = proceed(field, obj, value);
    } catch (RuntimeException ex) {
        throw ex;
    }
    return result;
}

Actually you do not need to bind the first parameter obj via args(), I just use it for logging so as to show you what happens there. So this slightly simpler form will also do:

Object around(Field field, Object value) :
    within(com.google.gson..*) &&
    call(public void Field.set(Object, Object)) &&
    target(field) &&
    args(*, value)
{
    Object result = null;
    System.out.println(thisJoinPoint);
    try {
        if (field.getAnnotation(Annotation.class) != null && field.getType() == String.class)
            result = proceed(field, "intercepted");
        else
            result = proceed(field, value);
    } catch (RuntimeException ex) {
        throw ex;
    }
    return result;
}

The changes to your existing GitHub repo are contained in yet another pull request from my fork.

查看更多
登录 后发表回答