I would like to create a pointcut on the following sample class whenever a variable gets assigned. So for instance, in method1(int number), this.x gets set to int. I realize in this case I could just make a pointcut on method1 and then find out what the new x value is using reflection. However, I was wondering if there is a way to make a pointcut on the line this.x = number, so that my pointcut gets triggered, for example, before the function ends?
public class Sample {
private int x;
public void method1(int number) {
this.x = number;
}
public int getX() {
return this.x;
}
public void method1(int number, String value) {
this.x = number;
}
public void method2(String value) {
this.x = 105;
}
}
You can do that with either:
a privileged aspect:
import java.lang.reflect.Field;
import org.aspectj.lang.reflect.FieldSignature;
public privileged aspect FieldChangeMonitorAspect {
void around(Sample sample): set(int Sample.x) && target(sample) {
FieldSignature fieldSignature = (FieldSignature) thisJoinPoint.getSignature();
Field field = fieldSignature.getField();
int oldValue = sample.x;
int newValue = ((Integer)thisJoinPoint.getArgs()[0]).intValue();
proceed(sample);
int actualNewValue = sample.x;
System.out.printf("changed field %s: old value=%d, new value=%d, "
+ "actual new value=%d\n",
field, oldValue, newValue, actualNewValue);
}
}
a non-privileged aspect using reflection:
import java.lang.reflect.Field;
import org.aspectj.lang.reflect.FieldSignature;
public aspect FieldChangeMonitorAspectWithReflection {
void around(Sample sample): set(int Sample.x) && target(sample) {
FieldSignature fieldSignature = (FieldSignature) thisJoinPoint.getSignature();
Field field = fieldSignature.getField();
try {
Object oldValue = field.getInt(sample);
Object newValue = thisJoinPoint.getArgs()[0];
proceed(sample);
Object actualNewValue = field.get(sample);
System.out.printf("changed field %s: old value=%d, new value=%d, "
+ "actual new value=%d\n",
field, oldValue, newValue, actualNewValue);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
The first (privileged) version is recommended when you need to monitor a known field of a known type, because it's faster by not using reflection. However, when you need to monitor fields which are not known at the time of writing (for instance, marked by an annotation) or there are multiple fields you want to monitor in possibly multiple types, the second version might come handy.
Not that newValue
and actualNewValue
should always have the same value, but the newValue
is available before changing the field value, while actualNewValue
can only be obtained after the field value has been changed.