From 84fe379f64bd1e479d70275a89c55a6eec7f2e83 Mon Sep 17 00:00:00 2001 From: Dewet Diener Date: Thu, 30 Apr 2015 16:34:31 +0100 Subject: [PATCH] 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 --- .../LinkMaskingResponsePostProcessor.java | 32 ++++------- ...PatternReplacingResponsePostProcessor.java | 56 +++++++++++++++++++ .../response/ResponsePostProcessors.java | 17 ++++++ .../RestDocumentationIntegrationTests.java | 9 ++- ...rnReplacingResponsePostProcessorTests.java | 47 ++++++++++++++++ 5 files changed, 137 insertions(+), 24 deletions(-) create mode 100644 spring-restdocs/src/main/java/org/springframework/restdocs/response/PatternReplacingResponsePostProcessor.java create mode 100644 spring-restdocs/src/test/java/org/springframework/restdocs/response/PatternReplacingResponsePostProcessorTests.java diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/response/LinkMaskingResponsePostProcessor.java b/spring-restdocs/src/main/java/org/springframework/restdocs/response/LinkMaskingResponsePostProcessor.java index 6ad58e4c..8396b163 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/response/LinkMaskingResponsePostProcessor.java +++ b/spring-restdocs/src/main/java/org/springframework/restdocs/response/LinkMaskingResponsePostProcessor.java @@ -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); } } diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/response/PatternReplacingResponsePostProcessor.java b/spring-restdocs/src/main/java/org/springframework/restdocs/response/PatternReplacingResponsePostProcessor.java new file mode 100644 index 00000000..ce640341 --- /dev/null +++ b/spring-restdocs/src/main/java/org/springframework/restdocs/response/PatternReplacingResponsePostProcessor.java @@ -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(); + } + +} diff --git a/spring-restdocs/src/main/java/org/springframework/restdocs/response/ResponsePostProcessors.java b/spring-restdocs/src/main/java/org/springframework/restdocs/response/ResponsePostProcessors.java index b04128a9..6c1f2295 100644 --- a/spring-restdocs/src/main/java/org/springframework/restdocs/response/ResponsePostProcessors.java +++ b/spring-restdocs/src/main/java/org/springframework/restdocs/response/ResponsePostProcessors.java @@ -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); + } + } diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/RestDocumentationIntegrationTests.java b/spring-restdocs/src/test/java/org/springframework/restdocs/RestDocumentationIntegrationTests.java index 646623b3..a7dc2b94 100644 --- a/spring-restdocs/src/test/java/org/springframework/restdocs/RestDocumentationIntegrationTests.java +++ b/spring-restdocs/src/test/java/org/springframework/restdocs/RestDocumentationIntegrationTests.java @@ -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, "\"<>\""), 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\" : \"<>\",%n \"links\" :" + " [ {%n \"rel\" : \"rel\",%n \"href\" :" + " \"...\"%n } ]%n}"))))); } diff --git a/spring-restdocs/src/test/java/org/springframework/restdocs/response/PatternReplacingResponsePostProcessorTests.java b/spring-restdocs/src/test/java/org/springframework/restdocs/response/PatternReplacingResponsePostProcessorTests.java new file mode 100644 index 00000000..1074ea35 --- /dev/null +++ b/spring-restdocs/src/test/java/org/springframework/restdocs/response/PatternReplacingResponsePostProcessorTests.java @@ -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, "<>"); + assertThat( + postProcessor + .modifyContent("{\"id\" : \"CA761232-ED42-11CE-BACD-00AA0057B223\"}"), + is(equalTo("{\"id\" : \"<>\"}"))); + } + +}