下面列出了org.springframework.core.annotation.MergedAnnotations#org.springframework.web.reactive.result.method.RequestMappingInfo 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Uses method and type-level @{@link RequestMapping} annotations to create
* the RequestMappingInfo.
* @return the created RequestMappingInfo, or {@code null} if the method
* does not have a {@code @RequestMapping} annotation.
* @see #getCustomMethodCondition(Method)
* @see #getCustomTypeCondition(Class)
*/
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
for (Map.Entry<String, Predicate<Class<?>>> entry : this.pathPrefixes.entrySet()) {
if (entry.getValue().test(handlerType)) {
String prefix = entry.getKey();
if (this.embeddedValueResolver != null) {
prefix = this.embeddedValueResolver.resolveStringValue(prefix);
}
info = RequestMappingInfo.paths(prefix).build().combine(info);
break;
}
}
}
return info;
}
/**
* Create a {@link RequestMappingInfo} from the supplied
* {@link RequestMapping @RequestMapping} annotation, which is either
* a directly declared annotation, a meta-annotation, or the synthesized
* result of merging annotation attributes within an annotation hierarchy.
*/
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
RequestMappingInfo.Builder builder = RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name());
if (customCondition != null) {
builder.customCondition(customCondition);
}
return builder.options(this.config).build();
}
@Override
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
Class<?> beanType = handlerMethod.getBeanType();
CrossOrigin typeAnnotation = AnnotatedElementUtils.findMergedAnnotation(beanType, CrossOrigin.class);
CrossOrigin methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);
if (typeAnnotation == null && methodAnnotation == null) {
return null;
}
CorsConfiguration config = new CorsConfiguration();
updateCorsConfig(config, typeAnnotation);
updateCorsConfig(config, methodAnnotation);
if (CollectionUtils.isEmpty(config.getAllowedMethods())) {
for (RequestMethod allowedMethod : mappingInfo.getMethodsCondition().getMethods()) {
config.addAllowedMethod(allowedMethod.name());
}
}
return config.applyPermitDefaultValues();
}
@Test
public void customPathMatchConfig() {
ApplicationContext context = loadConfig(CustomPatchMatchConfig.class);
final Field field = ReflectionUtils.findField(PathPatternParser.class, "matchOptionalTrailingSeparator");
ReflectionUtils.makeAccessible(field);
String name = "requestMappingHandlerMapping";
RequestMappingHandlerMapping mapping = context.getBean(name, RequestMappingHandlerMapping.class);
assertNotNull(mapping);
PathPatternParser patternParser = mapping.getPathPatternParser();
assertNotNull(patternParser);
boolean matchOptionalTrailingSlash = (boolean) ReflectionUtils.getField(field, patternParser);
assertFalse(matchOptionalTrailingSlash);
Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
assertEquals(1, map.size());
assertEquals(Collections.singleton(new PathPatternParser().parse("/api/user/{id}")),
map.keySet().iterator().next().getPatternsCondition().getPatterns());
}
@Test
public void compareTwoHttpMethodsOneParam() {
RequestMappingInfo none = paths().build();
RequestMappingInfo oneMethod = paths().methods(RequestMethod.GET).build();
RequestMappingInfo oneMethodOneParam = paths().methods(RequestMethod.GET).params("foo").build();
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/foo"));
Comparator<RequestMappingInfo> comparator = (info, otherInfo) -> info.compareTo(otherInfo, exchange);
List<RequestMappingInfo> list = asList(none, oneMethod, oneMethodOneParam);
Collections.shuffle(list);
list.sort(comparator);
assertEquals(oneMethodOneParam, list.get(0));
assertEquals(oneMethod, list.get(1));
assertEquals(none, list.get(2));
}
@Test
@Ignore
public void preFlightRequest() throws Exception {
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.options("/foo")
.header("Origin", "https://domain.com")
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, "POST")
);
RequestMappingInfo info = paths("/foo").methods(RequestMethod.POST).build();
RequestMappingInfo match = info.getMatchingCondition(exchange);
assertNotNull(match);
info = paths("/foo").methods(RequestMethod.OPTIONS).build();
match = info.getMatchingCondition(exchange);
assertNull("Pre-flight should match the ACCESS_CONTROL_REQUEST_METHOD", match);
}
private RequestMappingInfo assertComposedAnnotationMapping(String methodName, String path,
RequestMethod requestMethod) throws Exception {
Class<?> clazz = ComposedAnnotationController.class;
Method method = ClassUtils.getMethod(clazz, methodName, (Class<?>[]) null);
RequestMappingInfo info = this.handlerMapping.getMappingForMethod(method, clazz);
assertNotNull(info);
Set<PathPattern> paths = info.getPatternsCondition().getPatterns();
assertEquals(1, paths.size());
assertEquals(path, paths.iterator().next().getPatternString());
Set<RequestMethod> methods = info.getMethodsCondition().getMethods();
assertEquals(1, methods.size());
assertEquals(requestMethod, methods.iterator().next());
return info;
}
/**
* Calculate path.
*
* @param restControllers the rest controllers
* @param map the map
*/
protected void calculatePath(Map<String, Object> restControllers, Map<RequestMappingInfo, HandlerMethod> map) {
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : map.entrySet()) {
RequestMappingInfo requestMappingInfo = entry.getKey();
HandlerMethod handlerMethod = entry.getValue();
PatternsRequestCondition patternsRequestCondition = requestMappingInfo.getPatternsCondition();
Set<PathPattern> patterns = patternsRequestCondition.getPatterns();
for (PathPattern pathPattern : patterns) {
String operationPath = pathPattern.getPatternString();
Map<String, String> regexMap = new LinkedHashMap<>();
operationPath = PathUtils.parsePath(operationPath, regexMap);
if (operationPath.startsWith(DEFAULT_PATH_SEPARATOR)
&& (restControllers.containsKey(handlerMethod.getBean().toString()) || actuatorProvider.isPresent())
&& isPackageToScan(handlerMethod.getBeanType().getPackage()) && isPathToMatch(operationPath)) {
Set<RequestMethod> requestMethods = requestMappingInfo.getMethodsCondition().getMethods();
// default allowed requestmethods
if (requestMethods.isEmpty())
requestMethods = this.getDefaultAllowedHttpMethods();
calculatePath(handlerMethod, operationPath, requestMethods);
}
}
}
}
/**
* Uses method and type-level @{@link RequestMapping} annotations to create
* the RequestMappingInfo.
* @return the created RequestMappingInfo, or {@code null} if the method
* does not have a {@code @RequestMapping} annotation.
* @see #getCustomMethodCondition(Method)
* @see #getCustomTypeCondition(Class)
*/
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
for (Map.Entry<String, Predicate<Class<?>>> entry : this.pathPrefixes.entrySet()) {
if (entry.getValue().test(handlerType)) {
String prefix = entry.getKey();
if (this.embeddedValueResolver != null) {
prefix = this.embeddedValueResolver.resolveStringValue(prefix);
}
info = RequestMappingInfo.paths(prefix).build().combine(info);
break;
}
}
}
return info;
}
/**
* Create a {@link RequestMappingInfo} from the supplied
* {@link RequestMapping @RequestMapping} annotation, which is either
* a directly declared annotation, a meta-annotation, or the synthesized
* result of merging annotation attributes within an annotation hierarchy.
*/
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
RequestMappingInfo.Builder builder = RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name());
if (customCondition != null) {
builder.customCondition(customCondition);
}
return builder.options(this.config).build();
}
@Override
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
Class<?> beanType = handlerMethod.getBeanType();
CrossOrigin typeAnnotation = AnnotatedElementUtils.findMergedAnnotation(beanType, CrossOrigin.class);
CrossOrigin methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);
if (typeAnnotation == null && methodAnnotation == null) {
return null;
}
CorsConfiguration config = new CorsConfiguration();
updateCorsConfig(config, typeAnnotation);
updateCorsConfig(config, methodAnnotation);
if (CollectionUtils.isEmpty(config.getAllowedMethods())) {
for (RequestMethod allowedMethod : mappingInfo.getMethodsCondition().getMethods()) {
config.addAllowedMethod(allowedMethod.name());
}
}
return config.applyPermitDefaultValues();
}
@Test
public void customPathMatchConfig() {
ApplicationContext context = loadConfig(CustomPatchMatchConfig.class);
final Field field = ReflectionUtils.findField(PathPatternParser.class, "matchOptionalTrailingSeparator");
ReflectionUtils.makeAccessible(field);
String name = "requestMappingHandlerMapping";
RequestMappingHandlerMapping mapping = context.getBean(name, RequestMappingHandlerMapping.class);
assertNotNull(mapping);
PathPatternParser patternParser = mapping.getPathPatternParser();
assertNotNull(patternParser);
boolean matchOptionalTrailingSlash = (boolean) ReflectionUtils.getField(field, patternParser);
assertFalse(matchOptionalTrailingSlash);
Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
assertEquals(1, map.size());
assertEquals(Collections.singleton(new PathPatternParser().parse("/api/user/{id}")),
map.keySet().iterator().next().getPatternsCondition().getPatterns());
}
@Test
public void compareTwoHttpMethodsOneParam() {
RequestMappingInfo none = paths().build();
RequestMappingInfo oneMethod = paths().methods(RequestMethod.GET).build();
RequestMappingInfo oneMethodOneParam = paths().methods(RequestMethod.GET).params("foo").build();
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/foo"));
Comparator<RequestMappingInfo> comparator = (info, otherInfo) -> info.compareTo(otherInfo, exchange);
List<RequestMappingInfo> list = asList(none, oneMethod, oneMethodOneParam);
Collections.shuffle(list);
list.sort(comparator);
assertEquals(oneMethodOneParam, list.get(0));
assertEquals(oneMethod, list.get(1));
assertEquals(none, list.get(2));
}
@Test
@Ignore
public void preFlightRequest() throws Exception {
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.options("/foo")
.header("Origin", "http://domain.com")
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, "POST")
);
RequestMappingInfo info = paths("/foo").methods(RequestMethod.POST).build();
RequestMappingInfo match = info.getMatchingCondition(exchange);
assertNotNull(match);
info = paths("/foo").methods(RequestMethod.OPTIONS).build();
match = info.getMatchingCondition(exchange);
assertNull("Pre-flight should match the ACCESS_CONTROL_REQUEST_METHOD", match);
}
private RequestMappingInfo assertComposedAnnotationMapping(String methodName, String path,
RequestMethod requestMethod) throws Exception {
Class<?> clazz = ComposedAnnotationController.class;
Method method = clazz.getMethod(methodName);
RequestMappingInfo info = this.handlerMapping.getMappingForMethod(method, clazz);
assertNotNull(info);
Set<PathPattern> paths = info.getPatternsCondition().getPatterns();
assertEquals(1, paths.size());
assertEquals(path, paths.iterator().next().getPatternString());
Set<RequestMethod> methods = info.getMethodsCondition().getMethods();
assertEquals(1, methods.size());
assertEquals(requestMethod, methods.iterator().next());
return info;
}
@Override
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setPatternParser(getPathPatternParser());
this.config.setContentTypeResolver(getContentTypeResolver());
super.afterPropertiesSet();
}
/**
* Delegates to {@link #createRequestMappingInfo(RequestMapping, RequestCondition)},
* supplying the appropriate custom {@link RequestCondition} depending on whether
* the supplied {@code annotatedElement} is a class or method.
* @see #getCustomTypeCondition(Class)
* @see #getCustomMethodCondition(Method)
*/
@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
private void updateConsumesCondition(RequestMappingInfo info, Method method) {
ConsumesRequestCondition condition = info.getConsumesCondition();
if (!condition.isEmpty()) {
for (Parameter parameter : method.getParameters()) {
MergedAnnotation<RequestBody> annot = MergedAnnotations.from(parameter).get(RequestBody.class);
if (annot.isPresent()) {
condition.setBodyRequired(annot.getBoolean("required"));
break;
}
}
}
}
@Test
public void createEmpty() {
RequestMappingInfo info = paths().build();
PathPattern emptyPattern = (new PathPatternParser()).parse("");
assertEquals(Collections.singleton(emptyPattern), info.getPatternsCondition().getPatterns());
assertEquals(0, info.getMethodsCondition().getMethods().size());
assertEquals(true, info.getConsumesCondition().isEmpty());
assertEquals(true, info.getProducesCondition().isEmpty());
assertNotNull(info.getParamsCondition());
assertNotNull(info.getHeadersCondition());
assertNull(info.getCustomCondition());
}
@Test
public void prependPatternWithSlash() {
RequestMappingInfo actual = paths("foo").build();
List<PathPattern> patterns = new ArrayList<>(actual.getPatternsCondition().getPatterns());
assertEquals(1, patterns.size());
assertEquals("/foo", patterns.get(0).getPatternString());
}
@Test
public void matchPatternsCondition() {
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/foo"));
RequestMappingInfo info = paths("/foo*", "/bar").build();
RequestMappingInfo expected = paths("/foo*").build();
assertEquals(expected, info.getMatchingCondition(exchange));
info = paths("/**", "/foo*", "/foo").build();
expected = paths("/foo", "/foo*", "/**").build();
assertEquals(expected, info.getMatchingCondition(exchange));
}
@Test
public void matchParamsCondition() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/foo?foo=bar"));
RequestMappingInfo info = paths("/foo").params("foo=bar").build();
RequestMappingInfo match = info.getMatchingCondition(exchange);
assertNotNull(match);
info = paths("/foo").params("foo!=bar").build();
match = info.getMatchingCondition(exchange);
assertNull(match);
}
@Test
public void matchHeadersCondition() {
MockServerHttpRequest request = MockServerHttpRequest.get("/foo").header("foo", "bar").build();
ServerWebExchange exchange = MockServerWebExchange.from(request);
RequestMappingInfo info = paths("/foo").headers("foo=bar").build();
RequestMappingInfo match = info.getMatchingCondition(exchange);
assertNotNull(match);
info = paths("/foo").headers("foo!=bar").build();
match = info.getMatchingCondition(exchange);
assertNull(match);
}
@Test
public void matchConsumesCondition() {
MockServerHttpRequest request = MockServerHttpRequest.post("/foo").contentType(MediaType.TEXT_PLAIN).build();
ServerWebExchange exchange = MockServerWebExchange.from(request);
RequestMappingInfo info = paths("/foo").consumes("text/plain").build();
RequestMappingInfo match = info.getMatchingCondition(exchange);
assertNotNull(match);
info = paths("/foo").consumes("application/xml").build();
match = info.getMatchingCondition(exchange);
assertNull(match);
}
@Test
public void matchProducesCondition() {
MockServerHttpRequest request = MockServerHttpRequest.get("/foo").accept(MediaType.TEXT_PLAIN).build();
ServerWebExchange exchange = MockServerWebExchange.from(request);
RequestMappingInfo info = paths("/foo").produces("text/plain").build();
RequestMappingInfo match = info.getMatchingCondition(exchange);
assertNotNull(match);
info = paths("/foo").produces("application/xml").build();
match = info.getMatchingCondition(exchange);
assertNull(match);
}
@Test
public void pathPrefix() throws Exception {
this.handlerMapping.setEmbeddedValueResolver(value -> "/${prefix}".equals(value) ? "/api" : value);
this.handlerMapping.setPathPrefixes(Collections.singletonMap(
"/${prefix}", HandlerTypePredicate.forAnnotation(RestController.class)));
Method method = UserController.class.getMethod("getUser");
RequestMappingInfo info = this.handlerMapping.getMappingForMethod(method, UserController.class);
assertNotNull(info);
assertEquals(Collections.singleton(new PathPatternParser().parse("/api/user/{id}")),
info.getPatternsCondition().getPatterns());
}
@Test
public void resolveRequestMappingViaComposedAnnotation() throws Exception {
RequestMappingInfo info = assertComposedAnnotationMapping("postJson", "/postJson", RequestMethod.POST);
assertEquals(MediaType.APPLICATION_JSON_VALUE,
info.getConsumesCondition().getConsumableMediaTypes().iterator().next().toString());
assertEquals(MediaType.APPLICATION_JSON_VALUE,
info.getProducesCondition().getProducibleMediaTypes().iterator().next().toString());
}
@Test // SPR-14988
public void getMappingOverridesConsumesFromTypeLevelAnnotation() throws Exception {
RequestMappingInfo requestMappingInfo = assertComposedAnnotationMapping(RequestMethod.POST);
ConsumesRequestCondition condition = requestMappingInfo.getConsumesCondition();
assertEquals(Collections.singleton(MediaType.APPLICATION_XML), condition.getConsumableMediaTypes());
}
@Test // gh-22010
public void consumesWithOptionalRequestBody() {
this.wac.registerSingleton("testController", ComposedAnnotationController.class);
this.wac.refresh();
this.handlerMapping.afterPropertiesSet();
RequestMappingInfo info = this.handlerMapping.getHandlerMethods().keySet().stream()
.filter(i -> {
PatternsRequestCondition condition = i.getPatternsCondition();
return condition.getPatterns().iterator().next().getPatternString().equals("/post");
})
.findFirst()
.orElseThrow(() -> new AssertionError("No /post"));
assertFalse(info.getConsumesCondition().isBodyRequired());
}
private RequestMappingInfo withPrefix(RequestMappingInfo mapping) {
if (!StringUtils.hasText(adminContextPath)) {
return mapping;
}
PatternsRequestCondition patternsCondition = new PatternsRequestCondition(
withNewPatterns(mapping.getPatternsCondition().getPatterns()));
return new RequestMappingInfo(patternsCondition, mapping.getMethodsCondition(), mapping.getParamsCondition(),
mapping.getHeadersCondition(), mapping.getConsumesCondition(), mapping.getProducesCondition(),
mapping.getCustomCondition());
}