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 25c373cd..30b577e9 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 @@ -38,7 +38,7 @@ class JsonFieldTypeResolver { if (commonType == null) { commonType = fieldType; } - else if (fieldType != commonType) { + else if (fieldType != commonType && fieldType != JsonFieldType.NULL) { return JsonFieldType.VARIES; } } 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 e1ba3ec5..10d38d12 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 @@ -112,13 +112,73 @@ public class JsonFieldTypeResolverTests { } @Test - public void nonExistentFieldProducesIllegalArgumentException() throws IOException { + public void multipleFieldsWithDifferentTypesAndSometimesAbsent() throws IOException { + assertThat( + this.fieldTypeResolver.resolveFieldType("a[].id", + createPayload("{\"a\":[{\"id\":1},{\"id\":true}, { }]}")), + equalTo(JsonFieldType.VARIES)); + } + + @Test + public void multipleFieldsWhenSometimesAbsent() throws IOException { + assertThat( + this.fieldTypeResolver.resolveFieldType("a[].id", + createPayload("{\"a\":[{\"id\":1},{ }]}")), + equalTo(JsonFieldType.NUMBER)); + } + + @Test + public void multipleFieldsWithDifferentTypesAndSometimesNull() throws IOException { + assertThat( + this.fieldTypeResolver.resolveFieldType("a[].id", + createPayload( + "{\"a\":[{\"id\":1},{\"id\":true}, {\"id\":null}]}")), + equalTo(JsonFieldType.VARIES)); + } + + @Test + public void multipleFieldsWhenSometimesNull() throws IOException { + assertThat( + this.fieldTypeResolver.resolveFieldType("a[].id", + createPayload("{\"a\":[{\"id\":1},{\"id\":null}]}")), + equalTo(JsonFieldType.NUMBER)); + } + + @Test + public void multipleFieldsWhenEitherNullOrAbsent() throws IOException { + assertThat( + this.fieldTypeResolver.resolveFieldType("a[].id", + createPayload("{\"a\":[{},{\"id\":null}]}")), + equalTo(JsonFieldType.NULL)); + } + + @Test + public void multipleFieldsThatAreAllNull() throws IOException { + assertThat( + this.fieldTypeResolver.resolveFieldType("a[].id", + createPayload("{\"a\":[{\"id\":null},{\"id\":null}]}")), + equalTo(JsonFieldType.NULL)); + } + + @Test + public void nonExistentSingleFieldProducesFieldDoesNotExistException() + throws IOException { this.thrownException.expect(FieldDoesNotExistException.class); this.thrownException.expectMessage( "The payload does not contain a field with the path 'a.b'"); this.fieldTypeResolver.resolveFieldType("a.b", createPayload("{\"a\":{}}")); } + @Test + public void nonExistentMultipleFieldsProducesFieldDoesNotExistException() + throws IOException { + this.thrownException.expect(FieldDoesNotExistException.class); + this.thrownException.expectMessage( + "The payload does not contain a field with the path 'a[].b'"); + this.fieldTypeResolver.resolveFieldType("a[].b", + createPayload("{\"a\":[{\"c\":1},{\"c\":2}]}")); + } + private void assertFieldType(JsonFieldType expectedType, String jsonValue) throws IOException { assertThat(this.fieldTypeResolver.resolveFieldType("field", diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java index d1c56f3b..cf2ee2f3 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java @@ -368,6 +368,20 @@ public class RequestFieldsSnippetTests extends AbstractSnippetTests { .build()); } + @Test + public void requestWithArrayContainingFieldThatIsSometimesNull() throws IOException { + this.snippets.expectRequestFields() + .withContents(tableWithHeader("Path", "Type", "Description") + .row("`assets[].name`", "`String`", "one")); + new RequestFieldsSnippet(Arrays.asList(fieldWithPath("assets[].name") + .description("one").type(JsonFieldType.STRING))) + .document(this.operationBuilder.request("http://localhost") + .content("{\"assets\": [" + "{\"name\": \"sample1\"}, " + + "{\"name\": null}, " + + "{\"name\": \"sample2\"}]}") + .build()); + } + private String escapeIfNecessary(String input) { if (this.templateFormat.equals(TemplateFormats.markdown())) { return input; diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java index a7f2f047..1affb789 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java @@ -378,6 +378,20 @@ public class ResponseFieldsSnippetTests extends AbstractSnippetTests { .build()); } + @Test + public void responseWithArrayContainingFieldThatIsSometimesNull() throws IOException { + this.snippets.expectResponseFields() + .withContents(tableWithHeader("Path", "Type", "Description") + .row("`assets[].name`", "`String`", "one")); + new ResponseFieldsSnippet(Arrays.asList(fieldWithPath("assets[].name") + .description("one").type(JsonFieldType.STRING))) + .document(this.operationBuilder.response() + .content("{\"assets\": [" + "{\"name\": \"sample1\"}, " + + "{\"name\": null}, " + + "{\"name\": \"sample2\"}]}") + .build()); + } + private String escapeIfNecessary(String input) { if (this.templateFormat.equals(TemplateFormats.markdown())) { return input;