Skip to content

Commit

Permalink
Use getUriTemplate of MockHttpServletRequest
Browse files Browse the repository at this point in the history
Fixes gh-939
  • Loading branch information
wilkinsona committed Sep 13, 2024
1 parent 4315acf commit 272ed24
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/src/docs/asciidoc/documenting-your-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ Uses the static `parameterWithName` method on `org.springframework.restdocs.requ

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

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`.
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`.

When documenting path parameters, the test fails if an undocumented path parameter is used in the request.
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.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,8 +16,10 @@

package org.springframework.restdocs.mockmvc;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.restdocs.RestDocumentationContext;
Expand All @@ -27,6 +29,7 @@
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.context.WebApplicationContext;

/**
Expand Down Expand Up @@ -85,6 +88,26 @@ public MockMvcOperationPreprocessorsConfigurer operationPreprocessors() {

private final class ConfigurerApplyingRequestPostProcessor implements RequestPostProcessor {

private static final Function<MockHttpServletRequest, String> urlTemplateExtractor;

static {
Function<MockHttpServletRequest, String> fromRequestAttribute = (
request) -> (String) request.getAttribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE);
Function<MockHttpServletRequest, String> extractor;
try {
Method accessorMethod = MockHttpServletRequest.class.getMethod("getUriTemplate");
extractor = (request) -> {
String urlTemplate = fromRequestAttribute.apply(request);
return (urlTemplate != null) ? urlTemplate
: (String) ReflectionUtils.invokeMethod(accessorMethod, request);
};
}
catch (Exception ex) {
extractor = fromRequestAttribute;
}
urlTemplateExtractor = extractor;
}

private final RestDocumentationContextProvider contextManager;

private ConfigurerApplyingRequestPostProcessor(RestDocumentationContextProvider contextManager) {
Expand All @@ -97,7 +120,7 @@ public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request)
Map<String, Object> configuration = new HashMap<>();
configuration.put(MockHttpServletRequest.class.getName(), request);
configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE,
request.getAttribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE));
urlTemplateExtractor.apply(request));
configuration.put(RestDocumentationContext.class.getName(), context);
request.setAttribute(RestDocumentationResultHandler.ATTRIBUTE_NAME_CONFIGURATION, configuration);
MockMvcRestDocumentationConfigurer.this.apply(configuration, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,18 @@

package org.springframework.restdocs.mockmvc;

import java.lang.reflect.Method;
import java.util.Map;

import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;

import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.generate.RestDocumentationGenerator;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
Expand Down Expand Up @@ -86,6 +92,33 @@ public void noContentLengthHeaderWhenRequestHasNotContent() {
assertThat(this.request.getHeader("Content-Length")).isNull();
}

@Test
@SuppressWarnings("unchecked")
public void uriTemplateFromRequestAttribute() {
RequestPostProcessor postProcessor = new MockMvcRestDocumentationConfigurer(this.restDocumentation)
.beforeMockMvcCreated(null, null);
this.request.setAttribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "{a}/{b}");
postProcessor.postProcessRequest(this.request);
Map<String, Object> configuration = (Map<String, Object>) this.request
.getAttribute(RestDocumentationResultHandler.ATTRIBUTE_NAME_CONFIGURATION);
assertThat(configuration).containsEntry(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "{a}/{b}");
}

@Test
@SuppressWarnings("unchecked")
public void uriTemplateFromRequest() {
Method setUriTemplate = ReflectionUtils.findMethod(MockHttpServletRequest.class, "setUriTemplate",
String.class);
Assume.assumeNotNull(setUriTemplate);
RequestPostProcessor postProcessor = new MockMvcRestDocumentationConfigurer(this.restDocumentation)
.beforeMockMvcCreated(null, null);
ReflectionUtils.invokeMethod(setUriTemplate, this.request, "{a}/{b}");
postProcessor.postProcessRequest(this.request);
Map<String, Object> configuration = (Map<String, Object>) this.request
.getAttribute(RestDocumentationResultHandler.ATTRIBUTE_NAME_CONFIGURATION);
assertThat(configuration).containsEntry(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "{a}/{b}");
}

private void assertUriConfiguration(String scheme, String host, int port) {
assertThat(scheme).isEqualTo(this.request.getScheme());
assertThat(host).isEqualTo(this.request.getServerName());
Expand Down

0 comments on commit 272ed24

Please sign in to comment.