diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentationException.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentationException.java new file mode 100644 index 00000000..5bdf27c1 --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentationException.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2016 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; + +/** + * An exception that can be thrown when a failure occurs during REST documentation + * generation. + * + * @author Andy Wilkinson + */ +public class RestDocumentationException extends RuntimeException { + + /** + * Creates a new {@code RestDocumentationException} with the given {@code cause}. + * + * @param cause the cause + */ + public RestDocumentationException(Throwable cause) { + super(cause); + } + + /** + * Creates a new {@code RestDocumentationException} with the given {@code message} and + * {@code cause}. + * + * @param message the message + * @param cause the cause + */ + public RestDocumentationException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentationHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentationHandler.java new file mode 100644 index 00000000..f8be483b --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/RestDocumentationHandler.java @@ -0,0 +1,232 @@ +/* + * Copyright 2012-2016 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.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.restdocs.config.SnippetConfigurer; +import org.springframework.restdocs.operation.Operation; +import org.springframework.restdocs.operation.OperationRequest; +import org.springframework.restdocs.operation.OperationResponse; +import org.springframework.restdocs.operation.RequestConverter; +import org.springframework.restdocs.operation.ResponseConverter; +import org.springframework.restdocs.operation.StandardOperation; +import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; +import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; +import org.springframework.restdocs.snippet.Snippet; +import org.springframework.util.Assert; + +/** + * A {@code RestDocumentationHandler} is used to produce documentation snippets from the + * request and response of an operation performed on a service. + * + * @param the request type that can be handled + * @param the response type that can be handled + * @author Andy Wilkinson + */ +public final class RestDocumentationHandler { + + private final String identifier; + + private final OperationRequestPreprocessor requestPreprocessor; + + private final OperationResponsePreprocessor responsePreprocessor; + + private final List snippets; + + private final RequestConverter requestConverter; + + private final ResponseConverter responseConverter; + + /** + * Creates a new {@code RestDocumentationHandler} for the operation identified by the + * given {@code identifier}. The given {@code requestConverter} and + * {@code responseConverter} are used to convert the operation's request and response + * into generic {@code OperationRequest} and {@code OperationResponse} instances that + * can then be documented. The given documentation {@code snippets} will be produced. + * + * @param identifier the identifier for the operation + * @param requestConverter the request converter + * @param responseConverter the response converter + * @param snippets the snippets + */ + public RestDocumentationHandler(String identifier, + RequestConverter requestConverter, + ResponseConverter responseConverter, Snippet... snippets) { + this(identifier, requestConverter, responseConverter, + new IdentityOperationRequestPreprocessor(), + new IdentityOperationResponsePreprocessor(), snippets); + } + + /** + * Creates a new {@code RestDocumentationHandler} for the operation identified by the + * given {@code identifier}. The given {@code requestConverter} and + * {@code responseConverter} are used to convert the operation's request and response + * into generic {@code OperationRequest} and {@code OperationResponse} instances that + * can then be documented. The given {@code requestPreprocessor} is applied to the + * request before it is documented. The given documentation {@code snippets} will be + * produced. + * + * @param identifier the identifier for the operation + * @param requestConverter the request converter + * @param responseConverter the response converter + * @param requestPreprocessor the request preprocessor + * @param snippets the snippets + */ + public RestDocumentationHandler(String identifier, + RequestConverter requestConverter, + ResponseConverter responseConverter, + OperationRequestPreprocessor requestPreprocessor, Snippet... snippets) { + this(identifier, requestConverter, responseConverter, requestPreprocessor, + new IdentityOperationResponsePreprocessor(), snippets); + } + + /** + * Creates a new {@code RestDocumentationHandler} for the operation identified by the + * given {@code identifier}. The given {@code requestConverter} and + * {@code responseConverter} are used to convert the operation's request and response + * into generic {@code OperationRequest} and {@code OperationResponse} instances that + * can then be documented. The given {@code responsePreprocessor} is applied to the + * response before it is documented. The given documentation {@code snippets} will be + * produced. + * + * @param identifier the identifier for the operation + * @param requestConverter the request converter + * @param responseConverter the response converter + * @param responsePreprocessor the response preprocessor + * @param snippets the snippets + */ + public RestDocumentationHandler(String identifier, + RequestConverter requestConverter, + ResponseConverter responseConverter, + OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) { + this(identifier, requestConverter, responseConverter, + new IdentityOperationRequestPreprocessor(), responsePreprocessor, + snippets); + } + + /** + * Creates a new {@code RestDocumentationHandler} for the operation identified by the + * given {@code identifier}. The given {@code requestConverter} and + * {@code responseConverter} are used to convert the operation's request and response + * into generic {@code OperationRequest} and {@code OperationResponse} instances that + * can then be documented. The given {@code requestPreprocessor} and + * {@code responsePreprocessor} are applied to the request and response before they + * are documented. The given documentation {@code snippets} will be produced. + * + * @param identifier the identifier for the operation + * @param requestConverter the request converter + * @param responseConverter the response converter + * @param requestPreprocessor the request preprocessor + * @param responsePreprocessor the response preprocessor + * @param snippets the snippets + */ + public RestDocumentationHandler(String identifier, + RequestConverter requestConverter, + ResponseConverter responseConverter, + OperationRequestPreprocessor requestPreprocessor, + OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) { + Assert.notNull(identifier, "identifier must be non-null"); + Assert.notNull(requestConverter, "requestConverter must be non-null"); + Assert.notNull(responseConverter, "responseConverter must be non-null"); + Assert.notNull(identifier, "identifier must be non-null"); + Assert.notNull(requestPreprocessor, "requestPreprocessor must be non-null"); + Assert.notNull(responsePreprocessor, "responsePreprocessor must be non-null"); + Assert.notNull(snippets, "snippets must be non-null"); + this.identifier = identifier; + this.requestConverter = requestConverter; + this.responseConverter = responseConverter; + this.requestPreprocessor = requestPreprocessor; + this.responsePreprocessor = responsePreprocessor; + this.snippets = new ArrayList<>(Arrays.asList(snippets)); + } + + /** + * Handles the given {@code request} and {@code response}, producing documentation + * snippets for them using the given {@code configuration}. + * + * @param request the request + * @param response the request + * @param configuration the configuration + * @throws RestDocumentationException if a failure occurs during handling + */ + public void handle(REQ request, RESP response, Map configuration) { + OperationRequest operationRequest = this.requestPreprocessor + .preprocess(this.requestConverter.convert(request)); + + OperationResponse operationResponse = this.responsePreprocessor + .preprocess(this.responseConverter.convert(response)); + Map attributes = new HashMap<>(configuration); + Operation operation = new StandardOperation(this.identifier, operationRequest, + operationResponse, attributes); + try { + for (Snippet snippet : getSnippets(attributes)) { + snippet.document(operation); + } + } + catch (IOException ex) { + throw new RestDocumentationException(ex); + } + } + + /** + * Adds the given {@code snippets} such that they are documented when this handler is + * called. + * + * @param snippets the snippets to add + */ + public void addSnippets(Snippet... snippets) { + this.snippets.addAll(Arrays.asList(snippets)); + } + + @SuppressWarnings("unchecked") + private List getSnippets(Map configuration) { + List combinedSnippets = new ArrayList<>(this.snippets); + List defaultSnippets = (List) configuration + .get(SnippetConfigurer.ATTRIBUTE_DEFAULT_SNIPPETS); + if (defaultSnippets != null) { + combinedSnippets.addAll(defaultSnippets); + } + return combinedSnippets; + } + + private static final class IdentityOperationRequestPreprocessor implements + OperationRequestPreprocessor { + + @Override + public OperationRequest preprocess(OperationRequest request) { + return request; + } + + } + + private static final class IdentityOperationResponsePreprocessor implements + OperationResponsePreprocessor { + + @Override + public OperationResponse preprocess(OperationResponse response) { + return response; + } + + } + +} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/ConversionException.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/ConversionException.java new file mode 100644 index 00000000..397f79d9 --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/ConversionException.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2016 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.operation; + +/** + * An exception that can be thrown by {@link RequestConverter} and + * {@link ResponseConverter} implementations to indicate that a failure has occurred + * during conversion. + * + * @author Andy Wilkinson + * @see RequestConverter#convert(Object) + * @see ResponseConverter#convert(Object) + */ +public class ConversionException extends RuntimeException { + + /** + * Creates a new {@code ConversionException} with the given {@code cause}. + * + * @param cause the cause + */ + public ConversionException(Throwable cause) { + super(cause); + } + + /** + * Creates a new {@code ConversionException} with the given {@code message} and + * {@code cause}. + * + * @param message the message + * @param cause the cause + */ + public ConversionException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/RequestConverter.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/RequestConverter.java new file mode 100644 index 00000000..5c2377d5 --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/RequestConverter.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2016 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.operation; + +/** + * A {@code RequestConverter} is used to convert an implementation-specific request into + * an {@link OperationRequest}. + * + * @param The implementation-specific request type + * @author Andy Wilkinson + */ +public interface RequestConverter { + + /** + * Converts the given {@code request} into an {@code OperationRequest}. + * + * @param request the request + * @return the operation request + * @throws ConversionException if the conversion fails + */ + OperationRequest convert(R request); + +} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/ResponseConverter.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/ResponseConverter.java new file mode 100644 index 00000000..48a76be2 --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/operation/ResponseConverter.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2016 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.operation; + +/** + * A {@code ResponseConverter} is used to convert an implementation-specific response into + * an {@link OperationResponse}. + * + * @param The implementation-specific response type + * @author Andy Wilkinson + */ +public interface ResponseConverter { + + /** + * Converts the given {@code response} into an {@code OperationResponse}. + * + * @param response the response + * @return the operation response + * @throws ConversionException if the conversion fails + */ + OperationResponse convert(R response); + +} diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/RestDocumentationHandlerTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/RestDocumentationHandlerTests.java new file mode 100644 index 00000000..abfdafa5 --- /dev/null +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/RestDocumentationHandlerTests.java @@ -0,0 +1,130 @@ +/* + * Copyright 2012-2016 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.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.springframework.http.HttpHeaders; +import org.springframework.restdocs.config.SnippetConfigurer; +import org.springframework.restdocs.operation.Operation; +import org.springframework.restdocs.operation.OperationRequest; +import org.springframework.restdocs.operation.OperationRequestFactory; +import org.springframework.restdocs.operation.OperationResponse; +import org.springframework.restdocs.operation.OperationResponseFactory; +import org.springframework.restdocs.operation.RequestConverter; +import org.springframework.restdocs.operation.ResponseConverter; +import org.springframework.restdocs.snippet.Snippet; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link RestDocumentationHandler}. + * + * @author Andy Wilkinson + */ +public class RestDocumentationHandlerTests { + + @SuppressWarnings("unchecked") + private final RequestConverter requestConverter = mock(RequestConverter.class); + + @SuppressWarnings("unchecked") + private final ResponseConverter responseConverter = mock(ResponseConverter.class); + + private final Object request = new Object(); + + private final Object response = new Object(); + + private final OperationRequest operationRequest = new OperationRequestFactory() + .create(URI.create("http://localhost:8080"), null, null, new HttpHeaders(), + null, null); + + private final OperationResponse operationResponse = new OperationResponseFactory() + .create(null, null, null); + + private final Snippet snippet = mock(Snippet.class); + + @Test + public void basicHandling() throws IOException { + given(this.requestConverter.convert(this.request)).willReturn( + this.operationRequest); + given(this.responseConverter.convert(this.response)).willReturn( + this.operationResponse); + HashMap configuration = new HashMap<>(); + new RestDocumentationHandler<>("id", this.requestConverter, + this.responseConverter, this.snippet).handle(this.request, this.response, + configuration); + verifySnippetInvocation(this.snippet, configuration); + } + + @Test + public void defaultSnippetsAreCalled() throws IOException { + given(this.requestConverter.convert(this.request)).willReturn( + this.operationRequest); + given(this.responseConverter.convert(this.response)).willReturn( + this.operationResponse); + HashMap configuration = new HashMap<>(); + Snippet defaultSnippet1 = mock(Snippet.class); + Snippet defaultSnippet2 = mock(Snippet.class); + configuration.put(SnippetConfigurer.ATTRIBUTE_DEFAULT_SNIPPETS, + Arrays.asList(defaultSnippet1, defaultSnippet2)); + new RestDocumentationHandler<>("id", this.requestConverter, + this.responseConverter, this.snippet).handle(this.request, this.response, + configuration); + verifySnippetInvocation(this.snippet, configuration); + verifySnippetInvocation(defaultSnippet1, configuration); + verifySnippetInvocation(defaultSnippet2, configuration); + } + + @Test + public void additionalSnippetsAreCalled() throws IOException { + given(this.requestConverter.convert(this.request)).willReturn( + this.operationRequest); + given(this.responseConverter.convert(this.response)).willReturn( + this.operationResponse); + Snippet additionalSnippet1 = mock(Snippet.class); + Snippet additionalSnippet2 = mock(Snippet.class); + RestDocumentationHandler handler = new RestDocumentationHandler<>( + "id", this.requestConverter, this.responseConverter, this.snippet); + handler.addSnippets(additionalSnippet1, additionalSnippet2); + HashMap configuration = new HashMap<>(); + handler.handle(this.request, this.response, configuration); + verifySnippetInvocation(this.snippet, configuration); + verifySnippetInvocation(additionalSnippet1, configuration); + verifySnippetInvocation(additionalSnippet2, configuration); + } + + private void verifySnippetInvocation(Snippet snippet, Map attributes) + throws IOException { + ArgumentCaptor operation = ArgumentCaptor.forClass(Operation.class); + verify(snippet).document(operation.capture()); + assertThat(this.operationRequest, is(equalTo(operation.getValue().getRequest()))); + assertThat(this.operationResponse, + is(equalTo(operation.getValue().getResponse()))); + assertThat(attributes, is(equalTo(operation.getValue().getAttributes()))); + } +} diff --git a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationRequestFactory.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRequestConverter.java similarity index 83% rename from spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationRequestFactory.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRequestConverter.java index 9449354a..6ad0c553 100644 --- a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationRequestFactory.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRequestConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2015 the original author or authors. + * Copyright 2014-2016 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. @@ -32,11 +32,13 @@ import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockMultipartHttpServletRequest; +import org.springframework.restdocs.operation.ConversionException; import org.springframework.restdocs.operation.OperationRequest; import org.springframework.restdocs.operation.OperationRequestFactory; import org.springframework.restdocs.operation.OperationRequestPart; import org.springframework.restdocs.operation.OperationRequestPartFactory; import org.springframework.restdocs.operation.Parameters; +import org.springframework.restdocs.operation.RequestConverter; import org.springframework.util.FileCopyUtils; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; @@ -44,13 +46,13 @@ import org.springframework.web.multipart.MultipartFile; import static org.springframework.restdocs.mockmvc.IterableEnumeration.iterable; /** - * A factory for creating an {@link OperationRequest} from a + * A converter for creating an {@link OperationRequest} from a * {@link MockHttpServletRequest}. * * @author Andy Wilkinson * */ -class MockMvcOperationRequestFactory { +class MockMvcRequestConverter implements RequestConverter { private static final String SCHEME_HTTP = "http"; @@ -60,28 +62,29 @@ class MockMvcOperationRequestFactory { private static final int STANDARD_PORT_HTTPS = 443; - /** - * Creates a new {@code OperationRequest} derived from the given {@code mockRequest}. - * - * @param mockRequest the request - * @return the {@code OperationRequest} - * @throws Exception if the request could not be created - */ - OperationRequest createOperationRequest(MockHttpServletRequest mockRequest) - throws Exception { - HttpHeaders headers = extractHeaders(mockRequest); - Parameters parameters = extractParameters(mockRequest); - List parts = extractParts(mockRequest); - String queryString = mockRequest.getQueryString(); - if (!StringUtils.hasText(queryString) && "GET".equals(mockRequest.getMethod())) { - queryString = parameters.toQueryString(); + @Override + public OperationRequest convert(MockHttpServletRequest mockRequest) { + try { + HttpHeaders headers = extractHeaders(mockRequest); + Parameters parameters = extractParameters(mockRequest); + List parts = extractParts(mockRequest); + String queryString = mockRequest.getQueryString(); + if (!StringUtils.hasText(queryString) + && "GET".equals(mockRequest.getMethod())) { + queryString = parameters.toQueryString(); + } + return new OperationRequestFactory() + .create(URI + .create(getRequestUri(mockRequest) + + (StringUtils.hasText(queryString) ? "?" + + queryString : "")), + HttpMethod.valueOf(mockRequest.getMethod()), FileCopyUtils + .copyToByteArray(mockRequest.getInputStream()), + headers, parameters, parts); + } + catch (Exception ex) { + throw new ConversionException(ex); } - return new OperationRequestFactory().create( - URI.create(getRequestUri(mockRequest) - + (StringUtils.hasText(queryString) ? "?" + queryString : "")), - HttpMethod.valueOf(mockRequest.getMethod()), - FileCopyUtils.copyToByteArray(mockRequest.getInputStream()), headers, - parameters, parts); } private List extractParts(MockHttpServletRequest servletRequest) diff --git a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationResponseFactory.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcResponseConverter.java similarity index 77% rename from spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationResponseFactory.java rename to spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcResponseConverter.java index 4e4f765f..d0677cce 100644 --- a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationResponseFactory.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcResponseConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2015 the original author or authors. + * Copyright 2014-2016 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. @@ -21,22 +21,18 @@ import org.springframework.http.HttpStatus; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.restdocs.operation.OperationResponse; import org.springframework.restdocs.operation.OperationResponseFactory; +import org.springframework.restdocs.operation.ResponseConverter; /** - * A factory for creating an {@link OperationResponse} derived from a + * A converter for creating an {@link OperationResponse} derived from a * {@link MockHttpServletResponse}. * * @author Andy Wilkinson */ -class MockMvcOperationResponseFactory { +class MockMvcResponseConverter implements ResponseConverter { - /** - * Create a new {@code OperationResponse} derived from the given {@code mockResponse}. - * - * @param mockResponse the response - * @return the {@code OperationResponse} - */ - OperationResponse createOperationResponse(MockHttpServletResponse mockResponse) { + @Override + public OperationResponse convert(MockHttpServletResponse mockResponse) { return new OperationResponseFactory().create( HttpStatus.valueOf(mockResponse.getStatus()), extractHeaders(mockResponse), mockResponse.getContentAsByteArray()); @@ -51,4 +47,5 @@ class MockMvcOperationResponseFactory { } return headers; } + } diff --git a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentation.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentation.java index 541f380d..64825f7e 100644 --- a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentation.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentation.java @@ -17,6 +17,7 @@ package org.springframework.restdocs.mockmvc; import org.springframework.restdocs.RestDocumentation; +import org.springframework.restdocs.RestDocumentationHandler; import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; import org.springframework.restdocs.snippet.Snippet; @@ -32,6 +33,10 @@ import org.springframework.test.web.servlet.setup.MockMvcConfigurer; */ public abstract class MockMvcRestDocumentation { + private static final MockMvcRequestConverter REQUEST_CONVERTER = new MockMvcRequestConverter(); + + private static final MockMvcResponseConverter RESPONSE_CONVERTER = new MockMvcResponseConverter(); + private MockMvcRestDocumentation() { } @@ -61,7 +66,8 @@ public abstract class MockMvcRestDocumentation { */ public static RestDocumentationResultHandler document(String identifier, Snippet... snippets) { - return new RestDocumentationResultHandler(identifier, snippets); + return new RestDocumentationResultHandler(new RestDocumentationHandler<>( + identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, snippets)); } /** @@ -78,8 +84,9 @@ public abstract class MockMvcRestDocumentation { */ public static RestDocumentationResultHandler document(String identifier, OperationRequestPreprocessor requestPreprocessor, Snippet... snippets) { - return new RestDocumentationResultHandler(identifier, requestPreprocessor, - snippets); + return new RestDocumentationResultHandler(new RestDocumentationHandler<>( + identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, requestPreprocessor, + snippets)); } /** @@ -96,8 +103,9 @@ public abstract class MockMvcRestDocumentation { */ public static RestDocumentationResultHandler document(String identifier, OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) { - return new RestDocumentationResultHandler(identifier, responsePreprocessor, - snippets); + return new RestDocumentationResultHandler(new RestDocumentationHandler<>( + identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, responsePreprocessor, + snippets)); } /** @@ -117,8 +125,9 @@ public abstract class MockMvcRestDocumentation { public static RestDocumentationResultHandler document(String identifier, OperationRequestPreprocessor requestPreprocessor, OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) { - return new RestDocumentationResultHandler(identifier, requestPreprocessor, - responsePreprocessor, snippets); + return new RestDocumentationResultHandler(new RestDocumentationHandler<>( + identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, requestPreprocessor, + responsePreprocessor, snippets)); } } diff --git a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationConfigurer.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationConfigurer.java index a402487f..7921cab8 100644 --- a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationConfigurer.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationConfigurer.java @@ -88,12 +88,12 @@ public class MockMvcRestDocumentationConfigurer @Override public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { RestDocumentationContext context = this.restDocumentation.beforeOperation(); - request.setAttribute(RestDocumentationContext.class.getName(), context); Map configuration = new HashMap<>(); configuration.put(MockHttpServletRequest.class.getName(), request); String urlTemplateAttribute = "org.springframework.restdocs.urlTemplate"; configuration.put(urlTemplateAttribute, request.getAttribute(urlTemplateAttribute)); + configuration.put(RestDocumentationContext.class.getName(), context); request.setAttribute("org.springframework.restdocs.configuration", configuration); MockMvcRestDocumentationConfigurer.this.apply(configuration, context); diff --git a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java index 075c162f..3194e826 100644 --- a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java @@ -16,20 +16,11 @@ package org.springframework.restdocs.mockmvc; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; import java.util.Map; -import org.springframework.restdocs.RestDocumentationContext; -import org.springframework.restdocs.config.SnippetConfigurer; -import org.springframework.restdocs.operation.Operation; -import org.springframework.restdocs.operation.OperationRequest; -import org.springframework.restdocs.operation.OperationResponse; -import org.springframework.restdocs.operation.StandardOperation; -import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; -import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.restdocs.RestDocumentationHandler; import org.springframework.restdocs.snippet.Snippet; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultHandler; @@ -44,68 +35,20 @@ import org.springframework.util.Assert; */ public class RestDocumentationResultHandler implements ResultHandler { - private final String identifier; + private final RestDocumentationHandler delegate; - private final OperationRequestPreprocessor requestPreprocessor; - - private final OperationResponsePreprocessor responsePreprocessor; - - private final List snippets; - - RestDocumentationResultHandler(String identifier, Snippet... snippets) { - this(identifier, new IdentityOperationRequestPreprocessor(), - new IdentityOperationResponsePreprocessor(), snippets); - } - - RestDocumentationResultHandler(String identifier, - OperationRequestPreprocessor requestPreprocessor, Snippet... snippets) { - this(identifier, requestPreprocessor, - new IdentityOperationResponsePreprocessor(), snippets); - } - - RestDocumentationResultHandler(String identifier, - OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) { - this(identifier, new IdentityOperationRequestPreprocessor(), - responsePreprocessor, snippets); - } - - RestDocumentationResultHandler(String identifier, - OperationRequestPreprocessor requestPreprocessor, - OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) { - Assert.notNull(identifier, "identifier must be non-null"); - Assert.notNull(requestPreprocessor, "requestPreprocessor must be non-null"); - Assert.notNull(responsePreprocessor, "responsePreprocessor must be non-null"); - Assert.notNull(snippets, "snippets must be non-null"); - this.identifier = identifier; - this.requestPreprocessor = requestPreprocessor; - this.responsePreprocessor = responsePreprocessor; - this.snippets = new ArrayList<>(Arrays.asList(snippets)); + RestDocumentationResultHandler( + RestDocumentationHandler delegate) { + Assert.notNull(delegate, "delegate must be non-null"); + this.delegate = delegate; } @Override public void handle(MvcResult result) throws Exception { - Map attributes = new HashMap<>(); - attributes.put(RestDocumentationContext.class.getName(), result.getRequest() - .getAttribute(RestDocumentationContext.class.getName())); - attributes.put("org.springframework.restdocs.urlTemplate", result.getRequest() - .getAttribute("org.springframework.restdocs.urlTemplate")); @SuppressWarnings("unchecked") Map configuration = (Map) result.getRequest() .getAttribute("org.springframework.restdocs.configuration"); - attributes.putAll(configuration); - - OperationRequest request = this.requestPreprocessor - .preprocess(new MockMvcOperationRequestFactory() - .createOperationRequest(result.getRequest())); - - OperationResponse response = this.responsePreprocessor - .preprocess(new MockMvcOperationResponseFactory() - .createOperationResponse(result.getResponse())); - Operation operation = new StandardOperation(this.identifier, request, response, - attributes); - for (Snippet snippet : getSnippets(result)) { - snippet.document(operation); - } + this.delegate.handle(result.getRequest(), result.getResponse(), configuration); } /** @@ -113,41 +56,11 @@ public class RestDocumentationResultHandler implements ResultHandler { * handler is called. * * @param snippets the snippets to add - * @return this {@code ResultDocumentationResultHandler} + * @return this {@code RestDocumentationResultHandler} */ public RestDocumentationResultHandler snippets(Snippet... snippets) { - this.snippets.addAll(Arrays.asList(snippets)); + this.delegate.addSnippets(snippets); return this; } - @SuppressWarnings("unchecked") - private List getSnippets(MvcResult result) { - List combinedSnippets = new ArrayList<>( - (List) ((Map) result.getRequest().getAttribute( - "org.springframework.restdocs.configuration")) - .get(SnippetConfigurer.ATTRIBUTE_DEFAULT_SNIPPETS)); - combinedSnippets.addAll(this.snippets); - return combinedSnippets; - } - - private static final class IdentityOperationRequestPreprocessor implements - OperationRequestPreprocessor { - - @Override - public OperationRequest preprocess(OperationRequest request) { - return request; - } - - } - - private static final class IdentityOperationResponsePreprocessor implements - OperationResponsePreprocessor { - - @Override - public OperationResponse preprocess(OperationResponse response) { - return response; - } - - } - } diff --git a/spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcOperationRequestFactoryTests.java b/spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRequestConverterTests.java similarity index 92% rename from spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcOperationRequestFactoryTests.java rename to spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRequestConverterTests.java index 6770d31b..5c5c2aea 100644 --- a/spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcOperationRequestFactoryTests.java +++ b/spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRequestConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2015 the original author or authors. + * Copyright 2014-2016 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. @@ -43,13 +43,13 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; /** - * Tests for {@link MockMvcOperationRequestFactory}. + * Tests for {@link MockMvcRequestConverter}. * * @author Andy Wilkinson */ -public class MockMvcOperationRequestFactoryTests { +public class MockMvcRequestConverterTests { - private final MockMvcOperationRequestFactory factory = new MockMvcOperationRequestFactory(); + private final MockMvcRequestConverter factory = new MockMvcRequestConverter(); @Test public void httpRequest() throws Exception { @@ -64,7 +64,7 @@ public class MockMvcOperationRequestFactoryTests { MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo") .buildRequest(new MockServletContext()); mockRequest.setServerPort(8080); - OperationRequest request = this.factory.createOperationRequest(mockRequest); + OperationRequest request = this.factory.convert(mockRequest); assertThat(request.getUri(), is(URI.create("http://localhost:8080/foo"))); assertThat(request.getMethod(), is(HttpMethod.GET)); } @@ -93,7 +93,7 @@ public class MockMvcOperationRequestFactoryTests { .buildRequest(new MockServletContext()); mockRequest.setScheme("https"); mockRequest.setServerPort(443); - OperationRequest request = this.factory.createOperationRequest(mockRequest); + OperationRequest request = this.factory.convert(mockRequest); assertThat(request.getUri(), is(URI.create("https://localhost/foo"))); assertThat(request.getMethod(), is(HttpMethod.GET)); } @@ -104,7 +104,7 @@ public class MockMvcOperationRequestFactoryTests { .buildRequest(new MockServletContext()); mockRequest.setScheme("https"); mockRequest.setServerPort(8443); - OperationRequest request = this.factory.createOperationRequest(mockRequest); + OperationRequest request = this.factory.convert(mockRequest); assertThat(request.getUri(), is(URI.create("https://localhost:8443/foo"))); assertThat(request.getMethod(), is(HttpMethod.GET)); } @@ -191,7 +191,7 @@ public class MockMvcOperationRequestFactoryTests { given(mockPart.getName()).willReturn("part-name"); given(mockPart.getSubmittedFileName()).willReturn("submitted.txt"); mockRequest.addPart(mockPart); - OperationRequest request = this.factory.createOperationRequest(mockRequest); + OperationRequest request = this.factory.convert(mockRequest); assertThat(request.getParts().size(), is(1)); OperationRequestPart part = request.getParts().iterator().next(); assertThat(part.getName(), is(equalTo("part-name"))); @@ -216,7 +216,7 @@ public class MockMvcOperationRequestFactoryTests { given(mockPart.getSubmittedFileName()).willReturn("submitted.png"); given(mockPart.getContentType()).willReturn("image/png"); mockRequest.addPart(mockPart); - OperationRequest request = this.factory.createOperationRequest(mockRequest); + OperationRequest request = this.factory.convert(mockRequest); assertThat(request.getParts().size(), is(1)); OperationRequestPart part = request.getParts().iterator().next(); assertThat(part.getName(), is(equalTo("part-name"))); @@ -229,8 +229,7 @@ public class MockMvcOperationRequestFactoryTests { private OperationRequest createOperationRequest(MockHttpServletRequestBuilder builder) throws Exception { - return this.factory.createOperationRequest(builder - .buildRequest(new MockServletContext())); + return this.factory.convert(builder.buildRequest(new MockServletContext())); } } diff --git a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredOperationRequestFactory.java b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredRequestConverter.java similarity index 92% rename from spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredOperationRequestFactory.java rename to spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredRequestConverter.java index c3ef0b20..cfc19677 100644 --- a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredOperationRequestFactory.java +++ b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredRequestConverter.java @@ -30,20 +30,23 @@ import org.springframework.restdocs.operation.OperationRequestFactory; import org.springframework.restdocs.operation.OperationRequestPart; import org.springframework.restdocs.operation.OperationRequestPartFactory; import org.springframework.restdocs.operation.Parameters; +import org.springframework.restdocs.operation.RequestConverter; import com.jayway.restassured.response.Header; import com.jayway.restassured.specification.FilterableRequestSpecification; import com.jayway.restassured.specification.MultiPartSpecification; /** - * A factory for creating an {@link OperationRequest} derived from a REST Assured + * A converter for creating an {@link OperationRequest} from a REST Assured * {@link FilterableRequestSpecification}. * * @author Andy Wilkinson */ -class RestAssuredOperationRequestFactory { +class RestAssuredRequestConverter implements + RequestConverter { - OperationRequest createOperationRequest(FilterableRequestSpecification requestSpec) { + @Override + public OperationRequest convert(FilterableRequestSpecification requestSpec) { return new OperationRequestFactory().create(URI.create(requestSpec.getURI()), HttpMethod.valueOf(requestSpec.getMethod().name()), extractContent(requestSpec), extractHeaders(requestSpec), diff --git a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredOperationResponseFactory.java b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredResponseConverter.java similarity index 84% rename from spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredOperationResponseFactory.java rename to spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredResponseConverter.java index bbcd251e..425fc96f 100644 --- a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredOperationResponseFactory.java +++ b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredResponseConverter.java @@ -20,19 +20,21 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.restdocs.operation.OperationResponse; import org.springframework.restdocs.operation.OperationResponseFactory; +import org.springframework.restdocs.operation.ResponseConverter; import com.jayway.restassured.response.Header; import com.jayway.restassured.response.Response; /** - * A factory for creating an {@link OperationResponse} derived from a REST Assured + * A converter for creating an {@link OperationResponse} from a REST Assured * {@link Response}. * * @author Andy Wilkinson */ -class RestAssuredOperationResponseFactory { +class RestAssuredResponseConverter implements ResponseConverter { - OperationResponse createOperationResponse(Response response) { + @Override + public OperationResponse convert(Response response) { return new OperationResponseFactory().create( HttpStatus.valueOf(response.getStatusCode()), extractHeaders(response), extractContent(response)); diff --git a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredRestDocumentation.java b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredRestDocumentation.java index 447ba1f5..0e47cbd2 100644 --- a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredRestDocumentation.java +++ b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestAssuredRestDocumentation.java @@ -17,6 +17,7 @@ package org.springframework.restdocs.restassured; import org.springframework.restdocs.RestDocumentation; +import org.springframework.restdocs.RestDocumentationHandler; import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; import org.springframework.restdocs.snippet.Snippet; @@ -28,6 +29,10 @@ import org.springframework.restdocs.snippet.Snippet; */ public abstract class RestAssuredRestDocumentation { + private static final RestAssuredRequestConverter REQUEST_CONVERTER = new RestAssuredRequestConverter(); + + private static final RestAssuredResponseConverter RESPONSE_CONVERTER = new RestAssuredResponseConverter(); + private RestAssuredRestDocumentation() { } @@ -41,7 +46,8 @@ public abstract class RestAssuredRestDocumentation { * @return a {@link RestDocumentationFilter} that will produce the documentation */ public static RestDocumentationFilter document(String identifier, Snippet... snippets) { - return new RestDocumentationFilter(identifier, snippets); + return new RestDocumentationFilter(new RestDocumentationHandler<>(identifier, + REQUEST_CONVERTER, RESPONSE_CONVERTER, snippets)); } /** @@ -56,7 +62,8 @@ public abstract class RestAssuredRestDocumentation { */ public static RestDocumentationFilter document(String identifier, OperationRequestPreprocessor requestPreprocessor, Snippet... snippets) { - return new RestDocumentationFilter(identifier, requestPreprocessor, snippets); + return new RestDocumentationFilter(new RestDocumentationHandler<>(identifier, + REQUEST_CONVERTER, RESPONSE_CONVERTER, requestPreprocessor, snippets)); } /** @@ -71,7 +78,8 @@ public abstract class RestAssuredRestDocumentation { */ public static RestDocumentationFilter document(String identifier, OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) { - return new RestDocumentationFilter(identifier, responsePreprocessor, snippets); + return new RestDocumentationFilter(new RestDocumentationHandler<>(identifier, + REQUEST_CONVERTER, RESPONSE_CONVERTER, responsePreprocessor, snippets)); } /** @@ -89,8 +97,9 @@ public abstract class RestAssuredRestDocumentation { public static RestDocumentationFilter document(String identifier, OperationRequestPreprocessor requestPreprocessor, OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) { - return new RestDocumentationFilter(identifier, requestPreprocessor, - responsePreprocessor, snippets); + return new RestDocumentationFilter(new RestDocumentationHandler<>(identifier, + REQUEST_CONVERTER, RESPONSE_CONVERTER, requestPreprocessor, + responsePreprocessor, snippets)); } /** diff --git a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestDocumentationFilter.java b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestDocumentationFilter.java index 3460a99a..f588ed16 100644 --- a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestDocumentationFilter.java +++ b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured/RestDocumentationFilter.java @@ -16,22 +16,13 @@ package org.springframework.restdocs.restassured; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.springframework.restdocs.RestDocumentationContext; -import org.springframework.restdocs.config.SnippetConfigurer; -import org.springframework.restdocs.operation.Operation; -import org.springframework.restdocs.operation.OperationRequest; -import org.springframework.restdocs.operation.OperationResponse; -import org.springframework.restdocs.operation.StandardOperation; -import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; -import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; +import org.springframework.restdocs.RestDocumentationHandler; import org.springframework.restdocs.snippet.Snippet; +import org.springframework.util.Assert; import com.jayway.restassured.filter.Filter; import com.jayway.restassured.filter.FilterContext; @@ -46,40 +37,12 @@ import com.jayway.restassured.specification.FilterableResponseSpecification; */ public final class RestDocumentationFilter implements Filter { - private final String identifier; + private final RestDocumentationHandler delegate; - private final OperationRequestPreprocessor requestPreprocessor; - - private final OperationResponsePreprocessor responsePreprocessor; - - private final List snippets; - - RestDocumentationFilter(String identifier, Snippet... snippets) { - this(identifier, new IdentityOperationRequestPreprocessor(), - new IdentityOperationResponsePreprocessor(), snippets); - } - - RestDocumentationFilter(String identifier, - OperationRequestPreprocessor operationRequestPreprocessor, - Snippet... snippets) { - this(identifier, operationRequestPreprocessor, - new IdentityOperationResponsePreprocessor(), snippets); - } - - RestDocumentationFilter(String identifier, - OperationResponsePreprocessor operationResponsePreprocessor, - Snippet... snippets) { - this(identifier, new IdentityOperationRequestPreprocessor(), - operationResponsePreprocessor, snippets); - } - - RestDocumentationFilter(String identifier, - OperationRequestPreprocessor requestPreprocessor, - OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) { - this.identifier = identifier; - this.requestPreprocessor = requestPreprocessor; - this.responsePreprocessor = responsePreprocessor; - this.snippets = new ArrayList<>(Arrays.asList(snippets)); + RestDocumentationFilter( + RestDocumentationHandler delegate) { + Assert.notNull(delegate, "delegate must be non-null"); + this.delegate = delegate; } @Override @@ -87,35 +50,15 @@ public final class RestDocumentationFilter implements Filter { FilterableResponseSpecification responseSpec, FilterContext context) { Response response = context.next(requestSpec, responseSpec); - OperationRequest operationRequest = this.requestPreprocessor - .preprocess(new RestAssuredOperationRequestFactory() - .createOperationRequest(requestSpec)); - OperationResponse operationResponse = this.responsePreprocessor - .preprocess(new RestAssuredOperationResponseFactory() - .createOperationResponse(response)); - - RestDocumentationContext documentationContext = context - .getValue(RestDocumentationContext.class.getName()); - - Map attributes = new HashMap<>(); - attributes.put(RestDocumentationContext.class.getName(), documentationContext); - attributes.put("org.springframework.restdocs.urlTemplate", + Map configuration = new HashMap<>( + context.>getValue("org.springframework.restdocs.configuration")); + configuration.put(RestDocumentationContext.class.getName(), context + .getValue(RestDocumentationContext.class + .getName())); + configuration.put("org.springframework.restdocs.urlTemplate", requestSpec.getUserDefinedPath()); - Map configuration = context - .getValue("org.springframework.restdocs.configuration"); - attributes.putAll(configuration); - Operation operation = new StandardOperation(this.identifier, operationRequest, - operationResponse, attributes); - - try { - for (Snippet snippet : getSnippets(configuration)) { - snippet.document(operation); - } - } - catch (IOException ex) { - throw new RuntimeException(ex); - } + this.delegate.handle(requestSpec, response, configuration); return response; } @@ -128,37 +71,8 @@ public final class RestDocumentationFilter implements Filter { * @return this {@code RestDocumentationFilter} */ public RestDocumentationFilter snippets(Snippet... snippets) { - this.snippets.addAll(Arrays.asList(snippets)); + this.delegate.addSnippets(snippets); return this; } - @SuppressWarnings("unchecked") - private List getSnippets(Map configuration) { - List combinedSnippets = new ArrayList<>( - (List) configuration - .get(SnippetConfigurer.ATTRIBUTE_DEFAULT_SNIPPETS)); - combinedSnippets.addAll(this.snippets); - return combinedSnippets; - } - - private static final class IdentityOperationRequestPreprocessor implements - OperationRequestPreprocessor { - - @Override - public OperationRequest preprocess(OperationRequest request) { - return request; - } - - } - - private static final class IdentityOperationResponsePreprocessor implements - OperationResponsePreprocessor { - - @Override - public OperationResponse preprocess(OperationResponse response) { - return response; - } - - } - } diff --git a/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured/RestAssuredOperationRequestFactoryTests.java b/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured/RestAssuredRequestConverterTests.java similarity index 85% rename from spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured/RestAssuredOperationRequestFactoryTests.java rename to spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured/RestAssuredRequestConverterTests.java index bb532559..f39b15b2 100644 --- a/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured/RestAssuredOperationRequestFactoryTests.java +++ b/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured/RestAssuredRequestConverterTests.java @@ -36,7 +36,7 @@ import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.restdocs.operation.OperationRequest; import org.springframework.restdocs.operation.OperationRequestPart; -import org.springframework.restdocs.restassured.RestAssuredOperationRequestFactoryTests.TestApplication; +import org.springframework.restdocs.restassured.RestAssuredRequestConverterTests.TestApplication; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.web.bind.annotation.RequestMapping; @@ -51,7 +51,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; /** - * Tests for {@link RestAssuredOperationRequestFactory}. + * Tests for {@link RestAssuredRequestConverter}. * * @author Andy Wilkinson */ @@ -59,12 +59,12 @@ import static org.junit.Assert.assertThat; @SpringApplicationConfiguration(classes = TestApplication.class) @WebAppConfiguration @IntegrationTest("server.port=0") -public class RestAssuredOperationRequestFactoryTests { +public class RestAssuredRequestConverterTests { @Rule public final ExpectedException thrown = ExpectedException.none(); - private final RestAssuredOperationRequestFactory factory = new RestAssuredOperationRequestFactory(); + private final RestAssuredRequestConverter factory = new RestAssuredRequestConverter(); @Value("${local.server.port}") private int port; @@ -74,7 +74,7 @@ public class RestAssuredOperationRequestFactoryTests { RequestSpecification requestSpec = RestAssured.given().port(this.port); requestSpec.get("/foo/bar"); OperationRequest request = this.factory - .createOperationRequest((FilterableRequestSpecification) requestSpec); + .convert((FilterableRequestSpecification) requestSpec); assertThat(request.getUri(), is(equalTo(URI.create("http://localhost:" + this.port + "/foo/bar")))); } @@ -84,7 +84,7 @@ public class RestAssuredOperationRequestFactoryTests { RequestSpecification requestSpec = RestAssured.given().port(this.port); requestSpec.head("/foo/bar"); OperationRequest request = this.factory - .createOperationRequest((FilterableRequestSpecification) requestSpec); + .convert((FilterableRequestSpecification) requestSpec); assertThat(request.getMethod(), is(equalTo(HttpMethod.HEAD))); } @@ -94,7 +94,7 @@ public class RestAssuredOperationRequestFactoryTests { .queryParam("foo", "bar"); requestSpec.get("/"); OperationRequest request = this.factory - .createOperationRequest((FilterableRequestSpecification) requestSpec); + .convert((FilterableRequestSpecification) requestSpec); assertThat(request.getParameters().size(), is(1)); assertThat(request.getParameters().get("foo"), is(equalTo(Arrays.asList("bar")))); } @@ -104,7 +104,7 @@ public class RestAssuredOperationRequestFactoryTests { RequestSpecification requestSpec = RestAssured.given().port(this.port); requestSpec.get("/?foo=bar"); OperationRequest request = this.factory - .createOperationRequest((FilterableRequestSpecification) requestSpec); + .convert((FilterableRequestSpecification) requestSpec); assertThat(request.getParameters().size(), is(1)); assertThat(request.getParameters().get("foo"), is(equalTo(Arrays.asList("bar")))); } @@ -115,7 +115,7 @@ public class RestAssuredOperationRequestFactoryTests { .formParameter("foo", "bar"); requestSpec.get("/"); OperationRequest request = this.factory - .createOperationRequest((FilterableRequestSpecification) requestSpec); + .convert((FilterableRequestSpecification) requestSpec); assertThat(request.getParameters().size(), is(1)); assertThat(request.getParameters().get("foo"), is(equalTo(Arrays.asList("bar")))); } @@ -126,7 +126,7 @@ public class RestAssuredOperationRequestFactoryTests { .parameter("foo", "bar"); requestSpec.get("/"); OperationRequest request = this.factory - .createOperationRequest((FilterableRequestSpecification) requestSpec); + .convert((FilterableRequestSpecification) requestSpec); assertThat(request.getParameters().size(), is(1)); assertThat(request.getParameters().get("foo"), is(equalTo(Arrays.asList("bar")))); } @@ -137,7 +137,7 @@ public class RestAssuredOperationRequestFactoryTests { .header("Foo", "bar"); requestSpec.get("/"); OperationRequest request = this.factory - .createOperationRequest((FilterableRequestSpecification) requestSpec); + .convert((FilterableRequestSpecification) requestSpec); assertThat(request.getHeaders().toString(), request.getHeaders().size(), is(3)); assertThat(request.getHeaders().get("Foo"), is(equalTo(Arrays.asList("bar")))); assertThat(request.getHeaders().get("Accept"), is(equalTo(Arrays.asList("*/*")))); @@ -152,7 +152,7 @@ public class RestAssuredOperationRequestFactoryTests { .multiPart("b", new ObjectBody("bar"), "application/json"); requestSpec.post().then().statusCode(200); OperationRequest request = this.factory - .createOperationRequest((FilterableRequestSpecification) requestSpec); + .convert((FilterableRequestSpecification) requestSpec); Collection parts = request.getParts(); assertThat(parts.size(), is(2)); Iterator iterator = parts.iterator(); @@ -174,7 +174,7 @@ public class RestAssuredOperationRequestFactoryTests { RequestSpecification requestSpec = RestAssured.given().body("body".getBytes()) .port(this.port); requestSpec.post(); - this.factory.createOperationRequest((FilterableRequestSpecification) requestSpec); + this.factory.convert((FilterableRequestSpecification) requestSpec); } @Test @@ -183,7 +183,7 @@ public class RestAssuredOperationRequestFactoryTests { .port(this.port); requestSpec.post(); OperationRequest request = this.factory - .createOperationRequest((FilterableRequestSpecification) requestSpec); + .convert((FilterableRequestSpecification) requestSpec); assertThat(request.getContentAsString(), is(equalTo("body"))); } @@ -193,7 +193,7 @@ public class RestAssuredOperationRequestFactoryTests { .body(new ObjectBody("bar")).port(this.port); requestSpec.post(); OperationRequest request = this.factory - .createOperationRequest((FilterableRequestSpecification) requestSpec); + .convert((FilterableRequestSpecification) requestSpec); assertThat(request.getContentAsString(), is(equalTo("{\"foo\":\"bar\"}"))); } @@ -205,7 +205,7 @@ public class RestAssuredOperationRequestFactoryTests { requestSpec.post(); this.thrown .expectMessage(equalTo("Unsupported request content: java.io.ByteArrayInputStream")); - this.factory.createOperationRequest((FilterableRequestSpecification) requestSpec); + this.factory.convert((FilterableRequestSpecification) requestSpec); } @Test @@ -214,7 +214,7 @@ public class RestAssuredOperationRequestFactoryTests { .body(new File("src/test/resources/body.txt")).port(this.port); requestSpec.post(); this.thrown.expectMessage(equalTo("Unsupported request content: java.io.File")); - this.factory.createOperationRequest((FilterableRequestSpecification) requestSpec); + this.factory.convert((FilterableRequestSpecification) requestSpec); } /**