mardi 6 septembre 2016

Using reflection

We are trying to use reflection to extract the exact mapped values to our methods. The code structure in the target module consists of multiple classes as follows -

@Controller
@RequestMapping(value = "/questions")
public class XYZController {

  @RequestMapping(value = "/ask")
  public boolean myMethod1() {..}

  @RequestMapping(value = "/{questionNo.}/{questionTitle}")
  public MyReturnObject myMethod2(){..}

}

What we are trying to grep here is the list of endpoints like /questions/ask and /questions/{questionNo.}/{questionTitle} for which the code we tried to execute filters all such classes based on the @Controller annotation and at the same time we are able to get the list of all the endpoints separately. The code we have tried so far is -

public class ReflectApi {

    public static void main(String[] args) {
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(true);
        final List<String> filteredClasses = new ArrayList<>();
        scanner.addIncludeFilter(new AnnotationTypeFilter(Controller.class));
        Set<BeanDefinition> filteredPackage = scanner.findCandidateComponents("com.package.test");

        // gives me a list of all the filtered classes
        filteredPackage.stream().forEach(beanDefinition -> filteredClasses.add(beanDefinition.getBeanClassName()));

        // call to get the annotation details
        filteredClasses.stream().forEach(filteredClass -> getEndPoints(filteredClass));
    }

    public static void getEndPoints(String controllerClassName) {
        try {
            Class clazz = Class.forName(controllerClassName);
            Annotation classAnnotation = clazz.getDeclaredAnnotation(RequestMapping.class);
            if (classAnnotation != null) {
                RequestMapping mappedValue = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
                System.out.println("Controller Mapped -> " + mappedValue.value()[0]); //This gives me the value for class like "/questions"
                runAllAnnotatedWith(RequestMapping.class);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    // followed from a SO reference
    public static void runAllAnnotatedWith(Class<? extends Annotation> annotation) {
        Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forJavaClassPath())
                .setScanners(new MethodAnnotationsScanner()));
        Set<Method> methods = reflections.getMethodsAnnotatedWith(annotation);

        methods.stream().forEach(m -> {
            if (m != null) {
                RequestMapping mappedValue = m.getAnnotation(RequestMapping.class); //this is listing out all the @RequestMapping annotations like "/questions" , "/ask" etc.
                    System.out.println(mappedValue.value()[0]);
            }
        });
    }
}

But the missing part is the concatenation of the class to method RequestMapping value here.

How do we loop inside a class to search annotations only from its methods?

Or is there any simpler way of doing this from what we are using?

References used - Scanning Java annotations at runtime && How to run all methods with a given annotation?





Aucun commentaire:

Enregistrer un commentaire