Fix Truncation of @PathVariable After Dot in Spring MVC

The Problem

Recently, while working on a project I encountered a strange behavior with the path variable binding in Spring controllers. It seems that, by default, the text after the last dot gets truncated in the @PathVariable value. So I decided to share this problem and a solution for it in this post:) Let’s take a look at a piece of code.

@RestController
public class DemoController {

    @GetMapping("/example/{firstValue}/{secondValue}")
    public void example(@PathVariable("firstValue") String firstValue,
                        @PathVariable("secondValue") String secondValue,
                        HttpServletRequest request) {
        System.out.println(request.getRequestURI());
        System.out.println("First value: " + firstValue);
        System.out.println("Second value: " + secondValue);
        System.out.println("---");
    }
}

And now let’s see the output of some HTTP requests:

For /example/romanian/coder
First value: romanian
Second value: coder

For /example/some.value/another.value
First value: some.value
Second value: another

For /example/some.value/another.value.two.dots
First value: some.value
Second value: another.value.two

Fix Truncation of @PathVariable After Dot in Spring MVC
It is obvious that the last dot from the last path variable gets truncated. The other values are not affected.

The Explanation

It turns out that Spring considers everything after the last dot sign (.) to be an extension. So it ignores it and binds your path variable by truncating the part that comes after the dot.

The Solution(s)

1.Modify the affected request by adding a regex mapping in the @PathVariable definition. In our case it will be {:.+secondValue}

@RestController
public class DemoController {

    @GetMapping("/example/{firstValue}/{secondValue:.+}")   //modified last path variable with regex mapping
    public void example(@PathVariable("firstValue") String firstValue,
                        @PathVariable("secondValue") String secondValue,
                        HttpServletRequest request) {
        System.out.println("For " + request.getRequestURI());
        System.out.println("First value: " + firstValue);
        System.out.println("Second value: " + secondValue);
        System.out.println("---");
    }
}

For /example/some.value/another.value.two.dots
First value: some.value
Second value: another.value.two.dots

2.Add ‘/’ at the end of your request and modify the request accordingly

@RestController
public class DemoController {

    @GetMapping("/example/{firstValue}/{secondValue}/")   //path now ends in /
    public void example(@PathVariable("firstValue") String firstValue,
                        @PathVariable("secondValue") String secondValue,
                        HttpServletRequest request) {
        System.out.println("For " + request.getRequestURI());
        System.out.println("First value: " + firstValue);
        System.out.println("Second value: " + secondValue);
        System.out.println("---");
    }
}

For /example/some.value/another.value.two.dots/
First value: some.value
Second value: another.value.two.dots

3.Create or modify the web configuration class in order to make the behavior global

@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {
    /**
     * Override default behaviour for all requests by setting the suffix pattern match
     * to false
     * @return
     */
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
        handlerMapping.setUseSuffixPatternMatch(false);
        return handlerMapping;
    }
}

For /example/some.value/another.value.two.dots
First value: some.value
Second value: another.value.two.dots

If you are using Spring Boot, then you can create a new class for extending the Web MVC configuration.