I have a generic method that accepts any type as its parameter.
For example, I would like a pointcut that matches the calls made to the method only with 'String' type as its parameter. Ultimately the requirement is to limit the scope which the advices get executed for to 'String' parameters.
Here is my generic class and method:
public class Param<T> {
public T execute(T s){
return s;
}
}
Main class: My app makes calls to the method with both Boolean and String as parameters.
public static void main(String[] args) {
Param<String> sp = new Param<String>();
String rs = sp.execute("myString"); //want a joint point
Param<Boolean> bp = new Param<Boolean>();
Boolean rb = bp.execute(true); //dont want a joint point
}
Below pointcuts are valid for both String and Boolean parameters (work for any type actually). But I would like a pointcut to intercept method calls only when parameter is of type String.
@Pointcut("call(* com.amazon.auiqa.aspectj.generics.Param.execute(**))")
void param(){}
@Pointcut("execution(Object com.amazon.auiqa.aspectj.generics.Param.execute(Object))")
void param(){}
Below ones did not work for me:
@Pointcut("execution(String com.amazon.auiqa.aspectj.generics.Param.execute(String))")
@Pointcut("call(String com.amazon.auiqa.aspectj.generics.Param.execute(String))")
I was wondering if it is possible to achieve what I want to achieve here. I would like to do the same thing with method return types.
Explanation: Union means the methods that either pointcut matches. Intersection means the methods that both pointcuts match. Union is usually more useful. Explanation: Using the static methods in the org.
Spring AOP only supports method execution join points for Spring beans, so you can think of a pointcut as matching the execution of methods on Spring beans.
This pointcut matches any method that starts with find and has only one parameter of type Long. If we want to match a method with any number of parameters, but still having the fist parameter of type Long, we can use the following expression: @Pointcut("execution(* *.. find*(Long,..))")
AspectJ provides primitive pointcuts that capture join points at these times. These pointcuts use the dynamic types of their objects to pick out join points. They may also be used to expose the objects used for discrimination. this(Type or Id) target(Type or Id)
You cannot do that with AspectJ, nor with any other bytecode manipulation library as generic type information is actually erased from the compiled bytecode (as of Java 9), so your generic method becomes public Object execute(Object s)
, since the type argument T
is unbounded. See Type Erasure at the Java Documentation for further info.
While the original method signature is preserved in the form of metadata, the compiler can check whether type bounds are respected or not while compiling against generic code, but this will not help you in any way to determine what generic type argument an instance of that class was instantiated with, because that information is simply not present at all.
It's true what the other posting mentioned about Java erasure.
AspectJ 5 does not allow the use of type variables in pointcut expressions and type patterns. Instead, members that use type parameters as part of their signature are matched by their erasure. Java 5 defines the rules for determing the erasure of a type as follows.
Let
|T|
represent the erasure of some typeT
. Then:
The erasure of a parameterized type
T<T1,...,Tn>
is|T|
. For example, the erasure ofList<String>
isList
.The erasure of a nested type
T.C
is|T|.C
. For example, the erasure of the nested typeFoo<T>.Bar
isFoo.Bar
.The erasure of an array type
T[]
is |T|[]
. For example, the erasure ofList<String>[]
isList[]
.The erasure of a type variable is its leftmost bound. For example, the erasure of a type variable
P
isObject
, and the erasure of a type variableN extends Number
isNumber
.
You can find more here.
However, you can do the following:
execute
method executions of Param
.String
arguments by the type of argument by using instanceof
.Remember, a plus sign (+
) is needed to indicate a generic.
Here is an example,
@Component
@Aspect
public class ParamAspect {
@Pointcut("execution(public * com.amazon.auiqa.aspectj.generics.Param+.execute(..))")
public void pointcut() {
}
@Before("pointcut()")
public void intercept(JoinPoint jp) {
System.out.println(
"Entering class: " + jp.getSignature().getDeclaringTypeName() +
" - before method: " + jp.getSignature().getName());
// check for argument type of String
Object[] args = jp.getArgs();
if (args.length == 1) {
if (args[0] instanceof String) {
System.out.println("1. parameter type is string");
} else {
System.out.println("2. parameter type is not string");
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With