4

Is it possible to control a @RestController programmatically to enable it or disable it? I don't want to just write code in each @RequestMapping method to do some kind of if (!enabled) { return 404Exception; }

I've seen this question but that works only at startup time. What I need is really something that would allow me to enable or disable the controller multiple times.

I've thought of different ways but don't know which are doable in spring.

  1. Actually control the container (jetty in my case) so requests to that particular endpoint are disabled
  2. Somehow control RequestMappingHandlerMapping since it seems to be that class that does the mapping between urls and controllers
  3. control the lifecycle of the @RestController component so that i can create it and destroy it at will, but then i'm not sure how to trigger the mapping to the endpoint
Cœur
  • 37,241
  • 25
  • 195
  • 267
Hilikus
  • 9,954
  • 14
  • 65
  • 118
  • The `if(!enabled)` logic is likely to be a lot simpler than a custom implementation of `RequestMappingHandlerMapping`. Look at a feature toggling framework like Togglz. – nbrooks Aug 23 '17 at 02:45
  • How about this? https://stackoverflow.com/questions/44456388/conditionalonexpression-on-a-class-object-getter – Raphael Amoedo Aug 23 '17 at 03:41
  • A few things came to my mind - Interceptors (url path based) or ControllerAdvice (this may be closer to what you want). Also, maybe you can start poking from DispatcherServlet but I have never tried that b4. – hummingV Aug 23 '17 at 04:25
  • You can add filter for your endpoint: https://stackoverflow.com/questions/19825946/how-to-add-a-filter-class-in-spring-boot/45833337#45833337 . Check 'enabled' property in it and act appropriately. – Justinas Jakavonis Aug 23 '17 at 08:30

1 Answers1

2

If the end result is that you want to respond with a 404 when you decide that a specific endpoint should be disabled then you could write an interceptor which checks whether your enabled condition is false and, if so, sets the response accordingly.

For example:

@Component
public class ConditionalRejectionInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        String requestUri = request.getRequestURI();
        if (shouldReject(requestUri)) {
            response.setStatus(HttpStatus.NOT_FOUND.value());
            return false;
        }
        return super.preHandle(request, response, handler);
    }

    private boolean shouldReject(String requestUri) {
        // presumably you have some mechanism of inferring or discovering whether 
        // the endpoint represented by requestUri should be allowed or disallowed
        return ...;
    }
}

In Spring Boot, registering your own interceptor just involves implementing a WebMvcConfigurerAdapter. For example:

@Configuration
public class CustomWebMvcConfigurer extends WebMvcConfigurerAdapter {

  @Autowired 
  private HandlerInterceptor conditionalRejectionInterceptor;

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // you can use .addPathPatterns(...) here to limit this interceptor to specific endpoints
    // this could be used to replace any 'conditional on the value of requestUri' code in the interceptor
    registry.addInterceptor(conditionalRejectionInterceptor);
  }
}
Hilikus
  • 9,954
  • 14
  • 65
  • 118
glytching
  • 44,936
  • 9
  • 114
  • 120
  • this worked almost perfectly. i had to add a `return false` in the should reject, otherwise the request continues down the chain of handlers – Hilikus Aug 27 '17 at 00:02