Improve error message when extracting a sometimes absent sub-section

Fixes gh-715
This commit is contained in:
Andy Wilkinson
2021-04-19 14:18:47 +01:00
parent c3cb7af68a
commit 2b5eab309c
4 changed files with 45 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2021 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,6 +21,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -93,7 +94,9 @@ public class FieldPathPayloadSubsectionExtractor
List<?> extractedList = (List<?>) value;
JsonContentHandler contentHandler = new JsonContentHandler(payload, descriptorsByPath.values());
Set<JsonFieldPath> uncommonPaths = JsonFieldPaths.from(extractedList).getUncommon().stream()
.map((path) -> JsonFieldPath.compile(this.fieldPath + "." + path)).filter((path) -> {
.map((path) -> JsonFieldPath
.compile((path.equals("")) ? this.fieldPath : this.fieldPath + "." + path))
.filter((path) -> {
FieldDescriptor descriptorForPath = descriptorsByPath.getOrDefault(path,
new FieldDescriptor(path.toString()));
return contentHandler.isMissing(descriptorForPath);
@@ -105,7 +108,8 @@ public class FieldPathPayloadSubsectionExtractor
String message = this.fieldPath + " identifies multiple sections of "
+ "the payload and they do not have a common structure. The "
+ "following non-optional uncommon paths were found: ";
message += uncommonPaths;
message += uncommonPaths.stream().map(JsonFieldPath::toString)
.collect(Collectors.toCollection(TreeSet::new));
throw new PayloadHandlingException(message);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2021 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.
@@ -24,6 +24,8 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.springframework.restdocs.payload.JsonFieldProcessor.ExtractedField;
/**
* {@code JsonFieldPaths} provides support for extracting fields paths from JSON
* structures and identifying uncommon paths.
@@ -69,6 +71,9 @@ final class JsonFieldPaths {
else if (object instanceof Map) {
from(paths, parent, (Map<?, ?>) object);
}
else if (object.equals(ExtractedField.ABSENT)) {
paths.add(parent);
}
}
private static void from(Set<String> paths, String parent, List<?> items) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2021 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.
@@ -107,6 +107,25 @@ public class FieldPathPayloadSubsectionExtractorTests {
"{\"a\":[{\"b\":{\"c\":5}},{\"b\":{\"c\":6, \"d\": 7}}]}".getBytes(), MediaType.APPLICATION_JSON);
}
@Test
public void extractMapSubsectionWithVaryingStructureFromInconsistentJsonMap()
throws JsonParseException, JsonMappingException, IOException {
this.thrown.expect(PayloadHandlingException.class);
this.thrown.expectMessage("The following non-optional uncommon paths were found: [*.d, *.d.e, *.d.f]");
new FieldPathPayloadSubsectionExtractor("*.d").extractSubsection(
"{\"a\":{\"b\":1},\"c\":{\"d\":{\"e\":1,\"f\":2}}}".getBytes(), MediaType.APPLICATION_JSON);
}
@Test
public void extractMapSubsectionWithVaryingStructureFromInconsistentJsonMapWhereAllSubsectionFieldsAreOptional()
throws IOException {
this.thrown.expect(PayloadHandlingException.class);
this.thrown.expectMessage("The following non-optional uncommon paths were found: [*.d]");
new FieldPathPayloadSubsectionExtractor("*.d").extractSubsection(
"{\"a\":{\"b\":1},\"c\":{\"d\":{\"e\":1,\"f\":2}}}".getBytes(), MediaType.APPLICATION_JSON,
Arrays.asList(new FieldDescriptor("e").optional(), new FieldDescriptor("f").optional()));
}
@Test
@SuppressWarnings("unchecked")
public void extractMapSubsectionWithVaryingStructureDueToOptionalFieldsFromMultiElementArrayInAJsonMap()

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2021 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.
@@ -22,6 +22,8 @@ import java.util.Arrays;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.springframework.restdocs.payload.JsonFieldProcessor.ExtractedField;
import static org.assertj.core.api.Assertions.assertThat;
/**
@@ -74,6 +76,15 @@ public class JsonFieldPathsTests {
.getUncommon()).containsExactly("b.c", "b.d");
}
@Test
public void absentItemFromFieldExtractionCausesAllPresentFieldsToBeIdentifiedAsUncommon() {
assertThat(
JsonFieldPaths
.from(Arrays.asList(ExtractedField.ABSENT, ("{\"a\": 1, \"b\": {\"c\": 1}}"),
json("{\"a\": 1, \"b\": {\"c\": 1}}"), json("{\"a\": 1, \"b\": {\"d\": 2}}")))
.getUncommon()).containsExactly("", "a", "b", "b.c", "b.d");
}
@Test
public void missingEntryBeneathArrayIsIdentifiedAsUncommon() {
assertThat(JsonFieldPaths