Throw an exception if the same name is written to JSON more than once

Update `JsonValueWriter` to track written names and throw an exception
if there is a duplicate.

Closes gh-43041
This commit is contained in:
Phillip Webb 2024-11-05 16:10:36 -08:00
parent f38e1a5695
commit 796ce3d4b2
2 changed files with 21 additions and 0 deletions

View File

@ -21,7 +21,9 @@ import java.io.UncheckedIOException;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
@ -223,6 +225,8 @@ class JsonValueWriter {
ActiveSeries activeSeries = this.activeSeries.peek();
Assert.notNull(activeSeries, "No series has been started");
activeSeries.incrementIndexAndAddCommaIfRequired();
Assert.state(activeSeries.addName(processedName),
() -> "The name '" + processedName + "' has already been written");
writeString(processedName);
append(":");
write(value);
@ -359,10 +363,16 @@ class JsonValueWriter {
private int index;
private Set<String> names = new HashSet<>();
private ActiveSeries(Series series) {
this.series = series;
}
boolean addName(String processedName) {
return this.names.add(processedName);
}
MemberPath updatePath(MemberPath path) {
return (this.series != Series.ARRAY) ? path : path.child(this.index);
}

View File

@ -29,6 +29,7 @@ import org.springframework.boot.json.JsonValueWriter.Series;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Tests for {@link JsonValueWriter} .
@ -193,6 +194,16 @@ class JsonValueWriterTests {
{"a":"A","b":"B"}""");
}
@Test
void writePairsWhenDuplicateThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> doWrite((valueWriter) -> {
valueWriter.start(Series.OBJECT);
valueWriter.writePairs(Map.of("a", "A")::forEach);
valueWriter.writePairs(Map.of("a", "B")::forEach);
valueWriter.end(Series.OBJECT);
})).withMessage("The name 'a' has already been written");
}
@Test
void writeArray() {
List<String> list = List.of("a", "b", "c");