From abfe42fe2d64117f8589acb0b00081d239511d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20D=C3=BCsterh=C3=B6ft?= Date: Wed, 5 Sep 2018 21:55:39 +0200 Subject: [PATCH 1/3] Add public FieldTypeResolver. This can be useful for extensions to reuse field type determination logic. --- .../payload/AbstractFieldsSnippet.java | 37 +--- .../restdocs/payload/ContentHandler.java | 10 +- .../payload/ContentTypeHandlerFactory.java | 67 +++++++ .../restdocs/payload/FieldTypeResolver.java | 48 +++++ .../restdocs/payload/JsonContentHandler.java | 33 +-- .../payload/JsonFieldTypeResolver.java | 37 +++- .../restdocs/payload/XmlContentHandler.java | 7 +- .../payload/FieldTypeResolverTests.java | 51 +++++ .../payload/JsonContentHandlerTests.java | 64 +----- .../payload/JsonFieldTypeResolverTests.java | 189 +++++++++++------- 10 files changed, 343 insertions(+), 200 deletions(-) create mode 100644 spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java create mode 100644 spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java create mode 100644 spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java index fafde4a04..5c595fab4 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java @@ -38,6 +38,7 @@ * * @author Andreas Evers * @author Andy Wilkinson + * @author Mathias Düsterhöft */ public abstract class AbstractFieldsSnippet extends TemplatedSnippet { @@ -160,7 +161,8 @@ protected Map createModel(Operation operation) { content = verifyContent( this.subsectionExtractor.extractSubsection(content, contentType)); } - ContentHandler contentHandler = getContentHandler(content, contentType); + ContentHandler contentHandler = ContentTypeHandlerFactory.create(content, + contentType); validateFieldDocumentation(contentHandler); @@ -168,7 +170,8 @@ protected Map createModel(Operation operation) { for (FieldDescriptor descriptor : this.fieldDescriptors) { if (!descriptor.isIgnored()) { try { - Object type = contentHandler.determineFieldType(descriptor); + Object type = contentHandler.getFieldTypeResolver() + .determineFieldType(descriptor); descriptorsToDocument.add(copyWithType(descriptor, type)); } catch (FieldDoesNotExistException ex) { @@ -200,36 +203,6 @@ private byte[] verifyContent(byte[] content) { return content; } - private ContentHandler getContentHandler(byte[] content, MediaType contentType) { - ContentHandler contentHandler = createJsonContentHandler(content); - if (contentHandler == null) { - contentHandler = createXmlContentHandler(content); - if (contentHandler == null) { - throw new PayloadHandlingException("Cannot handle " + contentType - + " content as it could not be parsed as JSON or XML"); - } - } - return contentHandler; - } - - private ContentHandler createJsonContentHandler(byte[] content) { - try { - return new JsonContentHandler(content); - } - catch (Exception ex) { - return null; - } - } - - private ContentHandler createXmlContentHandler(byte[] content) { - try { - return new XmlContentHandler(content); - } - catch (Exception ex) { - return null; - } - } - private void validateFieldDocumentation(ContentHandler payloadHandler) { List missingFields = payloadHandler .findMissingFields(this.fieldDescriptors); diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentHandler.java index 32bed30bd..09b95611e 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentHandler.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentHandler.java @@ -22,6 +22,7 @@ * A handler for the content of a request or response. * * @author Andy Wilkinson + * @author Mathias Düsterhöft */ interface ContentHandler { @@ -48,11 +49,10 @@ interface ContentHandler { String getUndocumentedContent(List fieldDescriptors); /** - * Returns the type of the field that is described by the given - * {@code fieldDescriptor} based on the content of the payload. - * @param fieldDescriptor the field descriptor - * @return the type of the field + * Return a {@link FieldTypeResolver} that can be used for the content type this + * ContentHandler can process. + * @return a {@link FieldTypeResolver} */ - Object determineFieldType(FieldDescriptor fieldDescriptor); + FieldTypeResolver getFieldTypeResolver(); } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java new file mode 100644 index 000000000..2831f5222 --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java @@ -0,0 +1,67 @@ +/* + * 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. + * 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.payload; + +import org.springframework.http.MediaType; + +/** + * Factory providing access to {@link ContentHandler} implementation for the content type. + * + * @author Mathias Düsterhöft + */ +final class ContentTypeHandlerFactory { + + private ContentTypeHandlerFactory() { + } + + /** + * Create a {@link ContentHandler} for the given content type and payload. + * @param content the payload + * @param contentType the content type + * @return the ContentHandler + */ + static ContentHandler create(byte[] content, MediaType contentType) { + ContentHandler contentHandler = createJsonContentHandler(content); + if (contentHandler == null) { + contentHandler = createXmlContentHandler(content); + if (contentHandler == null) { + throw new PayloadHandlingException("Cannot handle " + contentType + + " content as it could not be parsed as JSON or XML"); + } + } + return contentHandler; + } + + private static ContentHandler createJsonContentHandler(byte[] content) { + try { + return new JsonContentHandler(content); + } + catch (Exception ex) { + return null; + } + } + + private static ContentHandler createXmlContentHandler(byte[] content) { + try { + return new XmlContentHandler(content); + } + catch (Exception ex) { + return null; + } + } + +} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java new file mode 100644 index 000000000..5616ca0b7 --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java @@ -0,0 +1,48 @@ +/* + * 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. + * 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.payload; + +import org.springframework.http.MediaType; + +/** + * Public abstraction for external access to field type determination for xml and json + * payloads. + * + * @author Mathias Düsterhöft + */ +public interface FieldTypeResolver { + + /** + * Create a FieldTypeResolver for the given content and contentType. + * @param content the payload that the {@link FieldTypeResolver} should handle + * @param contentType the content type of the payload + * @return the {@link FieldTypeResolver} + */ + static FieldTypeResolver create(byte[] content, MediaType contentType) { + return ContentTypeHandlerFactory.create(content, contentType) + .getFieldTypeResolver(); + } + + /** + * Returns the type of the field that is described by the given + * {@code fieldDescriptor} based on the content of the payload. + * @param fieldDescriptor the field descriptor + * @return the type of the field + */ + Object determineFieldType(FieldDescriptor fieldDescriptor); + +} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java index e64a91d11..6099c703b 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java @@ -37,8 +37,6 @@ class JsonContentHandler implements ContentHandler { private final JsonFieldProcessor fieldProcessor = new JsonFieldProcessor(); - private final JsonFieldTypeResolver fieldTypeResolver = new JsonFieldTypeResolver(); - private final ObjectMapper objectMapper = new ObjectMapper() .enable(SerializationFeature.INDENT_OUTPUT); @@ -124,6 +122,11 @@ public String getUndocumentedContent(List fieldDescriptors) { return null; } + @Override + public FieldTypeResolver getFieldTypeResolver() { + return new JsonFieldTypeResolver(readContent()); + } + private boolean describesSubsection(FieldDescriptor fieldDescriptor) { return fieldDescriptor instanceof SubsectionDescriptor; } @@ -144,30 +147,4 @@ private boolean isEmpty(Object object) { return ((List) object).isEmpty(); } - @Override - public Object determineFieldType(FieldDescriptor fieldDescriptor) { - if (fieldDescriptor.getType() == null) { - return this.fieldTypeResolver.resolveFieldType(fieldDescriptor, - readContent()); - } - if (!(fieldDescriptor.getType() instanceof JsonFieldType)) { - return fieldDescriptor.getType(); - } - JsonFieldType descriptorFieldType = (JsonFieldType) fieldDescriptor.getType(); - try { - JsonFieldType actualFieldType = this.fieldTypeResolver - .resolveFieldType(fieldDescriptor, readContent()); - if (descriptorFieldType == JsonFieldType.VARIES - || descriptorFieldType == actualFieldType - || (fieldDescriptor.isOptional() - && actualFieldType == JsonFieldType.NULL)) { - return descriptorFieldType; - } - throw new FieldTypesDoNotMatchException(fieldDescriptor, actualFieldType); - } - catch (FieldDoesNotExistException ex) { - return fieldDescriptor.getType(); - } - } - } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java index a577bc654..8f569b2cc 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java @@ -26,14 +26,45 @@ * Resolves the type of a field in a JSON request or response payload. * * @author Andy Wilkinson + * @author Mathias Düsterhöft */ -class JsonFieldTypeResolver { +class JsonFieldTypeResolver implements FieldTypeResolver { + + private final Object content; private final JsonFieldProcessor fieldProcessor = new JsonFieldProcessor(); - JsonFieldType resolveFieldType(FieldDescriptor fieldDescriptor, Object payload) { + JsonFieldTypeResolver(Object content) { + this.content = content; + } + + @Override + public Object determineFieldType(FieldDescriptor fieldDescriptor) { + if (fieldDescriptor.getType() == null) { + return resolveFieldType(fieldDescriptor); + } + if (!(fieldDescriptor.getType() instanceof JsonFieldType)) { + return fieldDescriptor.getType(); + } + JsonFieldType descriptorFieldType = (JsonFieldType) fieldDescriptor.getType(); + try { + JsonFieldType actualFieldType = resolveFieldType(fieldDescriptor); + if (descriptorFieldType == JsonFieldType.VARIES + || descriptorFieldType == actualFieldType + || (fieldDescriptor.isOptional() + && actualFieldType == JsonFieldType.NULL)) { + return descriptorFieldType; + } + throw new FieldTypesDoNotMatchException(fieldDescriptor, actualFieldType); + } + catch (FieldDoesNotExistException ex) { + return fieldDescriptor.getType(); + } + } + + JsonFieldType resolveFieldType(FieldDescriptor fieldDescriptor) { ExtractedField extractedField = this.fieldProcessor - .extract(fieldDescriptor.getPath(), payload); + .extract(fieldDescriptor.getPath(), this.content); Object value = extractedField.getValue(); if (value instanceof Collection && extractedField.getType() == PathType.MULTI) { JsonFieldType commonType = null; diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java index 45c088468..0e845a477 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java @@ -47,7 +47,7 @@ * * @author Andy Wilkinson */ -class XmlContentHandler implements ContentHandler { +class XmlContentHandler implements ContentHandler, FieldTypeResolver { private final DocumentBuilder documentBuilder; @@ -146,6 +146,11 @@ public String getUndocumentedContent(List fieldDescriptors) { return null; } + @Override + public FieldTypeResolver getFieldTypeResolver() { + return this; + } + private void removeLeafNodes(List candidates) { boolean changed = true; while (changed) { diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java new file mode 100644 index 000000000..44ea646ae --- /dev/null +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java @@ -0,0 +1,51 @@ +/* + * 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. + * 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.payload; + +import org.junit.Test; + +import org.springframework.http.MediaType; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * Tests for {@link FieldTypeResolver}. + * + * @author Mathias Düsterhöft + */ +public class FieldTypeResolverTests { + + @Test + public void returnJsonFieldTypeResolver() { + assertThat(FieldTypeResolver.create("{\"field\": \"value\"}".getBytes(), + MediaType.APPLICATION_JSON)).isInstanceOf(JsonFieldTypeResolver.class); + } + + @Test + public void returnXmlContentHandler() { + assertThat(FieldTypeResolver.create("5".getBytes(), + MediaType.APPLICATION_XML)).isInstanceOf(XmlContentHandler.class); + } + + @Test + public void throwOnInvalidContent() { + assertThatThrownBy(() -> FieldTypeResolver.create("some".getBytes(), + MediaType.APPLICATION_XML)).isInstanceOf(PayloadHandlingException.class); + } + +} diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java index bfb6eb8fa..aa153674c 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java @@ -29,75 +29,13 @@ * Tests for {@link JsonContentHandler}. * * @author Andy Wilkinson + * @author Mathias Düsterhöft */ public class JsonContentHandlerTests { @Rule public ExpectedException thrown = ExpectedException.none(); - @Test - public void typeForFieldWithNullValueMustMatch() { - this.thrown.expect(FieldTypesDoNotMatchException.class); - new JsonContentHandler("{\"a\": null}".getBytes()) - .determineFieldType(new FieldDescriptor("a").type(JsonFieldType.STRING)); - } - - @Test - public void typeForFieldWithNotNullAndThenNullValueMustMatch() { - this.thrown.expect(FieldTypesDoNotMatchException.class); - new JsonContentHandler("{\"a\":[{\"id\":1},{\"id\":null}]}".getBytes()) - .determineFieldType( - new FieldDescriptor("a[].id").type(JsonFieldType.STRING)); - } - - @Test - public void typeForFieldWithNullAndThenNotNullValueMustMatch() { - this.thrown.expect(FieldTypesDoNotMatchException.class); - new JsonContentHandler("{\"a\":[{\"id\":null},{\"id\":1}]}".getBytes()) - .determineFieldType( - new FieldDescriptor("a.[].id").type(JsonFieldType.STRING)); - } - - @Test - public void typeForOptionalFieldWithNumberAndThenNullValueIsNumber() { - Object fieldType = new JsonContentHandler( - "{\"a\":[{\"id\":1},{\"id\":null}]}\"".getBytes()) - .determineFieldType(new FieldDescriptor("a[].id").optional()); - assertThat((JsonFieldType) fieldType).isEqualTo(JsonFieldType.NUMBER); - } - - @Test - public void typeForOptionalFieldWithNullAndThenNumberIsNumber() { - Object fieldType = new JsonContentHandler( - "{\"a\":[{\"id\":null},{\"id\":1}]}".getBytes()) - .determineFieldType(new FieldDescriptor("a[].id").optional()); - assertThat((JsonFieldType) fieldType).isEqualTo(JsonFieldType.NUMBER); - } - - @Test - public void typeForFieldWithNumberAndThenNullValueIsVaries() { - Object fieldType = new JsonContentHandler( - "{\"a\":[{\"id\":1},{\"id\":null}]}\"".getBytes()) - .determineFieldType(new FieldDescriptor("a[].id")); - assertThat((JsonFieldType) fieldType).isEqualTo(JsonFieldType.VARIES); - } - - @Test - public void typeForFieldWithNullAndThenNumberIsVaries() { - Object fieldType = new JsonContentHandler( - "{\"a\":[{\"id\":null},{\"id\":1}]}".getBytes()) - .determineFieldType(new FieldDescriptor("a[].id")); - assertThat((JsonFieldType) fieldType).isEqualTo(JsonFieldType.VARIES); - } - - @Test - public void typeForOptionalFieldWithNullValueCanBeProvidedExplicitly() { - Object fieldType = new JsonContentHandler("{\"a\": null}".getBytes()) - .determineFieldType( - new FieldDescriptor("a").type(JsonFieldType.STRING).optional()); - assertThat((JsonFieldType) fieldType).isEqualTo(JsonFieldType.STRING); - } - @Test public void failsFastWithNonJsonContent() { this.thrown.expect(PayloadHandlingException.class); diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java index 3ebb74cf5..121ca958a 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java @@ -31,14 +31,71 @@ * Tests for {@link JsonFieldTypeResolver}. * * @author Andy Wilkinson + * @author Mathias Düsterhöft */ public class JsonFieldTypeResolverTests { - private final JsonFieldTypeResolver fieldTypeResolver = new JsonFieldTypeResolver(); - @Rule public ExpectedException thrownException = ExpectedException.none(); + @Test + public void typeForFieldWithNullValueMustMatch() throws IOException { + this.thrownException.expect(FieldTypesDoNotMatchException.class); + determineFieldType("{\"a\": null}", + new FieldDescriptor("a").type(JsonFieldType.STRING)); + } + + @Test + public void typeForFieldWithNotNullAndThenNullValueMustMatch() throws IOException { + this.thrownException.expect(FieldTypesDoNotMatchException.class); + determineFieldType("{\"a\":[{\"id\":1},{\"id\":null}]}", + new FieldDescriptor("a[].id").type(JsonFieldType.STRING)); + } + + @Test + public void typeForFieldWithNullAndThenNotNullValueMustMatch() throws IOException { + this.thrownException.expect(FieldTypesDoNotMatchException.class); + determineFieldType("{\"a\":[{\"id\":null},{\"id\":1}]}", + new FieldDescriptor("a.[].id").type(JsonFieldType.STRING)); + } + + @Test + public void typeForOptionalFieldWithNumberAndThenNullValueIsNumber() + throws IOException { + Object fieldType = determineFieldType("{\"a\":[{\"id\":1},{\"id\":null}]}\"", + new FieldDescriptor("a[].id").optional()); + assertThat(fieldType).isEqualTo(JsonFieldType.NUMBER); + } + + @Test + public void typeForOptionalFieldWithNullAndThenNumberIsNumber() throws IOException { + Object fieldType = determineFieldType("{\"a\":[{\"id\":null},{\"id\":1}]}", + new FieldDescriptor("a[].id").optional()); + assertThat(fieldType).isEqualTo(JsonFieldType.NUMBER); + } + + @Test + public void typeForFieldWithNumberAndThenNullValueIsVaries() throws IOException { + Object fieldType = determineFieldType("{\"a\":[{\"id\":1},{\"id\":null}]}\"", + new FieldDescriptor("a[].id")); + assertThat(fieldType).isEqualTo(JsonFieldType.VARIES); + } + + @Test + public void typeForFieldWithNullAndThenNumberIsVaries() throws IOException { + Object fieldType = determineFieldType("{\"a\":[{\"id\":null},{\"id\":1}]}", + new FieldDescriptor("a[].id")); + assertThat(fieldType).isEqualTo(JsonFieldType.VARIES); + } + + @Test + public void typeForOptionalFieldWithNullValueCanBeProvidedExplicitly() + throws IOException { + Object fieldType = determineFieldType("{\"a\": null}", + new FieldDescriptor("a").type(JsonFieldType.STRING).optional()); + assertThat(fieldType).isEqualTo(JsonFieldType.STRING); + } + @Test public void arrayField() throws IOException { assertFieldType(JsonFieldType.ARRAY, "[]"); @@ -46,31 +103,28 @@ public void arrayField() throws IOException { @Test public void topLevelArray() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("[]"), - new ObjectMapper().readValue("[{\"a\":\"alpha\"}]", List.class))) - .isEqualTo(JsonFieldType.ARRAY); + assertThat(new JsonFieldTypeResolver( + new ObjectMapper().readValue("[{\"a\":\"alpha\"}]", List.class)) + .resolveFieldType(new FieldDescriptor("[]"))) + .isEqualTo(JsonFieldType.ARRAY); } @Test public void nestedArray() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[]"), - createPayload("{\"a\": [{\"b\":\"bravo\"}]}"))) - .isEqualTo(JsonFieldType.ARRAY); + assertThat(resolveFieldType("{\"a\": [{\"b\":\"bravo\"}]}", "a[]")) + .isEqualTo(JsonFieldType.ARRAY); } @Test public void arrayNestedBeneathAnArray() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].b[]"), - createPayload("{\"a\": [{\"b\": [ 1, 2 ]}]}"))) - .isEqualTo(JsonFieldType.ARRAY); + assertThat(resolveFieldType("{\"a\": [{\"b\": [ 1, 2 ]}]}", "a[].b[]")) + .isEqualTo(JsonFieldType.ARRAY); } @Test public void specificFieldOfObjectInArrayNestedBeneathAnArray() throws IOException { - assertThat( - this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].b[].c"), - createPayload("{\"a\": [{\"b\": [ {\"c\": 5}, {\"c\": 5}]}]}"))) - .isEqualTo(JsonFieldType.NUMBER); + assertThat(resolveFieldType("{\"a\": [{\"b\": [ {\"c\": 5}, {\"c\": 5}]}]}", + "a[].b[].c")).isEqualTo(JsonFieldType.NUMBER); } @Test @@ -100,101 +154,91 @@ public void stringField() throws IOException { @Test public void nestedField() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.b.c"), - createPayload("{\"a\":{\"b\":{\"c\":{}}}}"))) + assertThat(fieldTypeResolver("{\"a\":{\"b\":{\"c\":{}}}}") + .resolveFieldType(new FieldDescriptor("a.b.c"))) .isEqualTo(JsonFieldType.OBJECT); } @Test public void multipleFieldsWithSameType() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), - createPayload("{\"a\":[{\"id\":1},{\"id\":2}]}"))) + assertThat(fieldTypeResolver("{\"a\":[{\"id\":1},{\"id\":2}]}") + .resolveFieldType(new FieldDescriptor("a[].id"))) .isEqualTo(JsonFieldType.NUMBER); } @Test public void multipleFieldsWithDifferentTypes() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), - createPayload("{\"a\":[{\"id\":1},{\"id\":true}]}"))) + assertThat(fieldTypeResolver("{\"a\":[{\"id\":1},{\"id\":true}]}") + .resolveFieldType(new FieldDescriptor("a[].id"))) .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWithDifferentTypesAndSometimesAbsent() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), - createPayload("{\"a\":[{\"id\":1},{\"id\":true}, { }]}"))) - .isEqualTo(JsonFieldType.VARIES); + assertThat(resolveFieldType("{\"a\":[{\"id\":1},{\"id\":true}, { }]}", "a[].id")) + .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWithDifferentTypesAndSometimesAbsentWhenOptionalResolvesToVaries() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType( - new FieldDescriptor("a[].id").optional(), - createPayload("{\"a\":[{\"id\":1},{\"id\":true}, { }]}"))) + assertThat(fieldTypeResolver("{\"a\":[{\"id\":1},{\"id\":true}, { }]}") + .resolveFieldType(new FieldDescriptor("a[].id").optional())) .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWhenSometimesAbsent() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), - createPayload("{\"a\":[{\"id\":1},{ }]}"))) - .isEqualTo(JsonFieldType.NUMBER); + assertThat(resolveFieldType("{\"a\":[{\"id\":1},{ }]}", "a[].id")) + .isEqualTo(JsonFieldType.NUMBER); } @Test public void multipleFieldsWithDifferentTypesAndSometimesNull() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), - createPayload("{\"a\":[{\"id\":1},{\"id\":true}, {\"id\":null}]}"))) - .isEqualTo(JsonFieldType.VARIES); + assertThat(resolveFieldType("{\"a\":[{\"id\":1},{\"id\":true}, {\"id\":null}]}", + "a[].id")).isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWhenNotNullThenNullWhenRequiredHasVariesType() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), - createPayload("{\"a\":[{\"id\":1},{\"id\":null}]}"))) - .isEqualTo(JsonFieldType.VARIES); + assertThat(resolveFieldType("{\"a\":[{\"id\":1},{\"id\":null}]}", "a[].id")) + .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWhenNotNullThenNullWhenOptionalHasSpecificType() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType( - new FieldDescriptor("a[].id").optional(), - createPayload("{\"a\":[{\"id\":1},{\"id\":null}]}"))) + assertThat(fieldTypeResolver("{\"a\":[{\"id\":1},{\"id\":null}]}") + .resolveFieldType(new FieldDescriptor("a[].id").optional())) .isEqualTo(JsonFieldType.NUMBER); } @Test public void multipleFieldsWhenNullThenNotNullWhenRequiredHasVariesType() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), - createPayload("{\"a\":[{\"id\":null},{\"id\":1}]}"))) - .isEqualTo(JsonFieldType.VARIES); + assertThat(resolveFieldType("{\"a\":[{\"id\":null},{\"id\":1}]}", "a[].id")) + .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWhenNullThenNotNullWhenOptionalHasSpecificType() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType( - new FieldDescriptor("a[].id").optional(), - createPayload("{\"a\":[{\"id\":null},{\"id\":1}]}"))) + assertThat(fieldTypeResolver("{\"a\":[{\"id\":null},{\"id\":1}]}") + .resolveFieldType(new FieldDescriptor("a[].id").optional())) .isEqualTo(JsonFieldType.NUMBER); } @Test public void multipleFieldsWhenEitherNullOrAbsent() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), - createPayload("{\"a\":[{},{\"id\":null}]}"))) - .isEqualTo(JsonFieldType.NULL); + assertThat(resolveFieldType("{\"a\":[{},{\"id\":null}]}", "a[].id")) + .isEqualTo(JsonFieldType.NULL); } @Test public void multipleFieldsThatAreAllNull() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), - createPayload("{\"a\":[{\"id\":null},{\"id\":null}]}"))) - .isEqualTo(JsonFieldType.NULL); + assertThat(resolveFieldType("{\"a\":[{\"id\":null},{\"id\":null}]}", "a[].id")) + .isEqualTo(JsonFieldType.NULL); } @Test @@ -203,8 +247,7 @@ public void nonExistentSingleFieldProducesFieldDoesNotExistException() this.thrownException.expect(FieldDoesNotExistException.class); this.thrownException.expectMessage( "The payload does not contain a field with the path 'a.b'"); - this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.b"), - createPayload("{\"a\":{}}")); + resolveFieldType("{\"a\":{}}", "a.b"); } @Test @@ -213,42 +256,38 @@ public void nonExistentMultipleFieldsProducesFieldDoesNotExistException() this.thrownException.expect(FieldDoesNotExistException.class); this.thrownException.expectMessage( "The payload does not contain a field with the path 'a[].b'"); - this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].b"), - createPayload("{\"a\":[{\"c\":1},{\"c\":2}]}")); + resolveFieldType("{\"a\":[{\"c\":1},{\"c\":2}]}", "a[].b"); } @Test public void leafWildcardWithCommonType() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.*"), - createPayload("{\"a\": {\"b\": 5, \"c\": 6}}"))) - .isEqualTo(JsonFieldType.NUMBER); + assertThat(resolveFieldType("{\"a\": {\"b\": 5, \"c\": 6}}", "a.*")) + .isEqualTo(JsonFieldType.NUMBER); } @Test public void leafWildcardWithVaryingType() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.*"), - createPayload("{\"a\": {\"b\": 5, \"c\": \"six\"}}"))) - .isEqualTo(JsonFieldType.VARIES); + assertThat(resolveFieldType("{\"a\": {\"b\": 5, \"c\": \"six\"}}", "a.*")) + .isEqualTo(JsonFieldType.VARIES); } @Test public void intermediateWildcardWithCommonType() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.*.d"), - createPayload("{\"a\": {\"b\": {\"d\": 4}, \"c\": {\"d\": 5}}}}"))) - .isEqualTo(JsonFieldType.NUMBER); + assertThat(resolveFieldType("{\"a\": {\"b\": {\"d\": 4}, \"c\": {\"d\": 5}}}}", + "a.*.d")).isEqualTo(JsonFieldType.NUMBER); } @Test public void intermediateWildcardWithVaryingType() throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.*.d"), - createPayload("{\"a\": {\"b\": {\"d\": 4}, \"c\": {\"d\": \"four\"}}}}"))) + assertThat(resolveFieldType( + "{\"a\": {\"b\": {\"d\": 4}, \"c\": {\"d\": \"four\"}}}}", "a.*.d")) .isEqualTo(JsonFieldType.VARIES); } private void assertFieldType(JsonFieldType expectedType, String jsonValue) throws IOException { - assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("field"), - createSimplePayload(jsonValue))).isEqualTo(expectedType); + assertThat(new JsonFieldTypeResolver(createSimplePayload(jsonValue)) + .resolveFieldType(new FieldDescriptor("field"))).isEqualTo(expectedType); } private Map createSimplePayload(String value) throws IOException { @@ -260,4 +299,18 @@ private Map createPayload(String json) throws IOException { return new ObjectMapper().readValue(json, Map.class); } + private Object determineFieldType(String json, FieldDescriptor fieldDescriptor) + throws IOException { + return new JsonFieldTypeResolver(createPayload(json)) + .determineFieldType(fieldDescriptor); + } + + private JsonFieldTypeResolver fieldTypeResolver(String json) throws IOException { + return new JsonFieldTypeResolver(createPayload(json)); + } + + private JsonFieldType resolveFieldType(String json, String path) throws IOException { + return fieldTypeResolver(json).resolveFieldType(new FieldDescriptor(path)); + } + } From 61fe2fdafc6c0323f44c69dac73e431759443560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20D=C3=BCsterh=C3=B6ft?= Date: Thu, 4 Oct 2018 08:52:19 +0200 Subject: [PATCH 2/3] Apply review hints. --- .../payload/ContentTypeHandlerFactory.java | 2 +- .../restdocs/payload/FieldTypeResolver.java | 5 +++-- .../restdocs/payload/FieldTypeResolverTests.java | 16 ++++++++++------ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java index 2831f5222..c02956b21 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * Copyright 2014-2018 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. diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java index 5616ca0b7..0c8395a9f 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * Copyright 2014-2018 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. @@ -23,6 +23,7 @@ * payloads. * * @author Mathias Düsterhöft + * @since 2.0.3 */ public interface FieldTypeResolver { @@ -32,7 +33,7 @@ public interface FieldTypeResolver { * @param contentType the content type of the payload * @return the {@link FieldTypeResolver} */ - static FieldTypeResolver create(byte[] content, MediaType contentType) { + static FieldTypeResolver forContent(byte[] content, MediaType contentType) { return ContentTypeHandlerFactory.create(content, contentType) .getFieldTypeResolver(); } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java index 44ea646ae..ef7988236 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * Copyright 2014-2018 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. @@ -16,12 +16,13 @@ package org.springframework.restdocs.payload; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.springframework.http.MediaType; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * Tests for {@link FieldTypeResolver}. @@ -30,22 +31,25 @@ */ public class FieldTypeResolverTests { + @Rule + public ExpectedException thrownException = ExpectedException.none(); + @Test public void returnJsonFieldTypeResolver() { - assertThat(FieldTypeResolver.create("{\"field\": \"value\"}".getBytes(), + assertThat(FieldTypeResolver.forContent("{\"field\": \"value\"}".getBytes(), MediaType.APPLICATION_JSON)).isInstanceOf(JsonFieldTypeResolver.class); } @Test public void returnXmlContentHandler() { - assertThat(FieldTypeResolver.create("5".getBytes(), + assertThat(FieldTypeResolver.forContent("5".getBytes(), MediaType.APPLICATION_XML)).isInstanceOf(XmlContentHandler.class); } @Test public void throwOnInvalidContent() { - assertThatThrownBy(() -> FieldTypeResolver.create("some".getBytes(), - MediaType.APPLICATION_XML)).isInstanceOf(PayloadHandlingException.class); + this.thrownException.expect(PayloadHandlingException.class); + FieldTypeResolver.forContent("some".getBytes(), MediaType.APPLICATION_XML); } } From bc96ffd79b9e46424133743a909393521c2ddfcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20D=C3=BCsterh=C3=B6ft?= Date: Thu, 4 Oct 2018 21:37:45 +0200 Subject: [PATCH 3/3] Keep separation of concerns of JsonContentHandler and JsonFieldTypeResolver. --- .../payload/AbstractFieldsSnippet.java | 6 +- .../restdocs/payload/ContentHandler.java | 28 ++- .../payload/ContentTypeHandlerFactory.java | 67 ------- .../restdocs/payload/FieldTypeResolver.java | 5 +- .../restdocs/payload/JsonContentHandler.java | 36 +++- .../payload/JsonFieldTypeResolver.java | 37 +--- .../restdocs/payload/XmlContentHandler.java | 9 +- .../payload/FieldTypeResolverTests.java | 2 +- .../payload/JsonContentHandlerTests.java | 63 ++++++ .../payload/JsonFieldTypeResolverTests.java | 189 +++++++----------- .../payload/XmlContentHandlerTests.java | 1 + 11 files changed, 195 insertions(+), 248 deletions(-) delete mode 100644 spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java index 5c595fab4..990cd2bb6 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/AbstractFieldsSnippet.java @@ -161,8 +161,7 @@ protected Map createModel(Operation operation) { content = verifyContent( this.subsectionExtractor.extractSubsection(content, contentType)); } - ContentHandler contentHandler = ContentTypeHandlerFactory.create(content, - contentType); + ContentHandler contentHandler = ContentHandler.forContent(content, contentType); validateFieldDocumentation(contentHandler); @@ -170,8 +169,7 @@ protected Map createModel(Operation operation) { for (FieldDescriptor descriptor : this.fieldDescriptors) { if (!descriptor.isIgnored()) { try { - Object type = contentHandler.getFieldTypeResolver() - .determineFieldType(descriptor); + Object type = contentHandler.resolveFieldType(descriptor); descriptorsToDocument.add(copyWithType(descriptor, type)); } catch (FieldDoesNotExistException ex) { diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentHandler.java index 09b95611e..9349ee88c 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentHandler.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentHandler.java @@ -18,13 +18,15 @@ import java.util.List; +import org.springframework.http.MediaType; + /** * A handler for the content of a request or response. * * @author Andy Wilkinson * @author Mathias Düsterhöft */ -interface ContentHandler { +interface ContentHandler extends FieldTypeResolver { /** * Finds the fields that are missing from the handler's payload. A field is missing if @@ -49,10 +51,26 @@ interface ContentHandler { String getUndocumentedContent(List fieldDescriptors); /** - * Return a {@link FieldTypeResolver} that can be used for the content type this - * ContentHandler can process. - * @return a {@link FieldTypeResolver} + * Create a {@link ContentHandler} for the given content type and payload. + * @param content the payload + * @param contentType the content type + * @return the ContentHandler + * @throws PayloadHandlingException if no known ContentHandler can handle the content */ - FieldTypeResolver getFieldTypeResolver(); + static ContentHandler forContent(byte[] content, MediaType contentType) { + + try { + return new JsonContentHandler(content); + } + catch (Exception je) { + try { + return new XmlContentHandler(content); + } + catch (Exception xe) { + throw new PayloadHandlingException("Cannot handle " + contentType + + " content as it could not be parsed as JSON or XML"); + } + } + } } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java deleted file mode 100644 index c02956b21..000000000 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ContentTypeHandlerFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2014-2018 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.payload; - -import org.springframework.http.MediaType; - -/** - * Factory providing access to {@link ContentHandler} implementation for the content type. - * - * @author Mathias Düsterhöft - */ -final class ContentTypeHandlerFactory { - - private ContentTypeHandlerFactory() { - } - - /** - * Create a {@link ContentHandler} for the given content type and payload. - * @param content the payload - * @param contentType the content type - * @return the ContentHandler - */ - static ContentHandler create(byte[] content, MediaType contentType) { - ContentHandler contentHandler = createJsonContentHandler(content); - if (contentHandler == null) { - contentHandler = createXmlContentHandler(content); - if (contentHandler == null) { - throw new PayloadHandlingException("Cannot handle " + contentType - + " content as it could not be parsed as JSON or XML"); - } - } - return contentHandler; - } - - private static ContentHandler createJsonContentHandler(byte[] content) { - try { - return new JsonContentHandler(content); - } - catch (Exception ex) { - return null; - } - } - - private static ContentHandler createXmlContentHandler(byte[] content) { - try { - return new XmlContentHandler(content); - } - catch (Exception ex) { - return null; - } - } - -} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java index 0c8395a9f..af7aa8596 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/FieldTypeResolver.java @@ -34,8 +34,7 @@ public interface FieldTypeResolver { * @return the {@link FieldTypeResolver} */ static FieldTypeResolver forContent(byte[] content, MediaType contentType) { - return ContentTypeHandlerFactory.create(content, contentType) - .getFieldTypeResolver(); + return ContentHandler.forContent(content, contentType); } /** @@ -44,6 +43,6 @@ static FieldTypeResolver forContent(byte[] content, MediaType contentType) { * @param fieldDescriptor the field descriptor * @return the type of the field */ - Object determineFieldType(FieldDescriptor fieldDescriptor); + Object resolveFieldType(FieldDescriptor fieldDescriptor); } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java index 6099c703b..158ec5d98 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonContentHandler.java @@ -32,11 +32,14 @@ * A {@link ContentHandler} for JSON content. * * @author Andy Wilkinson + * @author Mathias Düsterhöft */ -class JsonContentHandler implements ContentHandler { +class JsonContentHandler implements ContentHandler, FieldTypeResolver { private final JsonFieldProcessor fieldProcessor = new JsonFieldProcessor(); + private final JsonFieldTypeResolver fieldTypeResolver = new JsonFieldTypeResolver(); + private final ObjectMapper objectMapper = new ObjectMapper() .enable(SerializationFeature.INDENT_OUTPUT); @@ -122,11 +125,6 @@ public String getUndocumentedContent(List fieldDescriptors) { return null; } - @Override - public FieldTypeResolver getFieldTypeResolver() { - return new JsonFieldTypeResolver(readContent()); - } - private boolean describesSubsection(FieldDescriptor fieldDescriptor) { return fieldDescriptor instanceof SubsectionDescriptor; } @@ -147,4 +145,30 @@ private boolean isEmpty(Object object) { return ((List) object).isEmpty(); } + @Override + public Object resolveFieldType(FieldDescriptor fieldDescriptor) { + if (fieldDescriptor.getType() == null) { + return this.fieldTypeResolver.resolveFieldType(fieldDescriptor, + readContent()); + } + if (!(fieldDescriptor.getType() instanceof JsonFieldType)) { + return fieldDescriptor.getType(); + } + JsonFieldType descriptorFieldType = (JsonFieldType) fieldDescriptor.getType(); + try { + JsonFieldType actualFieldType = this.fieldTypeResolver + .resolveFieldType(fieldDescriptor, readContent()); + if (descriptorFieldType == JsonFieldType.VARIES + || descriptorFieldType == actualFieldType + || (fieldDescriptor.isOptional() + && actualFieldType == JsonFieldType.NULL)) { + return descriptorFieldType; + } + throw new FieldTypesDoNotMatchException(fieldDescriptor, actualFieldType); + } + catch (FieldDoesNotExistException ex) { + return fieldDescriptor.getType(); + } + } + } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java index 8f569b2cc..a577bc654 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/JsonFieldTypeResolver.java @@ -26,45 +26,14 @@ * Resolves the type of a field in a JSON request or response payload. * * @author Andy Wilkinson - * @author Mathias Düsterhöft */ -class JsonFieldTypeResolver implements FieldTypeResolver { - - private final Object content; +class JsonFieldTypeResolver { private final JsonFieldProcessor fieldProcessor = new JsonFieldProcessor(); - JsonFieldTypeResolver(Object content) { - this.content = content; - } - - @Override - public Object determineFieldType(FieldDescriptor fieldDescriptor) { - if (fieldDescriptor.getType() == null) { - return resolveFieldType(fieldDescriptor); - } - if (!(fieldDescriptor.getType() instanceof JsonFieldType)) { - return fieldDescriptor.getType(); - } - JsonFieldType descriptorFieldType = (JsonFieldType) fieldDescriptor.getType(); - try { - JsonFieldType actualFieldType = resolveFieldType(fieldDescriptor); - if (descriptorFieldType == JsonFieldType.VARIES - || descriptorFieldType == actualFieldType - || (fieldDescriptor.isOptional() - && actualFieldType == JsonFieldType.NULL)) { - return descriptorFieldType; - } - throw new FieldTypesDoNotMatchException(fieldDescriptor, actualFieldType); - } - catch (FieldDoesNotExistException ex) { - return fieldDescriptor.getType(); - } - } - - JsonFieldType resolveFieldType(FieldDescriptor fieldDescriptor) { + JsonFieldType resolveFieldType(FieldDescriptor fieldDescriptor, Object payload) { ExtractedField extractedField = this.fieldProcessor - .extract(fieldDescriptor.getPath(), this.content); + .extract(fieldDescriptor.getPath(), payload); Object value = extractedField.getValue(); if (value instanceof Collection && extractedField.getType() == PathType.MULTI) { JsonFieldType commonType = null; diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java index 0e845a477..c82ebb782 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/XmlContentHandler.java @@ -47,7 +47,7 @@ * * @author Andy Wilkinson */ -class XmlContentHandler implements ContentHandler, FieldTypeResolver { +class XmlContentHandler implements ContentHandler { private final DocumentBuilder documentBuilder; @@ -146,11 +146,6 @@ public String getUndocumentedContent(List fieldDescriptors) { return null; } - @Override - public FieldTypeResolver getFieldTypeResolver() { - return this; - } - private void removeLeafNodes(List candidates) { boolean changed = true; while (changed) { @@ -195,7 +190,7 @@ private String prettyPrint(Document document) { } @Override - public Object determineFieldType(FieldDescriptor fieldDescriptor) { + public Object resolveFieldType(FieldDescriptor fieldDescriptor) { if (fieldDescriptor.getType() != null) { return fieldDescriptor.getType(); } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java index ef7988236..0ed8780c4 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/FieldTypeResolverTests.java @@ -37,7 +37,7 @@ public class FieldTypeResolverTests { @Test public void returnJsonFieldTypeResolver() { assertThat(FieldTypeResolver.forContent("{\"field\": \"value\"}".getBytes(), - MediaType.APPLICATION_JSON)).isInstanceOf(JsonFieldTypeResolver.class); + MediaType.APPLICATION_JSON)).isInstanceOf(JsonContentHandler.class); } @Test diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java index aa153674c..622bfb2a9 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonContentHandlerTests.java @@ -36,6 +36,69 @@ public class JsonContentHandlerTests { @Rule public ExpectedException thrown = ExpectedException.none(); + @Test + public void typeForFieldWithNullValueMustMatch() { + this.thrown.expect(FieldTypesDoNotMatchException.class); + new JsonContentHandler("{\"a\": null}".getBytes()) + .resolveFieldType(new FieldDescriptor("a").type(JsonFieldType.STRING)); + } + + @Test + public void typeForFieldWithNotNullAndThenNullValueMustMatch() { + this.thrown.expect(FieldTypesDoNotMatchException.class); + new JsonContentHandler("{\"a\":[{\"id\":1},{\"id\":null}]}".getBytes()) + .resolveFieldType( + new FieldDescriptor("a[].id").type(JsonFieldType.STRING)); + } + + @Test + public void typeForFieldWithNullAndThenNotNullValueMustMatch() { + this.thrown.expect(FieldTypesDoNotMatchException.class); + new JsonContentHandler("{\"a\":[{\"id\":null},{\"id\":1}]}".getBytes()) + .resolveFieldType( + new FieldDescriptor("a.[].id").type(JsonFieldType.STRING)); + } + + @Test + public void typeForOptionalFieldWithNumberAndThenNullValueIsNumber() { + Object fieldType = new JsonContentHandler( + "{\"a\":[{\"id\":1},{\"id\":null}]}\"".getBytes()) + .resolveFieldType(new FieldDescriptor("a[].id").optional()); + assertThat((JsonFieldType) fieldType).isEqualTo(JsonFieldType.NUMBER); + } + + @Test + public void typeForOptionalFieldWithNullAndThenNumberIsNumber() { + Object fieldType = new JsonContentHandler( + "{\"a\":[{\"id\":null},{\"id\":1}]}".getBytes()) + .resolveFieldType(new FieldDescriptor("a[].id").optional()); + assertThat((JsonFieldType) fieldType).isEqualTo(JsonFieldType.NUMBER); + } + + @Test + public void typeForFieldWithNumberAndThenNullValueIsVaries() { + Object fieldType = new JsonContentHandler( + "{\"a\":[{\"id\":1},{\"id\":null}]}\"".getBytes()) + .resolveFieldType(new FieldDescriptor("a[].id")); + assertThat((JsonFieldType) fieldType).isEqualTo(JsonFieldType.VARIES); + } + + @Test + public void typeForFieldWithNullAndThenNumberIsVaries() { + Object fieldType = new JsonContentHandler( + "{\"a\":[{\"id\":null},{\"id\":1}]}".getBytes()) + .resolveFieldType(new FieldDescriptor("a[].id")); + assertThat((JsonFieldType) fieldType).isEqualTo(JsonFieldType.VARIES); + } + + @Test + public void typeForOptionalFieldWithNullValueCanBeProvidedExplicitly() { + Object fieldType = new JsonContentHandler("{\"a\": null}".getBytes()) + .resolveFieldType( + new FieldDescriptor("a").type(JsonFieldType.STRING).optional()); + assertThat((JsonFieldType) fieldType).isEqualTo(JsonFieldType.STRING); + } + @Test public void failsFastWithNonJsonContent() { this.thrown.expect(PayloadHandlingException.class); diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java index 121ca958a..3ebb74cf5 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/JsonFieldTypeResolverTests.java @@ -31,71 +31,14 @@ * Tests for {@link JsonFieldTypeResolver}. * * @author Andy Wilkinson - * @author Mathias Düsterhöft */ public class JsonFieldTypeResolverTests { + private final JsonFieldTypeResolver fieldTypeResolver = new JsonFieldTypeResolver(); + @Rule public ExpectedException thrownException = ExpectedException.none(); - @Test - public void typeForFieldWithNullValueMustMatch() throws IOException { - this.thrownException.expect(FieldTypesDoNotMatchException.class); - determineFieldType("{\"a\": null}", - new FieldDescriptor("a").type(JsonFieldType.STRING)); - } - - @Test - public void typeForFieldWithNotNullAndThenNullValueMustMatch() throws IOException { - this.thrownException.expect(FieldTypesDoNotMatchException.class); - determineFieldType("{\"a\":[{\"id\":1},{\"id\":null}]}", - new FieldDescriptor("a[].id").type(JsonFieldType.STRING)); - } - - @Test - public void typeForFieldWithNullAndThenNotNullValueMustMatch() throws IOException { - this.thrownException.expect(FieldTypesDoNotMatchException.class); - determineFieldType("{\"a\":[{\"id\":null},{\"id\":1}]}", - new FieldDescriptor("a.[].id").type(JsonFieldType.STRING)); - } - - @Test - public void typeForOptionalFieldWithNumberAndThenNullValueIsNumber() - throws IOException { - Object fieldType = determineFieldType("{\"a\":[{\"id\":1},{\"id\":null}]}\"", - new FieldDescriptor("a[].id").optional()); - assertThat(fieldType).isEqualTo(JsonFieldType.NUMBER); - } - - @Test - public void typeForOptionalFieldWithNullAndThenNumberIsNumber() throws IOException { - Object fieldType = determineFieldType("{\"a\":[{\"id\":null},{\"id\":1}]}", - new FieldDescriptor("a[].id").optional()); - assertThat(fieldType).isEqualTo(JsonFieldType.NUMBER); - } - - @Test - public void typeForFieldWithNumberAndThenNullValueIsVaries() throws IOException { - Object fieldType = determineFieldType("{\"a\":[{\"id\":1},{\"id\":null}]}\"", - new FieldDescriptor("a[].id")); - assertThat(fieldType).isEqualTo(JsonFieldType.VARIES); - } - - @Test - public void typeForFieldWithNullAndThenNumberIsVaries() throws IOException { - Object fieldType = determineFieldType("{\"a\":[{\"id\":null},{\"id\":1}]}", - new FieldDescriptor("a[].id")); - assertThat(fieldType).isEqualTo(JsonFieldType.VARIES); - } - - @Test - public void typeForOptionalFieldWithNullValueCanBeProvidedExplicitly() - throws IOException { - Object fieldType = determineFieldType("{\"a\": null}", - new FieldDescriptor("a").type(JsonFieldType.STRING).optional()); - assertThat(fieldType).isEqualTo(JsonFieldType.STRING); - } - @Test public void arrayField() throws IOException { assertFieldType(JsonFieldType.ARRAY, "[]"); @@ -103,28 +46,31 @@ public void arrayField() throws IOException { @Test public void topLevelArray() throws IOException { - assertThat(new JsonFieldTypeResolver( - new ObjectMapper().readValue("[{\"a\":\"alpha\"}]", List.class)) - .resolveFieldType(new FieldDescriptor("[]"))) - .isEqualTo(JsonFieldType.ARRAY); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("[]"), + new ObjectMapper().readValue("[{\"a\":\"alpha\"}]", List.class))) + .isEqualTo(JsonFieldType.ARRAY); } @Test public void nestedArray() throws IOException { - assertThat(resolveFieldType("{\"a\": [{\"b\":\"bravo\"}]}", "a[]")) - .isEqualTo(JsonFieldType.ARRAY); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[]"), + createPayload("{\"a\": [{\"b\":\"bravo\"}]}"))) + .isEqualTo(JsonFieldType.ARRAY); } @Test public void arrayNestedBeneathAnArray() throws IOException { - assertThat(resolveFieldType("{\"a\": [{\"b\": [ 1, 2 ]}]}", "a[].b[]")) - .isEqualTo(JsonFieldType.ARRAY); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].b[]"), + createPayload("{\"a\": [{\"b\": [ 1, 2 ]}]}"))) + .isEqualTo(JsonFieldType.ARRAY); } @Test public void specificFieldOfObjectInArrayNestedBeneathAnArray() throws IOException { - assertThat(resolveFieldType("{\"a\": [{\"b\": [ {\"c\": 5}, {\"c\": 5}]}]}", - "a[].b[].c")).isEqualTo(JsonFieldType.NUMBER); + assertThat( + this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].b[].c"), + createPayload("{\"a\": [{\"b\": [ {\"c\": 5}, {\"c\": 5}]}]}"))) + .isEqualTo(JsonFieldType.NUMBER); } @Test @@ -154,91 +100,101 @@ public void stringField() throws IOException { @Test public void nestedField() throws IOException { - assertThat(fieldTypeResolver("{\"a\":{\"b\":{\"c\":{}}}}") - .resolveFieldType(new FieldDescriptor("a.b.c"))) + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.b.c"), + createPayload("{\"a\":{\"b\":{\"c\":{}}}}"))) .isEqualTo(JsonFieldType.OBJECT); } @Test public void multipleFieldsWithSameType() throws IOException { - assertThat(fieldTypeResolver("{\"a\":[{\"id\":1},{\"id\":2}]}") - .resolveFieldType(new FieldDescriptor("a[].id"))) + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), + createPayload("{\"a\":[{\"id\":1},{\"id\":2}]}"))) .isEqualTo(JsonFieldType.NUMBER); } @Test public void multipleFieldsWithDifferentTypes() throws IOException { - assertThat(fieldTypeResolver("{\"a\":[{\"id\":1},{\"id\":true}]}") - .resolveFieldType(new FieldDescriptor("a[].id"))) + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), + createPayload("{\"a\":[{\"id\":1},{\"id\":true}]}"))) .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWithDifferentTypesAndSometimesAbsent() throws IOException { - assertThat(resolveFieldType("{\"a\":[{\"id\":1},{\"id\":true}, { }]}", "a[].id")) - .isEqualTo(JsonFieldType.VARIES); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), + createPayload("{\"a\":[{\"id\":1},{\"id\":true}, { }]}"))) + .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWithDifferentTypesAndSometimesAbsentWhenOptionalResolvesToVaries() throws IOException { - assertThat(fieldTypeResolver("{\"a\":[{\"id\":1},{\"id\":true}, { }]}") - .resolveFieldType(new FieldDescriptor("a[].id").optional())) + assertThat(this.fieldTypeResolver.resolveFieldType( + new FieldDescriptor("a[].id").optional(), + createPayload("{\"a\":[{\"id\":1},{\"id\":true}, { }]}"))) .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWhenSometimesAbsent() throws IOException { - assertThat(resolveFieldType("{\"a\":[{\"id\":1},{ }]}", "a[].id")) - .isEqualTo(JsonFieldType.NUMBER); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), + createPayload("{\"a\":[{\"id\":1},{ }]}"))) + .isEqualTo(JsonFieldType.NUMBER); } @Test public void multipleFieldsWithDifferentTypesAndSometimesNull() throws IOException { - assertThat(resolveFieldType("{\"a\":[{\"id\":1},{\"id\":true}, {\"id\":null}]}", - "a[].id")).isEqualTo(JsonFieldType.VARIES); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), + createPayload("{\"a\":[{\"id\":1},{\"id\":true}, {\"id\":null}]}"))) + .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWhenNotNullThenNullWhenRequiredHasVariesType() throws IOException { - assertThat(resolveFieldType("{\"a\":[{\"id\":1},{\"id\":null}]}", "a[].id")) - .isEqualTo(JsonFieldType.VARIES); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), + createPayload("{\"a\":[{\"id\":1},{\"id\":null}]}"))) + .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWhenNotNullThenNullWhenOptionalHasSpecificType() throws IOException { - assertThat(fieldTypeResolver("{\"a\":[{\"id\":1},{\"id\":null}]}") - .resolveFieldType(new FieldDescriptor("a[].id").optional())) + assertThat(this.fieldTypeResolver.resolveFieldType( + new FieldDescriptor("a[].id").optional(), + createPayload("{\"a\":[{\"id\":1},{\"id\":null}]}"))) .isEqualTo(JsonFieldType.NUMBER); } @Test public void multipleFieldsWhenNullThenNotNullWhenRequiredHasVariesType() throws IOException { - assertThat(resolveFieldType("{\"a\":[{\"id\":null},{\"id\":1}]}", "a[].id")) - .isEqualTo(JsonFieldType.VARIES); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), + createPayload("{\"a\":[{\"id\":null},{\"id\":1}]}"))) + .isEqualTo(JsonFieldType.VARIES); } @Test public void multipleFieldsWhenNullThenNotNullWhenOptionalHasSpecificType() throws IOException { - assertThat(fieldTypeResolver("{\"a\":[{\"id\":null},{\"id\":1}]}") - .resolveFieldType(new FieldDescriptor("a[].id").optional())) + assertThat(this.fieldTypeResolver.resolveFieldType( + new FieldDescriptor("a[].id").optional(), + createPayload("{\"a\":[{\"id\":null},{\"id\":1}]}"))) .isEqualTo(JsonFieldType.NUMBER); } @Test public void multipleFieldsWhenEitherNullOrAbsent() throws IOException { - assertThat(resolveFieldType("{\"a\":[{},{\"id\":null}]}", "a[].id")) - .isEqualTo(JsonFieldType.NULL); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), + createPayload("{\"a\":[{},{\"id\":null}]}"))) + .isEqualTo(JsonFieldType.NULL); } @Test public void multipleFieldsThatAreAllNull() throws IOException { - assertThat(resolveFieldType("{\"a\":[{\"id\":null},{\"id\":null}]}", "a[].id")) - .isEqualTo(JsonFieldType.NULL); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].id"), + createPayload("{\"a\":[{\"id\":null},{\"id\":null}]}"))) + .isEqualTo(JsonFieldType.NULL); } @Test @@ -247,7 +203,8 @@ public void nonExistentSingleFieldProducesFieldDoesNotExistException() this.thrownException.expect(FieldDoesNotExistException.class); this.thrownException.expectMessage( "The payload does not contain a field with the path 'a.b'"); - resolveFieldType("{\"a\":{}}", "a.b"); + this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.b"), + createPayload("{\"a\":{}}")); } @Test @@ -256,38 +213,42 @@ public void nonExistentMultipleFieldsProducesFieldDoesNotExistException() this.thrownException.expect(FieldDoesNotExistException.class); this.thrownException.expectMessage( "The payload does not contain a field with the path 'a[].b'"); - resolveFieldType("{\"a\":[{\"c\":1},{\"c\":2}]}", "a[].b"); + this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a[].b"), + createPayload("{\"a\":[{\"c\":1},{\"c\":2}]}")); } @Test public void leafWildcardWithCommonType() throws IOException { - assertThat(resolveFieldType("{\"a\": {\"b\": 5, \"c\": 6}}", "a.*")) - .isEqualTo(JsonFieldType.NUMBER); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.*"), + createPayload("{\"a\": {\"b\": 5, \"c\": 6}}"))) + .isEqualTo(JsonFieldType.NUMBER); } @Test public void leafWildcardWithVaryingType() throws IOException { - assertThat(resolveFieldType("{\"a\": {\"b\": 5, \"c\": \"six\"}}", "a.*")) - .isEqualTo(JsonFieldType.VARIES); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.*"), + createPayload("{\"a\": {\"b\": 5, \"c\": \"six\"}}"))) + .isEqualTo(JsonFieldType.VARIES); } @Test public void intermediateWildcardWithCommonType() throws IOException { - assertThat(resolveFieldType("{\"a\": {\"b\": {\"d\": 4}, \"c\": {\"d\": 5}}}}", - "a.*.d")).isEqualTo(JsonFieldType.NUMBER); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.*.d"), + createPayload("{\"a\": {\"b\": {\"d\": 4}, \"c\": {\"d\": 5}}}}"))) + .isEqualTo(JsonFieldType.NUMBER); } @Test public void intermediateWildcardWithVaryingType() throws IOException { - assertThat(resolveFieldType( - "{\"a\": {\"b\": {\"d\": 4}, \"c\": {\"d\": \"four\"}}}}", "a.*.d")) + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("a.*.d"), + createPayload("{\"a\": {\"b\": {\"d\": 4}, \"c\": {\"d\": \"four\"}}}}"))) .isEqualTo(JsonFieldType.VARIES); } private void assertFieldType(JsonFieldType expectedType, String jsonValue) throws IOException { - assertThat(new JsonFieldTypeResolver(createSimplePayload(jsonValue)) - .resolveFieldType(new FieldDescriptor("field"))).isEqualTo(expectedType); + assertThat(this.fieldTypeResolver.resolveFieldType(new FieldDescriptor("field"), + createSimplePayload(jsonValue))).isEqualTo(expectedType); } private Map createSimplePayload(String value) throws IOException { @@ -299,18 +260,4 @@ private Map createPayload(String json) throws IOException { return new ObjectMapper().readValue(json, Map.class); } - private Object determineFieldType(String json, FieldDescriptor fieldDescriptor) - throws IOException { - return new JsonFieldTypeResolver(createPayload(json)) - .determineFieldType(fieldDescriptor); - } - - private JsonFieldTypeResolver fieldTypeResolver(String json) throws IOException { - return new JsonFieldTypeResolver(createPayload(json)); - } - - private JsonFieldType resolveFieldType(String json, String path) throws IOException { - return fieldTypeResolver(json).resolveFieldType(new FieldDescriptor(path)); - } - } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/XmlContentHandlerTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/XmlContentHandlerTests.java index 904093b8c..511c86212 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/XmlContentHandlerTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/XmlContentHandlerTests.java @@ -30,6 +30,7 @@ * Tests for {@link XmlContentHandler}. * * @author Andy Wilkinson + * @author Mathias Düsterhöft */ public class XmlContentHandlerTests {