-
Notifications
You must be signed in to change notification settings - Fork 733
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for post-processing a response before it is documented
This commit adds support for post-processing a response before it is documented. Post-processors are provided to pretty-print JSON and XML responses, remove headers from the response, and mask the hrefs of Atom- and HAL-formatted links in JSON responses. Response post-processing is configured prior to configuring the documentation. For example, mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andDo(modifyResponseTo(prettyPrintContent(), removeHeaders("a"), maskLinks()).andDocument("post-processed")); Closes gh-61 Closes gh-31 Closes gh-54
- Loading branch information
1 parent
b3eee08
commit e5f35c9
Showing
19 changed files
with
1,196 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
spring-restdocs/src/main/java/org/springframework/restdocs/ResponseModifier.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
* Copyright 2014-2015 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.restdocs; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import org.springframework.cglib.proxy.Enhancer; | ||
import org.springframework.cglib.proxy.MethodInterceptor; | ||
import org.springframework.cglib.proxy.MethodProxy; | ||
import org.springframework.core.BridgeMethodResolver; | ||
import org.springframework.mock.web.MockHttpServletResponse; | ||
import org.springframework.restdocs.response.ResponsePostProcessor; | ||
import org.springframework.test.web.servlet.MvcResult; | ||
import org.springframework.util.ReflectionUtils; | ||
|
||
/** | ||
* Modifies the response in an {@link MvcResult} by applying {@link ResponsePostProcessor | ||
* ResponsePostProcessors} to it. | ||
* | ||
* @see RestDocumentation#modifyResponseTo(ResponsePostProcessor...) | ||
* @author Andy Wilkinson | ||
*/ | ||
public class ResponseModifier { | ||
|
||
private final List<ResponsePostProcessor> postProcessors; | ||
|
||
ResponseModifier(ResponsePostProcessor... postProcessors) { | ||
this.postProcessors = Arrays.asList(postProcessors); | ||
} | ||
|
||
/** | ||
* Provides a {@link RestDocumentationResultHandler} that can be used to document the | ||
* request and modified result. | ||
* @param outputDir The directory to which the documentation will be written | ||
* @return the result handler that will produce the documentation | ||
*/ | ||
public RestDocumentationResultHandler andDocument(String outputDir) { | ||
return new ResponseModifyingRestDocumentationResultHandler(outputDir); | ||
} | ||
|
||
class ResponseModifyingRestDocumentationResultHandler extends | ||
RestDocumentationResultHandler { | ||
|
||
public ResponseModifyingRestDocumentationResultHandler(String outputDir) { | ||
super(outputDir); | ||
} | ||
|
||
@Override | ||
public void handle(MvcResult result) throws Exception { | ||
super.handle(postProcessResponse(result)); | ||
} | ||
|
||
MvcResult postProcessResponse(MvcResult result) throws Exception { | ||
MockHttpServletResponse response = result.getResponse(); | ||
for (ResponsePostProcessor postProcessor : ResponseModifier.this.postProcessors) { | ||
response = postProcessor.postProcess(response); | ||
} | ||
return decorateResult(result, response); | ||
} | ||
|
||
private MvcResult decorateResult(MvcResult result, | ||
MockHttpServletResponse response) { | ||
Enhancer enhancer = new Enhancer(); | ||
enhancer.setSuperclass(MvcResult.class); | ||
enhancer.setCallback(new GetResponseMethodInterceptor(response, result)); | ||
return (MvcResult) enhancer.create(); | ||
} | ||
|
||
private class GetResponseMethodInterceptor implements MethodInterceptor { | ||
|
||
private final MvcResult delegate; | ||
|
||
private final MockHttpServletResponse response; | ||
|
||
private final Method getResponseMethod = findMethod("getResponse"); | ||
|
||
private GetResponseMethodInterceptor(MockHttpServletResponse response, | ||
MvcResult delegate) { | ||
this.delegate = delegate; | ||
this.response = response; | ||
} | ||
|
||
@Override | ||
public Object intercept(Object proxy, Method method, Object[] args, | ||
MethodProxy methodProxy) throws Throwable { | ||
if (this.getResponseMethod.equals(method)) { | ||
return this.response; | ||
} | ||
return method.invoke(this.delegate, args); | ||
} | ||
|
||
private Method findMethod(String methodName) { | ||
return BridgeMethodResolver.findBridgedMethod(ReflectionUtils.findMethod( | ||
MvcResult.class, methodName)); | ||
} | ||
|
||
} | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
...main/java/org/springframework/restdocs/response/ContentModifyingReponsePostProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* | ||
* Copyright 2014-2015 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.restdocs.response; | ||
|
||
import java.lang.reflect.Method; | ||
|
||
import org.springframework.cglib.proxy.Enhancer; | ||
import org.springframework.cglib.proxy.MethodInterceptor; | ||
import org.springframework.cglib.proxy.MethodProxy; | ||
import org.springframework.core.BridgeMethodResolver; | ||
import org.springframework.mock.web.MockHttpServletResponse; | ||
import org.springframework.util.ReflectionUtils; | ||
|
||
/** | ||
* A base class for {@link ResponsePostProcessor ResponsePostProcessors} that modify the | ||
* content of the response. | ||
* | ||
* @author Andy Wilkinson | ||
*/ | ||
public abstract class ContentModifyingReponsePostProcessor implements | ||
ResponsePostProcessor { | ||
|
||
@Override | ||
public MockHttpServletResponse postProcess(MockHttpServletResponse response) | ||
throws Exception { | ||
String modifiedContent = modifyContent(response.getContentAsString()); | ||
|
||
Enhancer enhancer = new Enhancer(); | ||
enhancer.setSuperclass(MockHttpServletResponse.class); | ||
enhancer.setCallback(new ContentModifyingMethodInterceptor(modifiedContent, | ||
response)); | ||
|
||
return (MockHttpServletResponse) enhancer.create(); | ||
} | ||
|
||
/** | ||
* Returns a modified version of the given {@code originalContent} | ||
* | ||
* @param originalContent the content to modify | ||
* @return the modified content | ||
* @throws Exception if a failure occurs while modifying the content | ||
*/ | ||
protected abstract String modifyContent(String originalContent) throws Exception; | ||
|
||
private static class ContentModifyingMethodInterceptor implements MethodInterceptor { | ||
|
||
private final Method getContentAsStringMethod = findMethod("getContentAsString"); | ||
|
||
private final Method getContentAsByteArray = findMethod("getContentAsByteArray"); | ||
|
||
private final String modifiedContent; | ||
|
||
private final MockHttpServletResponse delegate; | ||
|
||
public ContentModifyingMethodInterceptor(String modifiedContent, | ||
MockHttpServletResponse delegate) { | ||
this.modifiedContent = modifiedContent; | ||
this.delegate = delegate; | ||
} | ||
|
||
@Override | ||
public Object intercept(Object proxy, Method method, Object[] args, | ||
MethodProxy methodProxy) throws Throwable { | ||
if (this.getContentAsStringMethod.equals(method)) { | ||
return this.modifiedContent; | ||
} | ||
if (this.getContentAsByteArray.equals(method)) { | ||
throw new UnsupportedOperationException( | ||
"Following modification, the response's content should be" | ||
+ " accessed as a String"); | ||
} | ||
return method.invoke(this.delegate, args); | ||
} | ||
|
||
private static Method findMethod(String methodName) { | ||
return BridgeMethodResolver.findBridgedMethod(ReflectionUtils.findMethod( | ||
MockHttpServletResponse.class, methodName)); | ||
} | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.