Inspired by this article http://mydailyjava.blogspot.com/2022/02/using-byte-buddy-for-proxy-creation.html, I managed to intercept a method invocation, check all the method parameter's values, and return a mock response.
However, I cannot get the parameters' actual names (as in source code). I can only get names such as "arg0".
The best effort I made is, in a method matcher, I have access to the method's MethodDescription, and I can get the parameter's ParameterDescription.
@Override
public DynamicType.Builder<?> apply(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassFileLocator classFileLocator) {
logger.info("OiiPlugin processing "+typeDescription);
return builder
.method(new ElementMatcher<MethodDescription>() {
@Override
public boolean matches(MethodDescription target) {
boolean isTarget = target.getDeclaredAnnotations().isAnnotationPresent(MockMe.class);
if (isTarget) {
ParameterDescription p = target.getParameters().get(0);
logger.info(
"Parameter 0 NAME:"+p.getActualName()+":"+p.getName()+":"+p.getInternalName());
};
return isTarget;
}
})
.intercept(MethodDelegation.to(
OiiInterceptor.class
));
}
However, its getActualName() returns empty string.
[INFO] OiiPlugin processing class com.example.research.oii.client.ExampleClient
[INFO] Parameter 0 NAME::arg0:arg0
I did add javac -g:vars parameter through maven plugin config, to instruct javac put parameter names into the .class files.
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<compilerArgs>
<arg>-g:vars</arg>
</compilerArgs>
</configuration>
</plugin>
What else can I do?
Thanks!
Post Note:
Thanks @boneill for the answer. After using -parameters with compiler:
@RuntimeType
public static Object intercept(
@This Object self,
@Origin Method method,
@AllArguments Object[] args,
@SuperMethod Method superMethod
) throws Throwable {
// need to get parameter name from @Origin method, not @SuperMethod
Parameter[] parameters = method.getParameters();
Object[] mockInterceptionParameters = new Object[parameters.length*2];
for (int i=0; i<parameters.length; i++) {
Parameter p = parameters[i];
mockInterceptionParameters[i*2] = p.getName();
mockInterceptionParameters[i*2+1] = args[i];
}
.... ....
}
You need to pass the -parameters
argument to the java compiler. The -g:vars
argument provides information regarding all local variables, but the attribute which defines this is never accessible using the reflection API. When using -parameters
, a special attribute is used which is explicitly designed for being accessed by the reflection API.