Skip to content

Commit 272ed24

Browse files
committed
Use getUriTemplate of MockHttpServletRequest
Fixes gh-939
1 parent 4315acf commit 272ed24

File tree

3 files changed

+59
-3
lines changed

3 files changed

+59
-3
lines changed

Diff for: docs/src/docs/asciidoc/documenting-your-api.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,7 @@ Uses the static `parameterWithName` method on `org.springframework.restdocs.requ
802802

803803
The result is a snippet named `path-parameters.adoc` that contains a table describing the path parameters that are supported by the resource.
804804

805-
TIP: If you use MockMvc, to make the path parameters available for documentation, you must build the request by using one of the methods on `RestDocumentationRequestBuilders` rather than `MockMvcRequestBuilders`.
805+
TIP: If you use MockMvc with Spring Framework 6.1 or earlier, to make the path parameters available for documentation, you must build the request by using one of the methods on `RestDocumentationRequestBuilders` rather than `MockMvcRequestBuilders`.
806806

807807
When documenting path parameters, the test fails if an undocumented path parameter is used in the request.
808808
Similarly, the test also fails if a documented path parameter is not found in the request and the path parameter has not been marked as optional.

Diff for: spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationConfigurer.java

+25-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2019 the original author or authors.
2+
* Copyright 2014-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,8 +16,10 @@
1616

1717
package org.springframework.restdocs.mockmvc;
1818

19+
import java.lang.reflect.Method;
1920
import java.util.HashMap;
2021
import java.util.Map;
22+
import java.util.function.Function;
2123

2224
import org.springframework.mock.web.MockHttpServletRequest;
2325
import org.springframework.restdocs.RestDocumentationContext;
@@ -27,6 +29,7 @@
2729
import org.springframework.test.web.servlet.request.RequestPostProcessor;
2830
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
2931
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
32+
import org.springframework.util.ReflectionUtils;
3033
import org.springframework.web.context.WebApplicationContext;
3134

3235
/**
@@ -85,6 +88,26 @@ public MockMvcOperationPreprocessorsConfigurer operationPreprocessors() {
8588

8689
private final class ConfigurerApplyingRequestPostProcessor implements RequestPostProcessor {
8790

91+
private static final Function<MockHttpServletRequest, String> urlTemplateExtractor;
92+
93+
static {
94+
Function<MockHttpServletRequest, String> fromRequestAttribute = (
95+
request) -> (String) request.getAttribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE);
96+
Function<MockHttpServletRequest, String> extractor;
97+
try {
98+
Method accessorMethod = MockHttpServletRequest.class.getMethod("getUriTemplate");
99+
extractor = (request) -> {
100+
String urlTemplate = fromRequestAttribute.apply(request);
101+
return (urlTemplate != null) ? urlTemplate
102+
: (String) ReflectionUtils.invokeMethod(accessorMethod, request);
103+
};
104+
}
105+
catch (Exception ex) {
106+
extractor = fromRequestAttribute;
107+
}
108+
urlTemplateExtractor = extractor;
109+
}
110+
88111
private final RestDocumentationContextProvider contextManager;
89112

90113
private ConfigurerApplyingRequestPostProcessor(RestDocumentationContextProvider contextManager) {
@@ -97,7 +120,7 @@ public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request)
97120
Map<String, Object> configuration = new HashMap<>();
98121
configuration.put(MockHttpServletRequest.class.getName(), request);
99122
configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE,
100-
request.getAttribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE));
123+
urlTemplateExtractor.apply(request));
101124
configuration.put(RestDocumentationContext.class.getName(), context);
102125
request.setAttribute(RestDocumentationResultHandler.ATTRIBUTE_NAME_CONFIGURATION, configuration);
103126
MockMvcRestDocumentationConfigurer.this.apply(configuration, context);

Diff for: spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationConfigurerTests.java

+33
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,18 @@
1616

1717
package org.springframework.restdocs.mockmvc;
1818

19+
import java.lang.reflect.Method;
20+
import java.util.Map;
21+
22+
import org.junit.Assume;
1923
import org.junit.Rule;
2024
import org.junit.Test;
2125

2226
import org.springframework.mock.web.MockHttpServletRequest;
2327
import org.springframework.restdocs.JUnitRestDocumentation;
28+
import org.springframework.restdocs.generate.RestDocumentationGenerator;
2429
import org.springframework.test.web.servlet.request.RequestPostProcessor;
30+
import org.springframework.util.ReflectionUtils;
2531
import org.springframework.web.context.request.RequestContextHolder;
2632
import org.springframework.web.context.request.ServletRequestAttributes;
2733
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
@@ -86,6 +92,33 @@ public void noContentLengthHeaderWhenRequestHasNotContent() {
8692
assertThat(this.request.getHeader("Content-Length")).isNull();
8793
}
8894

95+
@Test
96+
@SuppressWarnings("unchecked")
97+
public void uriTemplateFromRequestAttribute() {
98+
RequestPostProcessor postProcessor = new MockMvcRestDocumentationConfigurer(this.restDocumentation)
99+
.beforeMockMvcCreated(null, null);
100+
this.request.setAttribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "{a}/{b}");
101+
postProcessor.postProcessRequest(this.request);
102+
Map<String, Object> configuration = (Map<String, Object>) this.request
103+
.getAttribute(RestDocumentationResultHandler.ATTRIBUTE_NAME_CONFIGURATION);
104+
assertThat(configuration).containsEntry(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "{a}/{b}");
105+
}
106+
107+
@Test
108+
@SuppressWarnings("unchecked")
109+
public void uriTemplateFromRequest() {
110+
Method setUriTemplate = ReflectionUtils.findMethod(MockHttpServletRequest.class, "setUriTemplate",
111+
String.class);
112+
Assume.assumeNotNull(setUriTemplate);
113+
RequestPostProcessor postProcessor = new MockMvcRestDocumentationConfigurer(this.restDocumentation)
114+
.beforeMockMvcCreated(null, null);
115+
ReflectionUtils.invokeMethod(setUriTemplate, this.request, "{a}/{b}");
116+
postProcessor.postProcessRequest(this.request);
117+
Map<String, Object> configuration = (Map<String, Object>) this.request
118+
.getAttribute(RestDocumentationResultHandler.ATTRIBUTE_NAME_CONFIGURATION);
119+
assertThat(configuration).containsEntry(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "{a}/{b}");
120+
}
121+
89122
private void assertUriConfiguration(String scheme, String host, int port) {
90123
assertThat(scheme).isEqualTo(this.request.getScheme());
91124
assertThat(host).isEqualTo(this.request.getServerName());

0 commit comments

Comments
 (0)