From 6bf1edcd09185ed9e3d5c87b5a517ecf09ed0c57 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Sat, 1 Jul 2017 10:50:01 +0100 Subject: [PATCH] Improve handling of null fields beneath an array Previously, if an array contained objects where a field was sometimes null and sometimes had a value of a consistent type, the type inferred type was varies. Furthermore, it was not possible for the user to specify a type other than varies as a mismatch would be detected. This commit updates JsonFieldTypeResolver so that, when dealing with an imprecise field path (i.e. a path for a field within an array), null values that don't match the common type for the field are ignored. This produces the following behavior when nulls are involved: - All null fields results in the null type - A mixture of nulls and a particular type results in the particular type - A mixture of nulls and two or more other types results in the varies type Closes gh-398 --- .../payload/JsonFieldTypeResolver.java | 2 +- .../payload/JsonFieldTypeResolverTests.java | 62 ++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) 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",