![JAR search and dependency download from the Maven repository](/logo.png)
de.tsl2.nano.aspect.AspectCover Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tsl2.nano.aspects Show documentation
Show all versions of tsl2.nano.aspects Show documentation
TSL2 Framework Aspects (Generic Aspects with AspectJ)
The newest version!
package de.tsl2.nano.aspect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
/**
* The aspect works on methods annotated with @Cover. It is possible to
* coverup/mock fields - but only if they are declared as interface.
*
* Note: This aspect is not abstract to define a pointcut with arguments
*
* for more informations see {@link Cover}
*/
@Aspect
public class AspectCover {
private Object thisField; //workaround to the class, holding the field - on method invoking
// @Pointcut("call(@Cover * *(..)) || within(@Cover *)")
@Pointcut("@annotation(cover)")
public void callAt(Cover cover) {
}
@Around("callAt(cover)")
public Object around(ProceedingJoinPoint pjp, Cover cover) throws Throwable {
try {
log("------->");
Object result = null;
if (cover == null || cover.trace())
logInfo(pjp);
if (cover != null) {
invokeOrCover(CoverBefore.class, cover.before(), pjp);
if (isFieldAccess(pjp)) {
thisField = pjp.getThis();
}
if (cover.up() && !pjp.getKind().equals(JoinPoint.FIELD_GET)
&& (cover.upRegEx() == "" || Arrays.toString(pjp.getArgs()).matches(cover.upRegEx()))) {
log("COVERUP: "+ pjp.getSourceLocation() + ": " + pjp.toShortString() + " (" + Arrays.toString(pjp.getArgs()) + ")");
if (pjp.getKind().equals(JoinPoint.FIELD_SET)) {
Field field = getField(pjp);
if (field.getType().isInterface()) {
log("\tsetting proxy on field " + field);
log("TODO-ERROR: setting field with proxy is not working on aspectj!!!");
result = createProxy(cover, pjp);
} else { // we can't coverup here, otherwise we set only null fields!
result = invokeOrCover(CoverBody.class, cover.body(), pjp);
}
} else {
result = invokeOrCover(CoverBody.class, cover.body(), pjp);
}
} else {
result = invokeOrCover(CoverBody.class, cover.body(), pjp);
}
invokeOrCover(CoverAfter.class, cover.after(), pjp);
}
log("<-------");
return result;
} catch (Throwable ex) {
ex.printStackTrace(); // otherwise no error will be logged
throw ex;
}
}
private boolean isFieldAccess(ProceedingJoinPoint pjp) {
return pjp.getKind().equals(pjp.FIELD_GET) || pjp.getKind().equals(pjp.FIELD_SET);
}
private Field getField(ProceedingJoinPoint pjp) throws NoSuchFieldException {
return pjp.getSignature().getDeclaringType().getDeclaredField(pjp.getSignature().getName());
}
private Object invokeOrCover(
Class extends Annotation> inspectionPoint,
Class> staticClass, ProceedingJoinPoint pjp) throws Throwable {
return invokeOrCover_(false, inspectionPoint, staticClass, pjp);
}
// there is a bug on aspectj - standard function overloading ends up in an internal error!! so we use the '_'
private Object invokeOrCover_(
boolean coverUp,
Class extends Annotation> inspectionPoint,
Class> staticClass, ProceedingJoinPoint pjp) throws Throwable {
Method coverMethod;
if ((coverMethod = findMethod(staticClass, pjp, inspectionPoint)) != null)
return coverMethod(staticClass, coverMethod, pjp, inspectionPoint);
else if (!coverUp && inspectionPoint.equals(CoverBody.class))
return pjp.proceed();
else
return null;
}
private Method findMethod(Class> staticClass, ProceedingJoinPoint pjp, Class extends Annotation> inspectionPoint) {
try {
Class> cls = !staticClass.equals(Class.class) ? staticClass : caller(pjp).getClass();
String postfix = inspectionPoint.getSimpleName().toLowerCase().contains("body") ? "" : inspectionPoint.getSimpleName();
String name = pjp.getSignature().getName() + postfix;
System.out.print("\tcalling @" + inspectionPoint.getSimpleName() + " " + cls.getSimpleName() + "." + name + "(CoverArgs)...");
Method m = cls.getDeclaredMethod(name, new Class[]{CoverArgs.class});
return m.isAnnotationPresent(inspectionPoint) ? m : null;
} catch (NoSuchMethodException | SecurityException e) {
log("not available!");
return null; // ok, no problem
}
}
private Object caller(ProceedingJoinPoint pjp) {
return thisField == null || isFieldAccess(pjp) ? pjp.getThis() : thisField;
}
private Object coverMethod(Class> staticClass, Method coverMethod,
ProceedingJoinPoint pjp,
Class extends Annotation> inspectionPoint)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Object result = coverMethod.invoke(staticClass.equals(Class.class)
? caller(pjp) : null, createCoverArgs(pjp, inspectionPoint));
log("done! result=" + result);
return result;
}
private CoverArgs createCoverArgs(ProceedingJoinPoint pjp, Class extends Annotation> inspectionPoint) {
return new CoverArgs(pjp.toLongString(), caller(pjp), pjp.getTarget(), inspectionPoint, pjp.getArgs());
}
private Object createProxy(final Cover cover, final ProceedingJoinPoint pjp)
throws IllegalArgumentException, NoSuchFieldException {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{getField(pjp).getType()}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log("COVERPROXY: " + method + ": " + Arrays.toString(args));
if (method.toString().matches(cover.upRegEx())) {
return invokeOrCover_(true, CoverBody.class, cover.body(), pjp);
} else { //call on original instance
return method.invoke(pjp.getTarget(), args);
}
}
});
}
private void logInfo(ProceedingJoinPoint pjp) {
AbstractAspect.log(pjp.toShortString() + "(" + Arrays.toString(pjp.getArgs()) + ")");
}
private static final void log(Object o) {
System.out.println(o);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy