How to check if a parameter of the current method

2019-03-19 17:18发布

Consider this code:

public example(String s, int i, @Foo Bar bar) {
  /* ... */
}

I want to check if the method has an annotation @Foo and get the argument or throw an exception if no @Foo annotation is found.

My current approach is to first get the current method and then iterate through the parameter annotations:

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

class Util {

    private Method getCurrentMethod() {
        try {
            final StackTraceElement[] stes = Thread.currentThread().getStackTrace();
            final StackTraceElement ste = stes[stes.length - 1];
            final String methodName = ste.getMethodName();
            final String className = ste.getClassName();   
            final Class<?> currentClass = Class.forName(className);
            return currentClass.getDeclaredMethod(methodName);
        } catch (Exception cause) {
            throw new UnsupportedOperationException(cause);
        }  
    }

    private Object getArgumentFromMethodWithAnnotation(Method method, Class<?> annotation) {
        final Annotation[][] paramAnnotations = method.getParameterAnnotations();    
            for (Annotation[] annotations : paramAnnotations) {
                for (Annotation an : annotations) {
                    /* ... */
                }
            }
    }

}

Is this the right approach or is there a better one? How would the code inside the forach loop look like? I'm not sure if I have understood the what getParameterAnnotations actually returns...

3条回答
放我归山
2楼-- · 2019-03-19 17:29

If you're looking for annotations on the method, you probably want method.getAnnotations() or method.getDeclaredAnnotations().

The method.getParameterAnnotations() call gives you annotations on the method's formal parameters, not on the method itself.

Looking back at the question title, I suspect you are looking for annotations on the parameters, which I didn't read in the content of the question. If that's the case, your code looks fine.

See Method Javadoc and AnnotatedElement Javadoc.

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-03-19 17:39

getParameterAnnotations returns an array with the length equals to the amount of method parameters. Each element in that array contains an array of annotations on that parameter.
So getParameterAnnotations()[2][0] contains the first ([0]) annotation of the third ([2]) parameter.

If you only need to check if at least one parameter contains an annotation of a specific type, the method could look like this:

private boolean isAnyParameterAnnotated(Method method, Class<?> annotationType) {
    final Annotation[][] paramAnnotations = method.getParameterAnnotations();    
    for (Annotation[] annotations : paramAnnotations) {
        for (Annotation an : annotations) {
            if(an.annotationType().equals(annotationType)) {
                return true;
            }
        }
    }
    return false;
}
查看更多
做自己的国王
4楼-- · 2019-03-19 17:42

The outer for loop

for (Annotation[] annotations : paramAnnotations) {
   ...
}

should use an explicit counter, otherwise you don't know what parameter you are processing right now

final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final Class[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramAnnotations.length; i++) {
    for (Annotation a: paramAnnotations[i]) {
        if (a instanceof Foo) {
            System.out.println(String.format("parameter %d with type %s is annotated with @Foo", i, paramTypes[i]);
        }
    }
}

Also make sure your annotation type is annotated with @Retention(RetentionPolicy.RUNTIME)

From your question it is not entirely clear what you are trying to do. We agree on the difference of formal parameters vs. actual arguments:

void foo(int x) { }

{ foo(3); }

where x is a parameter and 3 is an argument?

It is not possible to get the arguments of methods via reflection. If it is possible at all, you would have to use the sun.unsafe package. I can't tell you much about that though.

查看更多
登录 后发表回答