Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reflectively getting list of Spring MVC controllers matching specific url

How to reflectively get list of all controllers (best if not only annotated, but also specified in xml), matching some specfic url in your Spring MVC application?

In case of annotated-only,

@Autowired
private ListableBeanFactory listableBeanFactory;
...
whatever() {
    Map<String,Object> beans = listableBeanFactory.getBeansWithAnnotation(RequestMapping.class);

    // iterate beans and compare RequestMapping.value() annotation parameters
    // to produce list of matching controllers
}

could be used, but what to do in more general case, when controllers may be specified in spring.xml config? And what to do with request-path parameters?

like image 970
Alexander Tumin Avatar asked Dec 24 '12 21:12

Alexander Tumin


3 Answers

Since Spring 3.1, there is the class RequestMappingHandlerMapping, it delivers information about the mapping (RequestMappingInfo) of @Controller classes.

@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;

@PostConstruct
public void init() {
    Map<RequestMappingInfo, HandlerMethod> handlerMethods =
                              this.requestMappingHandlerMapping.getHandlerMethods();

    for(Entry<RequestMappingInfo, HandlerMethod> item : handlerMethods.entrySet()) {
        RequestMappingInfo mapping = item.getKey();
        HandlerMethod method = item.getValue();

        for (String urlPattern : mapping.getPatternsCondition().getPatterns()) {
            System.out.println(
                 method.getBeanType().getName() + "#" + method.getMethod().getName() +
                 " <-- " + urlPattern);

            if (urlPattern.equals("some specific url")) {
               //add to list of matching METHODS
            }
        }
    }       
}

It is important that this bean is defined in the spring context where the controllers are defined.

like image 169
Ralph Avatar answered Nov 16 '22 15:11

Ralph


You get a mapped Controller by calling HandlerMapping.getHandler(HTTPServletRequest).getHandler(). An HandlerMapping instance can be aquired by IoC. If you don't have a HTTPServletRequest you can build your Request with a MockHttpServletRequest.

@Autowired
private HandlerMapping mapping;

public Object getController(String uri) {
    MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
    // configure your request to some mapping
    HandlerExecutionChain chain = mapping.getHandler(request);
    return chain.getHandler();
}

Sorry, I read now that you want all controllers for a URL. This will geht you only one exactly matched controller. It's obviously not want you need.

like image 5
Markus Malkusch Avatar answered Nov 16 '22 16:11

Markus Malkusch


You can try using ListableBeanFactory interface to retrieve all bean names.

private @Autowired ListableBeanFactory beanFactory;

public void doStuff() {
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        if (beanName.startsWith("env")) { // or whatever check you want to do
            Object bean = beanFactory.getBean(beanName)
            // .. do something with it
        }
    }
}

See documentation of ListableBeanFactory here. This interface provides several methods like getBeansOfType(), getBeanDefinitionCount() etc.

If this approach does not list @Controller annotated beans visit this page to see how that can be done.

like image 3
Jeevan Patil Avatar answered Nov 16 '22 15:11

Jeevan Patil