1

To be able to do stats per endpoint, I want to be able to get the @RequestMapping annotation value, the parameterized version. My monitoring tool otherwise will consider different ids as different urls:

@RequestMapping(value = "/customers/{customerId}/items/{itemId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<ItemDetailsDto> getItemById(
      @PathVariable(value = "customerId") int customerId
      @PathVariable(value = "itemId") int itemId)
      throws Exception
  {
    //do stuff

    //I want this to be "/customers/{customerId}/items/{itemId}"
    //,not "/customers/15988/items/85"
    String s = ????
  }

How can I grab /customers/{customerId}/items/{itemId} at runtime? My tool allows me to intercept methods and capture its parameters, so I could also monitor a specific method in the Spring framework to catch the setting or getting of something for example.

Icegras
  • 173
  • 1
  • 3
  • 8

2 Answers2

0

You can use Java reflection to do so, you just need to do like this:

String s= this.getClass().getDeclaredMethod("getItemById", int.class, int.class).getAnnotation(RequestMapping.class).value();

For the getDeclaredMethod the first parameter is the name of method and the other parameters are the parameters' types of that method.

Ismail
  • 2,322
  • 1
  • 12
  • 26
0

Another approach will be

private static final String URI_GET_ITEM_BY_ID ="/customers/{customerId}/items/{itemId}";

@RequestMapping(value = URI_GET_ITEM_BY_ID, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<ItemDetailsDto> getItemById(
      @PathVariable(value = "customerId") int customerId
      @PathVariable(value = "itemId") int itemId)
      throws Exception
  {
    //do stuff

    // Use URI_GET_ITEM_BY_ID

  }

Update 1:

Assuming the controller is annotated with @RestController

@RestController
public class SampleController {

      @RequestMapping(value = "/customers/{customerId}/items/{itemId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<ItemDetailsDto> getItemById(
      @PathVariable(value = "customerId") int customerId
      @PathVariable(value = "itemId") int itemId)
      throws Exception
  {
    //do stuff

    //I want this to be "/customers/{customerId}/items/{itemId}"
    //,not "/customers/15988/items/85"
    String s = ????
  }

}

following Aspect can be used to get the URI path without altering the controller methods.

@Aspect
@Component
public class RestControllerAspect {

    @Pointcut("@within(org.springframework.web.bind.annotation.RestController) && within(rg.boot.web.controller.*)")
    public void isRestController() {

    }

    @Before("isRestController()")
    public void handlePost(JoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();

        // controller method annotations of type @RequestMapping
        RequestMapping[] reqMappingAnnotations = method
                .getAnnotationsByType(org.springframework.web.bind.annotation.RequestMapping.class);
        for (RequestMapping annotation : reqMappingAnnotations) {
            System.out.println(annotation.toString());
            for(String val : annotation.value()) {
                System.out.println(val);
            }
        }

    }
}

This would print

@org.springframework.web.bind.annotation.RequestMapping(path=[], headers=[], method=[GET], name=, produces=[application/json], params=[], value=[/customers/{customerId}/items/{itemId}], consumes=[])
/customers/{customerId}/items/{itemId}

for a request to URI : /customers/1234/items/5678

Update 2:

Another way is to import

import static org.springframework.web.servlet.HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE;
import org.springframework.web.context.request.RequestContextHolder;

and get the path using the following code

 RequestAttributes reqAttributes = RequestContextHolder.currentRequestAttributes(); 
 String s = reqAttributes.getAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, 0);

This is adapted from my answer to another question.

R.G
  • 6,436
  • 3
  • 19
  • 28
  • Yeah that's the simplest solution, but I have over 200 controller methods and I'm trying to find a single way to get them all at runtime instead of altering my 200 methods. – Icegras Mar 13 '20 at 14:23
  • Ah!! Spring AOP then ? I have a similar answer [here](https://stackoverflow.com/a/59743940/4214241) – R.G Mar 13 '20 at 14:43