Add a response post processor that performs generic pattern replacement

This commit introduces a new ResponsePostProcessor,
PatternReplacingResponsePostProcessor, that modifies the content of the
response by replacing occurrences of a regular expression with a
configurable replacement. The existing LinkMaskingResponsePostProcessor,
which was already performing pattern replacement, has been updated to
subclass PatternReplacingResponsePostProcessor.

Closes gh-65
This commit is contained in:
Dewet Diener
2015-04-30 16:34:31 +01:00
committed by Andy Wilkinson
parent ca375c919c
commit 84fe379f64
5 changed files with 137 additions and 24 deletions

View File

@@ -16,40 +16,28 @@
package org.springframework.restdocs.response;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class LinkMaskingResponsePostProcessor extends ContentModifyingReponsePostProcessor {
/**
* A {@link ResponsePostProcessor} that modifies the content of a hypermedia response to
* mask the hrefs of any links.
*
* @author Andy Wilkinson
* @author Dewet Diener
*/
class LinkMaskingResponsePostProcessor extends PatternReplacingResponsePostProcessor {
private static final String DEFAULT_MASK = "...";
private static final Pattern LINK_HREF = Pattern.compile(
"\"href\"\\s*:\\s*\"(.*?)\"", Pattern.DOTALL);
private final String mask;
LinkMaskingResponsePostProcessor() {
this(DEFAULT_MASK);
super(LINK_HREF, DEFAULT_MASK);
}
LinkMaskingResponsePostProcessor(String mask) {
this.mask = mask;
}
@Override
protected String modifyContent(String originalContent) {
Matcher matcher = LINK_HREF.matcher(originalContent);
StringBuilder buffer = new StringBuilder();
int previous = 0;
while (matcher.find()) {
buffer.append(originalContent.substring(previous, matcher.start(1)));
buffer.append(this.mask);
previous = matcher.end(1);
}
if (previous < originalContent.length()) {
buffer.append(originalContent.substring(previous));
}
return buffer.toString();
super(LINK_HREF, mask);
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A {@link ResponsePostProcessor} that modifies the content of the response by replacing
* occurrences of a regular expression {@link Pattern}.
*
* @author Andy Wilkinson
* @author Dewet Diener
*/
class PatternReplacingResponsePostProcessor extends ContentModifyingReponsePostProcessor {
private final Pattern pattern;
private final String replacement;
PatternReplacingResponsePostProcessor(Pattern pattern, String replacement) {
this.pattern = pattern;
this.replacement = replacement;
}
@Override
protected String modifyContent(String originalContent) {
Matcher matcher = this.pattern.matcher(originalContent);
StringBuilder buffer = new StringBuilder();
int previous = 0;
while (matcher.find()) {
buffer.append(originalContent.substring(previous, matcher.start(1)));
buffer.append(this.replacement);
previous = matcher.end(1);
}
if (previous < originalContent.length()) {
buffer.append(originalContent.substring(previous));
}
return buffer.toString();
}
}

View File

@@ -16,11 +16,14 @@
package org.springframework.restdocs.response;
import java.util.regex.Pattern;
/**
* Static factory methods for accessing various {@link ResponsePostProcessor
* ResponsePostProcessors}.
*
* @author Andy Wilkinson
* @author Dewet Diener
*/
public abstract class ResponsePostProcessors {
@@ -71,4 +74,18 @@ public abstract class ResponsePostProcessors {
public static ResponsePostProcessor maskLinksWith(String mask) {
return new LinkMaskingResponsePostProcessor(mask);
}
/**
* Returns a {@link ResponsePostProcessor} that will update the content of the
* response by replacing any occurrences of the given {@code pattern} with the given
* {@code replacement}.
*
* @param pattern the pattern to match
* @param replacement the replacement to apply
* @return the response post-processor
*/
public static ResponsePostProcessor replacePattern(Pattern pattern, String replacement) {
return new PatternReplacingResponsePostProcessor(pattern, replacement);
}
}

View File

@@ -24,6 +24,7 @@ import static org.springframework.restdocs.RestDocumentation.modifyResponseTo;
import static org.springframework.restdocs.response.ResponsePostProcessors.maskLinks;
import static org.springframework.restdocs.response.ResponsePostProcessors.prettyPrintContent;
import static org.springframework.restdocs.response.ResponsePostProcessors.removeHeaders;
import static org.springframework.restdocs.response.ResponsePostProcessors.replacePattern;
import static org.springframework.restdocs.test.SnippetMatchers.httpResponse;
import static org.springframework.restdocs.test.SnippetMatchers.snippet;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -33,6 +34,7 @@ import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.junit.After;
import org.junit.Before;
@@ -64,6 +66,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* Integration tests for Spring REST Docs
*
* @author Andy Wilkinson
* @author Dewet Diener
*/
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@@ -155,17 +158,19 @@ public class RestDocumentationIntegrationTests {
"{\"a\":\"alpha\",\"links\":[{\"rel\":\"rel\","
+ "\"href\":\"href\"}]}"))));
Pattern pattern = Pattern.compile("(\"alpha\")");
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(modifyResponseTo(prettyPrintContent(), removeHeaders("a"),
maskLinks()).andDocument("post-processed"));
replacePattern(pattern, "\"<<beta>>\""), maskLinks())
.andDocument("post-processed"));
assertThat(
new File("build/generated-snippets/post-processed/http-response.adoc"),
is(snippet().withContents(
httpResponse(HttpStatus.OK).header("Content-Type",
"application/json").content(
String.format("{%n \"a\" : \"alpha\",%n \"links\" :"
String.format("{%n \"a\" : \"<<beta>>\",%n \"links\" :"
+ " [ {%n \"rel\" : \"rel\",%n \"href\" :"
+ " \"...\"%n } ]%n}")))));
}

View File

@@ -0,0 +1,47 @@
/*
* 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 static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.util.regex.Pattern;
import org.junit.Test;
/**
* Tests for {@link PatternReplacingResponsePostProcessor}.
*
* @author Dewet Diener
*/
public class PatternReplacingResponsePostProcessorTests {
@Test
public void patternsAreReplaced() throws Exception {
Pattern pattern = Pattern.compile(
"([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})",
Pattern.CASE_INSENSITIVE);
PatternReplacingResponsePostProcessor postProcessor = new PatternReplacingResponsePostProcessor(
pattern, "<<uuid>>");
assertThat(
postProcessor
.modifyContent("{\"id\" : \"CA761232-ED42-11CE-BACD-00AA0057B223\"}"),
is(equalTo("{\"id\" : \"<<uuid>>\"}")));
}
}