Kazuki Shimizu opened SPR-15558 and commented

I've tried the {*...} pattern on reactive handler method as follow:

Controller

@RestController
public class MyController {
    @GetMapping("/{*paths}")
    Mono<String> hello(@PathVariable String paths) {
        return Mono.defer(() -> Mono.just("Hello World !! on " + paths));
    }
}

cURL Command

$ curl -D - http://localhost:8080/a
HTTP/1.1 500 Internal Server Error
content-length: 0

StackTrace

...
05:15:08.073 [reactor-http-nio-4] ERROR org.springframework.web.server.adapter.HttpWebHandlerAdapter - Failed to handle request
org.springframework.web.util.patterns.PatternParseException: No more pattern data allowed after {*...} pattern element
    at org.springframework.web.util.patterns.InternalPathPatternParser.parse(InternalPathPatternParser.java:157)
    at org.springframework.web.util.patterns.PathPatternParser.parse(PathPatternParser.java:85)
    at org.springframework.web.util.ParsingPathMatcher.getPathPattern(ParsingPathMatcher.java:115)
    at org.springframework.web.util.ParsingPathMatcher.match(ParsingPathMatcher.java:50)
    at org.springframework.web.reactive.result.condition.PatternsRequestCondition.getMatchingPattern(PatternsRequestCondition.java:237)
    at org.springframework.web.reactive.result.condition.PatternsRequestCondition.getMatchingPatterns(PatternsRequestCondition.java:214)
    at org.springframework.web.reactive.result.condition.PatternsRequestCondition.getMatchingCondition(PatternsRequestCondition.java:195)
    at org.springframework.web.reactive.result.method.RequestMappingInfo.getMatchingCondition(RequestMappingInfo.java:219)
    at org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfoHandlerMapping.java:88)
    at org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfoHandlerMapping.java:57)
    at org.springframework.web.reactive.result.method.AbstractHandlerMethodMapping.addMatchingMappings(AbstractHandlerMethodMapping.java:339)
    at org.springframework.web.reactive.result.method.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:306)
    at org.springframework.web.reactive.result.method.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:264)
    at org.springframework.web.reactive.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:159)
    at org.springframework.web.reactive.DispatcherHandler.lambda$handle$0(DispatcherHandler.java:126)
...

Affects: 5.0 RC1

Issue Links: - #19868 When using ParsingPathMatcher in MVC user should not have to also explicitly set suffix matching

1 votes, 3 watchers

Comment From: spring-projects-issues

Kazuki Shimizu commented

This behavior also occurs on Spring MVC handler method as follow:

Configuration (apply the ParsingPathMatcher)

@Bean
public WebMvcConfigurer webMvcConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void configurePathMatch(PathMatchConfigurer configurer) {
            configurer.setPathMatcher(new ParsingPathMatcher()); // Add
        }
    };
}

Controller

@RestController
public class PathMatcherRestController {

    @GetMapping("/path-matcher/{*paths}")
    String get(@PathVariable String paths) {
        return paths;
    }

}

I can prevent this error using useSuffixPatternMatch=false as follow:

@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
    configurer.setPathMatcher(new ParsingPathMatcher());
    configurer.setUseSuffixPatternMatch(false); // Add
}

What do you think ?

Comment From: spring-projects-issues

Brian Clozel commented

Since changing the configuration behind the user's back or silently ignoring the exceptions were not good options, I've added a configuration check in the PathMatchConfigurer to throw an exception explaining the issue.

Thanks for your report!

Comment From: Mascotch

As a temporary workaround, replicate the class org.springdoc.core.data.DataRestOperationService in your application and add the check for null annotation in line 242.

        Param annotation = parameter.getAnnotation(Param.class);
        if (pName.equals(parameter.getName()) || (annotation != null && pName.equals(annotation.value()))) {

Remove the class if the next release fixes the problem;