JsonWriterTests Class — spring-boot Architecture
Architecture documentation for the JsonWriterTests class in JsonWriterTests.java from the spring-boot codebase.
Entity Profile
Source Code
core/spring-boot/src/test/java/org/springframework/boot/json/JsonWriterTests.java lines 54–998
class JsonWriterTests {
private static final Person PERSON = new Person("Spring", "Boot", 10);
@Test
void writeToStringWritesToString() {
assertThat(ofFormatString("%s").writeToString(123)).isEqualTo("123");
}
@Test
void writeReturnsWritableJson() {
assertThat(ofFormatString("%s").write(123)).isInstanceOf(WritableJson.class);
}
@Test
void withSuffixAddsSuffixToWrittenString() {
assertThat(ofFormatString("%s").withSuffix("000").writeToString(123)).isEqualTo("123000");
}
@Test
void withSuffixWhenSuffixIsNullReturnsExistingWriter() {
JsonWriter<?> writer = ofFormatString("%s");
assertThat(writer.withSuffix(null)).isSameAs(writer);
}
@Test
void withSuffixWhenSuffixIsEmptyReturnsExistingWriter() {
JsonWriter<?> writer = ofFormatString("%s");
assertThat(writer.withSuffix("")).isSameAs(writer);
}
@Test
void withNewLineAtEndAddsNewLineToWrittenString() {
assertThat(ofFormatString("%s").withNewLineAtEnd().writeToString(123)).isEqualTo("123\n");
}
@Test
void ofAddingNamedSelf() {
JsonWriter<Person> writer = JsonWriter.of((members) -> members.add("test"));
assertThat(writer.writeToString(PERSON)).isEqualTo("""
{"test":"Spring Boot (10)"}""");
}
@Test
void ofAddingUnnamedSelf() {
JsonWriter<Person> writer = JsonWriter.of((members) -> members.add());
assertThat(writer.writeToString(PERSON)).isEqualTo(quoted("Spring Boot (10)"));
}
@Test
void ofAddValue() {
JsonWriter<Person> writer = JsonWriter.of((members) -> members.add("Spring", "Boot"));
assertThat(writer.writeToString(PERSON)).isEqualTo("""
{"Spring":"Boot"}""");
}
@Test
void ofAddSupplier() {
Supplier<@Nullable String> supplier = () -> "Boot";
JsonWriter<Person> writer = JsonWriter.of((members) -> members.add("Spring", supplier));
assertThat(writer.writeToString(PERSON)).isEqualTo("""
{"Spring":"Boot"}""");
}
@Test
void ofAddExtractor() {
JsonWriter<Person> writer = JsonWriter.of((members) -> {
members.add("firstName", Person::firstName);
members.add("lastName", Person::lastName);
members.add("age", Person::age);
});
assertThat(writer.writeToString(PERSON)).isEqualTo("""
{"firstName":"Spring","lastName":"Boot","age":10}""");
}
@Test
void ofFromValue() {
JsonWriter<Person> writer = JsonWriter.of((members) -> members.from("Boot"));
assertThat(writer.writeToString(PERSON)).isEqualTo(quoted("Boot"));
}
@Test
void ofFromSupplier() {
Supplier<@Nullable String> supplier = () -> "Boot";
JsonWriter<Person> writer = JsonWriter.of((members) -> members.from(supplier));
assertThat(writer.writeToString(PERSON)).isEqualTo(quoted("Boot"));
}
@Test
void ofFromExtractor() {
JsonWriter<Person> writer = JsonWriter.of((members) -> members.from(Person::lastName));
assertThat(writer.writeToString(PERSON)).isEqualTo(quoted("Boot"));
}
@Test
void ofAddMapEntries() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("a", "A");
map.put("b", 123);
map.put("c", true);
JsonWriter<List<Map<String, Object>>> writer = JsonWriter
.of((members) -> members.addMapEntries((list) -> list.get(0)));
assertThat(writer.writeToString(List.of(map))).isEqualTo("""
{"a":"A","b":123,"c":true}""");
}
@Test
void ofWhenNoMembersAddedThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> JsonWriter.of((members) -> {
})).withMessage("No members have been added");
}
@Test
void ofWhenOneContributesPairByNameAndOneHasNoNameThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> JsonWriter.of((members) -> {
members.add("Spring", "Boot");
members.from("alone");
}))
.withMessage("Member at index 1 does not contribute a named pair, "
+ "ensure that all members have a name or call an appropriate 'using' method");
}
@Test
void ofWhenOneContributesPairByUsingPairsAndOneHasNoNameThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> JsonWriter.of((members) -> {
members.from(Map.of("Spring", "Boot")).usingPairs(Map::forEach);
members.from("alone");
}))
.withMessage("Member at index 1 does not contribute a named pair, "
+ "ensure that all members have a name or call an appropriate 'using' method");
}
@Test
void ofWhenOneContributesPairByUsingMembersAndOneHasNoNameThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> JsonWriter.of((members) -> {
members.from(PERSON).usingMembers((personMembers) -> {
personMembers.add("first", Person::firstName);
personMembers.add("last", Person::firstName);
});
members.from("alone");
}))
.withMessage("Member at index 1 does not contribute a named pair, "
+ "ensure that all members have a name or call an appropriate 'using' method");
}
private static String quoted(String value) {
return "\"" + value + "\"";
}
private static <T> JsonWriter<T> ofFormatString(String json) {
return (instance, out) -> out.append(json.formatted(instance));
}
/**
* Tests for {@link JsonWriter#standard()}.
*/
@Nested
class StandardWriterTests {
@Test
void whenPrimitive() {
assertThat(write(null)).isEqualTo("null");
assertThat(write(123)).isEqualTo("123");
assertThat(write(true)).isEqualTo("true");
assertThat(write("test")).isEqualTo(quoted("test"));
}
@Test
void whenMap() {
assertThat(write(Map.of("spring", "boot"))).isEqualTo("""
{"spring":"boot"}""");
}
@Test
void whenArray() {
assertThat(write(new int[] { 1, 2, 3 })).isEqualTo("[1,2,3]");
}
private <T> String write(@Nullable T instance) {
return JsonWriter.standard().writeToString(instance);
}
}
/**
* Tests for {@link Members} and {@link Member}.
*/
@Nested
class MembersTest {
@Test
void whenNotNull() {
JsonWriter<String> writer = JsonWriter.of((members) -> members.add().whenNotNull());
assertThat(writer.writeToString("test")).isEqualTo(quoted("test"));
assertThat(writer.writeToString(null)).isEmpty();
}
@Test
void whenNotNullExtracted() {
Person personWithNull = new Person("Spring", null, 10);
Function<@Nullable Person, @Nullable Object> lastName = (person) -> (person != null) ? person.lastName()
: null;
JsonWriter<Person> writer = JsonWriter.of((members) -> members.add().whenNotNull(lastName));
assertThat(writer.writeToString(PERSON)).isEqualTo(quoted("Spring Boot (10)"));
assertThat(writer.writeToString(personWithNull)).isEmpty();
}
@Test
void whenHasLength() {
JsonWriter<String> writer = JsonWriter.of((members) -> members.add().whenHasLength());
assertThat(writer.writeToString("test")).isEqualTo(quoted("test"));
assertThat(writer.writeToString("")).isEmpty();
assertThat(writer.writeToString(null)).isEmpty();
}
@Test
void whenHasLengthOnNonString() {
JsonWriter<StringBuilder> writer = JsonWriter.of((members) -> members.add().whenHasLength());
assertThat(writer.writeToString(new StringBuilder("test"))).isEqualTo(quoted("test"));
assertThat(writer.writeToString(new StringBuilder())).isEmpty();
assertThat(writer.writeToString(null)).isEmpty();
}
@Test
void whenNotEmpty() {
JsonWriter<Object> writer = JsonWriter.of((members) -> members.add().whenNotEmpty());
assertThat(writer.writeToString(List.of("a"))).isEqualTo("""
["a"]""");
assertThat(writer.writeToString(Collections.emptyList())).isEmpty();
assertThat(writer.writeToString(new Object[] {})).isEmpty();
assertThat(writer.writeToString(new int[] {})).isEmpty();
assertThat(writer.writeToString(null)).isEmpty();
}
@Test
void whenNot() {
Predicate<@Nullable List<String>> isEmpty = List::isEmpty;
JsonWriter<List<String>> writer = JsonWriter.of((members) -> members.add().whenNot(isEmpty));
assertThat(writer.writeToString(List.of("a"))).isEqualTo("""
["a"]""");
assertThat(writer.writeToString(Collections.emptyList())).isEmpty();
}
@Test
void when() {
Predicate<@Nullable List<String>> isEmpty = List::isEmpty;
JsonWriter<List<String>> writer = JsonWriter.of((members) -> members.add().when(isEmpty));
assertThat(writer.writeToString(List.of("a"))).isEmpty();
assertThat(writer.writeToString(Collections.emptyList())).isEqualTo("[]");
}
@Test
void chainedPredicates() {
Set<String> banned = Set.of("Spring", "Boot");
Predicate<@Nullable String> stringLengthPredicate = (string) -> string != null && string.length() <= 2;
Predicate<@Nullable String> bannedPredicate = (string) -> string != null && banned.contains(string);
JsonWriter<String> writer = JsonWriter
.of((members) -> members.add().whenHasLength().whenNot(bannedPredicate).whenNot(stringLengthPredicate));
assertThat(writer.writeToString("")).isEmpty();
assertThat(writer.writeToString("a")).isEmpty();
assertThat(writer.writeToString("Boot")).isEmpty();
assertThat(writer.writeToString("JSON")).isEqualTo(quoted("JSON"));
}
@Test
void as() {
JsonWriter<String> writer = JsonWriter.of((members) -> members.add().as(Integer::valueOf));
assertThat(writer.writeToString("123")).isEqualTo("123");
}
@Test
void asWhenValueIsNullDoesNotCallAdapter() {
JsonWriter<String> writer = JsonWriter.of((members) -> members.add().as((value) -> {
throw new RuntimeException("bad");
}));
writer.writeToString(null);
}
@Test
void chainedAs() {
Extractor<Integer, Boolean> booleanExtractor = (integer) -> integer != 0;
JsonWriter<String> writer = JsonWriter
.of((members) -> members.add().as(Integer::valueOf).as(booleanExtractor));
assertThat(writer.writeToString("0")).isEqualTo("false");
assertThat(writer.writeToString("1")).isEqualTo("true");
}
@Test
void chainedAsAndPredicates() {
Extractor<Integer, Boolean> booleanExtractor = (integer) -> integer != 0;
Predicate<@Nullable String> isEmpty = (string) -> !StringUtils.hasLength(string);
JsonWriter<String> writer = JsonWriter.of((members) -> members.add()
.whenNot(isEmpty)
.as(Integer::valueOf)
.when((integer) -> integer < 2)
.as(booleanExtractor));
assertThat(writer.writeToString("")).isEmpty();
assertThat(writer.writeToString("0")).isEqualTo("false");
assertThat(writer.writeToString("1")).isEqualTo("true");
assertThat(writer.writeToString("2")).isEmpty();
}
@Test
void usingExtractedPairsWithExtractor() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("a", "A");
map.put("b", "B");
PairExtractor<Map.Entry<String, Object>> extractor = PairExtractor.of(Map.Entry::getKey,
Map.Entry::getValue);
JsonWriter<Map<String, Object>> writer = JsonWriter
.of((members) -> members.add().as(Map::entrySet).usingExtractedPairs(Set::forEach, extractor));
assertThat(writer.writeToString(map)).isEqualTo("""
{"a":"A","b":"B"}""");
}
@Test
void usingExtractedPairs() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("a", "A");
map.put("b", "B");
Function<Map.Entry<String, Object>, String> nameExtractor = Map.Entry::getKey;
Function<Map.Entry<String, Object>, Object> valueExtractor = Map.Entry::getValue;
JsonWriter<Map<String, Object>> writer = JsonWriter.of((members) -> members.add()
.as(Map::entrySet)
.usingExtractedPairs(Set::forEach, nameExtractor, valueExtractor));
assertThat(writer.writeToString(map)).isEqualTo("""
{"a":"A","b":"B"}""");
}
@Test
void usingPairs() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("a", "A");
map.put("b", "B");
JsonWriter<Map<String, Object>> writer = JsonWriter.of((members) -> members.add().usingPairs(Map::forEach));
assertThat(writer.writeToString(map)).isEqualTo("""
{"a":"A","b":"B"}""");
}
@Test
void usingPairsWhenAlreadyDeclaredThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> JsonWriter.of((
members) -> members.from(Collections.emptyMap()).usingPairs(Map::forEach).usingPairs(Map::forEach)))
.withMessage("Pairs cannot be declared multiple times");
}
@Test
void usingPairsWhenUsingMembersThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> JsonWriter.of((members) -> members.from(Collections.emptyMap())
.usingMembers((mapMembers) -> mapMembers.add("test"))
.usingPairs(Map::forEach)))
.withMessage("Pairs cannot be declared when using members");
}
@Test
void usingMembers() {
Couple couple = new Couple(PERSON, new Person("Spring", "Framework", 20));
JsonWriter<Couple> writer = JsonWriter.of((members) -> {
members.add("personOne", Couple::person1).usingMembers((personMembers) -> {
personMembers.add("fn", Person::firstName);
personMembers.add("ln", Person::lastName);
});
members.add("personTwo", Couple::person2).usingMembers((personMembers) -> {
personMembers.add("details", Person::toString);
personMembers.add("eldest", true);
});
});
assertThat(writer.writeToString(couple)).isEqualTo("""
{"personOne":{"fn":"Spring","ln":"Boot"},""" + """
"personTwo":{"details":"Spring Framework (20)","eldest":true}}""");
}
@Test
void usingMembersWithoutName() {
Couple couple = new Couple(PERSON, new Person("Spring", "Framework", 20));
JsonWriter<Couple> writer = JsonWriter.of((members) -> {
members.add("version", 1);
members.from(Couple::person1)
.usingMembers((personMembers) -> personMembers.add("one", Person::toString));
members.from(Couple::person2)
.usingMembers((personMembers) -> personMembers.add("two", Person::toString));
});
assertThat(writer.writeToString(couple)).isEqualTo("""
{"version":1,"one":"Spring Boot (10)","two":"Spring Framework (20)"}""");
}
@Test
void usingMembersWithoutNameInMember() {
Couple couple = new Couple(PERSON, new Person("Spring", "Framework", 20));
JsonWriter<Couple> writer = JsonWriter.of((members) -> members.add("only", Couple::person2)
.usingMembers((personMembers) -> personMembers.from(Person::toString)));
assertThat(writer.writeToString(couple)).isEqualTo("""
{"only":"Spring Framework (20)"}""");
}
@Test
void usingMembersWithoutNameAtAll() {
Couple couple = new Couple(PERSON, new Person("Spring", "Framework", 20));
JsonWriter<Couple> writer = JsonWriter.of((members) -> members.from(Couple::person2)
.usingMembers((personMembers) -> personMembers.from(Person::toString)));
assertThat(writer.writeToString(couple)).isEqualTo(quoted("Spring Framework (20)"));
}
@Test
void usingMembersWhenAlreadyDeclaredThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> JsonWriter.of((members) -> members.from(Collections.emptyMap())
.usingMembers((mapMembers) -> mapMembers.add("test"))
.usingMembers((mapMembers) -> mapMembers.add("test"))))
.withMessage("Members cannot be declared multiple times");
}
@Test
void usingMembersWhenUsingPairsThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> JsonWriter.of((members) -> members.from(Collections.emptyMap())
.usingPairs(Map::forEach)
.usingMembers((mapMembers) -> mapMembers.add("test"))))
.withMessage("Members cannot be declared when using pairs");
}
}
/**
* Tests for {@link MemberPath}.
*/
@Nested
class MemberPathTests {
@Test
void createWhenIndexAndNamedThrowException() {
assertThatIllegalArgumentException().isThrownBy(() -> new MemberPath(null, "boot", 0))
.withMessage("'name' and 'index' cannot be mixed");
assertThatIllegalArgumentException().isThrownBy(() -> new MemberPath(null, null, -1))
.withMessage("'name' and 'index' cannot be mixed");
}
@Test
void toStringReturnsUsefulString() {
assertThat(MemberPath.ROOT).hasToString("");
MemberPath spring = new MemberPath(MemberPath.ROOT, "spring", MemberPath.UNINDEXED);
MemberPath springDotBoot = new MemberPath(spring, "boot", MemberPath.UNINDEXED);
MemberPath springZero = new MemberPath(spring, null, 0);
MemberPath springZeroDotBoot = new MemberPath(springZero, "boot", MemberPath.UNINDEXED);
assertThat(spring).hasToString("spring");
assertThat(springDotBoot).hasToString("spring.boot");
assertThat(springZero).hasToString("spring[0]");
assertThat(springZeroDotBoot).hasToString("spring[0].boot");
}
@Test
void childWithNameCreatesChild() {
assertThat(MemberPath.ROOT.child("spring").child("boot")).hasToString("spring.boot");
}
@Test
void childWithNameWhenNameSpecialChars() {
assertThat(MemberPath.ROOT.child("spring.io").child("boot")).hasToString("spring\\.io.boot");
assertThat(MemberPath.ROOT.child("spring[io]").child("boot")).hasToString("spring\\[io\\].boot");
assertThat(MemberPath.ROOT.child("spring.[io]").child("boot")).hasToString("spring\\.\\[io\\].boot");
assertThat(MemberPath.ROOT.child("spring\\io").child("boot")).hasToString("spring\\\\io.boot");
assertThat(MemberPath.ROOT.child("spring.\\io").child("boot")).hasToString("spring\\.\\\\io.boot");
assertThat(MemberPath.ROOT.child("spring[\\io]").child("boot")).hasToString("spring\\[\\\\io\\].boot");
assertThat(MemberPath.ROOT.child("123").child("boot")).hasToString("123.boot");
assertThat(MemberPath.ROOT.child("1.2.3").child("boot")).hasToString("1\\.2\\.3.boot");
}
@Test
void childWithIndexCreatesChild() {
assertThat(MemberPath.ROOT.child("spring").child(0)).hasToString("spring[0]");
}
@Test
void ofParsesPaths() {
assertOfFromToString(MemberPath.ROOT.child("spring").child("boot"));
assertOfFromToString(MemberPath.ROOT.child("spring").child(0));
assertOfFromToString(MemberPath.ROOT.child("spring.io").child("boot"));
assertOfFromToString(MemberPath.ROOT.child("spring[io]").child("boot"));
assertOfFromToString(MemberPath.ROOT.child("spring.[io]").child("boot"));
assertOfFromToString(MemberPath.ROOT.child("spring\\io").child("boot"));
assertOfFromToString(MemberPath.ROOT.child("spring.\\io").child("boot"));
assertOfFromToString(MemberPath.ROOT.child("spring[\\io]").child("boot"));
assertOfFromToString(MemberPath.ROOT.child("123").child("boot"));
assertOfFromToString(MemberPath.ROOT.child("1.2.3").child("boot"));
}
private void assertOfFromToString(MemberPath path) {
assertThat(MemberPath.of(path.toString())).isEqualTo(path);
}
}
/**
* Tests for {@link Members#applyingPathFilter(java.util.function.Predicate)}.
*/
@Nested
class PathFilterTests {
@Test
void filteringMember() {
JsonWriter<Person> writer = JsonWriter.of((members) -> {
members.add("first", Person::firstName);
members.add("last", Person::lastName);
members.applyingPathFilter((path) -> {
String name = path.name();
assertThat(name).isNotNull();
return name.equals("first");
});
});
assertThat(writer.writeToString(new Person("spring", "boot", 10))).isEqualTo("""
{"last":"boot"}""");
}
@Test
void filteringInMap() {
JsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {
members.add();
members.applyingPathFilter((path) -> {
String name = path.name();
assertThat(name).isNotNull();
return name.equals("spring");
});
});
assertThat(writer.writeToString(Map.of("spring", "boot", "test", "test"))).isEqualTo("""
{"test":"test"}""");
}
}
/**
* Tests for {@link NameProcessor}.
*/
@Nested
class NameProcessorTests {
@Test
void processNameWhenSimpleValue() {
JsonWriter<String> writer = JsonWriter.of((members) -> {
members.add();
members.applyingNameProcessor(NameProcessor.of(String::toUpperCase));
});
assertThat(writer.writeToString("test")).isEqualTo("\"test\"");
}
@Test
void processNameWhenMember() {
JsonWriter<Person> writer = JsonWriter.of((members) -> {
members.add("first", Person::firstName);
members.add("last", Person::lastName);
members.applyingNameProcessor(NameProcessor.of(String::toUpperCase));
});
assertThat(writer.writeToString(new Person("spring", "boot", 10))).isEqualTo("""
{"FIRST":"spring","LAST":"boot"}""");
}
@Test
void processNameWhenInMap() {
JsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {
members.add();
members.applyingNameProcessor(NameProcessor.of(String::toUpperCase));
});
assertThat(writer.writeToString(Map.of("spring", "boot"))).isEqualTo("""
{"SPRING":"boot"}""");
}
@Test
void processNameWhenInNestedMap() {
JsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {
members.add();
members.applyingNameProcessor(NameProcessor.of(String::toUpperCase));
});
assertThat(writer.writeToString(Map.of("test", Map.of("spring", "boot")))).isEqualTo("""
{"TEST":{"SPRING":"boot"}}""");
}
@Test
void processNameWhenInPairs() {
JsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {
members.add().usingPairs(Map::forEach);
members.applyingNameProcessor(NameProcessor.of(String::toUpperCase));
});
assertThat(writer.writeToString(Map.of("spring", "boot"))).isEqualTo("""
{"SPRING":"boot"}""");
}
@Test
void processNameWhenHasNestedMembers() {
Couple couple = new Couple(PERSON, new Person("Spring", "Framework", 20));
JsonWriter<Couple> writer = JsonWriter.of((members) -> {
members.from(Couple::person1)
.usingMembers((personMembers) -> personMembers.add("one", Person::toString));
members.from(Couple::person2)
.usingMembers((personMembers) -> personMembers.add("two", Person::toString));
members.applyingNameProcessor(NameProcessor.of(String::toUpperCase));
});
assertThat(writer.writeToString(couple)).isEqualTo("""
{"ONE":"Spring Boot (10)","TWO":"Spring Framework (20)"}""");
}
@Test
void processNameWhenHasNestedMembersWithAdditionalValueProcessor() {
Couple couple = new Couple(PERSON, new Person("Spring", "Framework", 20));
JsonWriter<Couple> writer = JsonWriter.of((members) -> {
members.from(Couple::person1)
.usingMembers((personMembers) -> personMembers.add("one", Person::toString));
members.from(Couple::person2).usingMembers((personMembers) -> {
personMembers.add("two", Person::toString);
personMembers.applyingNameProcessor(NameProcessor.of(String::toUpperCase));
});
members.applyingNameProcessor(NameProcessor.of((name) -> name + "!"));
});
assertThat(writer.writeToString(couple)).isEqualTo("""
{"one!":"Spring Boot (10)","TWO!":"Spring Framework (20)"}""");
}
@Test
void processNameWhenDeeplyNestedUsesCompoundPaths() {
List<String> paths = new ArrayList<>();
JsonWriter<Couple> writer = JsonWriter.of((members) -> {
members.add("one", Couple::person1).usingMembers((personMembers) -> {
personMembers.add("first", Person::firstName);
personMembers.add("last", Person::lastName);
});
members.add("two", Couple::person2).usingMembers((personMembers) -> {
personMembers.add("first", Person::firstName);
personMembers.add("last", Person::lastName);
});
members.applyingNameProcessor((path, existingName) -> {
paths.add(path.toString());
return existingName;
});
});
Couple couple = new Couple(PERSON, new Person("Spring", "Framework", 20));
writer.writeToString(couple);
assertThat(paths).containsExactly("one", "one.first", "one.last", "two", "two.first", "two.last");
}
@Test
void processNameWhenReturnsNullThrowsException() {
JsonWriter<Person> writer = JsonWriter.of((members) -> {
members.add("first", Person::firstName);
members.add("last", Person::lastName);
members
.applyingNameProcessor((path, existingName) -> !"first".equals(existingName) ? existingName : null);
});
assertThatIllegalStateException().isThrownBy(() -> writer.writeToString(new Person("spring", "boot", 10)))
.withMessageContaining("NameProcessor")
.withMessageContaining("returned an empty result");
}
@Test
void processNameWhenReturnsEmptyStringThrowsException() {
JsonWriter<Person> writer = JsonWriter.of((members) -> {
members.add("first", Person::firstName);
members.add("last", Person::lastName);
members
.applyingNameProcessor((path, existingName) -> !"first".equals(existingName) ? existingName : "");
});
assertThatIllegalStateException().isThrownBy(() -> writer.writeToString(new Person("spring", "boot", 10)))
.withMessageContaining("NameProcessor")
.withMessageContaining("returned an empty result");
}
}
/**
* Tests for {@link ValueProcessor}.
*/
@Nested
class ValueProcessorTests {
@Test
void of() {
ValueProcessor<String> processor = ValueProcessor.of(stringToUppercase());
assertThat(processor.processValue(MemberPath.ROOT, "test")).isEqualTo("TEST");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void ofWhenNull() {
assertThatIllegalArgumentException().isThrownBy(() -> ValueProcessor.of(null))
.withMessage("'action' must not be null");
}
@Test
void whenHasPathWithStringWhenPathMatches() {
ValueProcessor<String> processor = ValueProcessor.of(stringToUppercase()).whenHasPath("foo");
assertThat(processor.processValue(MemberPath.ROOT.child("foo"), "test")).isEqualTo("TEST");
}
@Test
void whenHasPathWithStringWhenPathDoesNotMatch() {
ValueProcessor<String> processor = ValueProcessor.<String>of(stringToUppercase()).whenHasPath("foo");
assertThat(processor.processValue(MemberPath.ROOT.child("bar"), "test")).isEqualTo("test");
}
@Test
void whenHasPathWithPredicateWhenPathMatches() {
ValueProcessor<String> processor = ValueProcessor.<String>of(stringToUppercase())
.whenHasPath((path) -> path.toString().startsWith("f"));
assertThat(processor.processValue(MemberPath.ROOT.child("foo"), "test")).isEqualTo("TEST");
}
@Test
void whenHasPathWithPredicateWhenPathDoesNotMatch() {
ValueProcessor<String> processor = ValueProcessor.<String>of(stringToUppercase())
.whenHasPath((path) -> path.toString().startsWith("f"));
assertThat(processor.processValue(MemberPath.ROOT.child("bar"), "test")).isEqualTo("test");
}
@Test
void whenInstanceOfWhenInstanceMatches() {
ValueProcessor<Object> processor = ValueProcessor.of(objectToUppercase()).whenInstanceOf(String.class);
assertThat(processor.processValue(MemberPath.ROOT, "test")).hasToString("TEST");
}
@Test
void whenInstanceOfWhenInstanceDoesNotMatch() {
ValueProcessor<Object> processor = ValueProcessor.of(objectToUppercase()).whenInstanceOf(String.class);
assertThat(processor.processValue(MemberPath.ROOT, new StringBuilder("test"))).hasToString("test");
}
@Test
void whenWhenPredicateMatches() {
Predicate<@Nullable String> equals = "test"::equals;
ValueProcessor<String> processor = ValueProcessor.of(stringToUppercase()).when(equals);
assertThat(processor.processValue(MemberPath.ROOT, "test")).isEqualTo("TEST");
}
@Test
void whenWhenPredicateDoesNotMatch() {
Predicate<@Nullable String> equals = "test"::equals;
ValueProcessor<String> processor = ValueProcessor.of(stringToUppercase()).when(equals);
assertThat(processor.processValue(MemberPath.ROOT, "other")).isEqualTo("other");
}
@Test
void processValueWhenSimpleValue() {
JsonWriter<String> writer = simpleWriterWithUppercaseProcessor();
assertThat(writer.writeToString("test")).isEqualTo("\"TEST\"");
}
@Test
void processValueWhenMemberValue() {
JsonWriter<Person> writer = JsonWriter.of((members) -> {
members.add("first", Person::firstName);
members.add("last", Person::lastName);
members.applyingValueProcessor(ValueProcessor.of(stringCapitalize()));
});
assertThat(writer.writeToString(new Person("spring", "boot", 10))).isEqualTo("""
{"first":"Spring","last":"Boot"}""");
}
@Test
void processValueWhenInMap() {
JsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {
members.add();
members.applyingValueProcessor(ValueProcessor.of(stringCapitalize()));
});
assertThat(writer.writeToString(Map.of("spring", "boot"))).isEqualTo("""
{"spring":"Boot"}""");
}
@Test
void processValueWhenInNestedMap() {
JsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {
members.add();
members.applyingValueProcessor(ValueProcessor.of(stringCapitalize()));
});
assertThat(writer.writeToString(Map.of("test", Map.of("spring", "boot")))).isEqualTo("""
{"test":{"spring":"Boot"}}""");
}
@Test
void processValueWhenInPairs() {
JsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {
members.add().usingPairs(Map::forEach);
members.applyingValueProcessor(ValueProcessor.of(stringCapitalize()));
});
assertThat(writer.writeToString(Map.of("spring", "boot"))).isEqualTo("""
{"spring":"Boot"}""");
}
@Test
void processValueWhenCalledWithMultipleTypesIgnoresLambdaErrors() {
JsonWriter<Object> writer = JsonWriter.of((members) -> {
members.add();
members.applyingValueProcessor(ValueProcessor.of(stringCapitalize()));
});
assertThat(writer.writeToString("spring")).isEqualTo("\"Spring\"");
assertThat(writer.writeToString(123)).isEqualTo("123");
assertThat(writer.writeToString(true)).isEqualTo("true");
}
@Test
void processValueWhenLimitedToPath() {
JsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {
members.add();
members.applyingValueProcessor(ValueProcessor.of(stringCapitalize()).whenHasPath("spring"));
});
assertThat(writer.writeToString(Map.of("spring", "boot"))).isEqualTo("""
{"spring":"Boot"}""");
assertThat(writer.writeToString(Map.of("boot", "spring"))).isEqualTo("""
{"boot":"spring"}""");
}
@Test
void processValueWhen() {
JsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {
members.add();
Predicate<@Nullable String> startsWithB = (candidate) -> candidate != null && candidate.startsWith("b");
members.applyingValueProcessor(ValueProcessor.of(stringCapitalize()).when(startsWithB));
});
assertThat(writer.writeToString(Map.of("spring", "boot"))).isEqualTo("""
{"spring":"Boot"}""");
assertThat(writer.writeToString(Map.of("boot", "spring"))).isEqualTo("""
{"boot":"spring"}""");
}
@Test
void processValueWhenHasNestedMembers() {
Couple couple = new Couple(PERSON, new Person("Spring", "Framework", 20));
JsonWriter<Couple> writer = JsonWriter.of((members) -> {
members.from(Couple::person1)
.usingMembers((personMembers) -> personMembers.add("one", Person::toString));
members.from(Couple::person2)
.usingMembers((personMembers) -> personMembers.add("two", Person::toString));
UnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null)
? string.toUpperCase(Locale.ROOT) : null;
members.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase));
});
assertThat(writer.writeToString(couple)).isEqualTo("""
{"one":"SPRING BOOT (10)","two":"SPRING FRAMEWORK (20)"}""");
}
@Test
void processValueWhenHasNestedMembersWithAdditionalValueProcessor() {
Couple couple = new Couple(PERSON, new Person("Spring", "Framework", 20));
JsonWriter<Couple> writer = JsonWriter.of((members) -> {
members.from(Couple::person1)
.usingMembers((personMembers) -> personMembers.add("one", Person::toString));
members.from(Couple::person2).usingMembers((personMembers) -> {
personMembers.add("two", Person::toString);
UnaryOperator<@Nullable String> operator = (item) -> item + "!";
personMembers.applyingValueProcessor(ValueProcessor.of(String.class, operator));
});
UnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null)
? string.toUpperCase(Locale.ROOT) : null;
members.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase));
});
assertThat(writer.writeToString(couple)).isEqualTo("""
{"one":"SPRING BOOT (10)","two":"SPRING FRAMEWORK (20)!"}""");
}
@Test
void processValueWhenDeeplyNestedUsesCompoundPaths() {
List<String> paths = new ArrayList<>();
JsonWriter<Couple> writer = JsonWriter.of((members) -> {
members.add("one", Couple::person1).usingMembers((personMembers) -> {
personMembers.add("first", Person::firstName);
personMembers.add("last", Person::lastName);
});
members.add("two", Couple::person2).usingMembers((personMembers) -> {
personMembers.add("first", Person::firstName);
personMembers.add("last", Person::lastName);
});
members.applyingValueProcessor((path, value) -> {
paths.add(path.toString());
return value;
});
});
Couple couple = new Couple(PERSON, new Person("Spring", "Framework", 20));
writer.writeToString(couple);
assertThat(paths).containsExactly("one", "one.first", "one.last", "two", "two.first", "two.last");
}
@Test
void processValueWhenUsingListUsesIndexedPaths() {
List<String> paths = new ArrayList<>();
JsonWriter<List<String>> writer = JsonWriter.of((members) -> {
members.add();
members.applyingValueProcessor((path, value) -> {
paths.add(path.toString());
return value;
});
});
writer.writeToString(List.of("a", "b", "c"));
assertThat(paths).containsExactly("", "[0]", "[1]", "[2]");
}
@Test
void processValueUsesUnprocessedNameInPath() {
List<String> paths = new ArrayList<>();
JsonWriter<Person> writer = JsonWriter.of((members) -> {
members.add("first", Person::firstName);
members.add("last", Person::lastName);
members.applyingValueProcessor((path, value) -> {
paths.add(path.toString());
return value;
});
members.applyingNameProcessor((path, existingName) -> "the-" + existingName);
});
writer.writeToString(PERSON);
assertThat(paths).containsExactly("first", "last");
}
private static UnaryOperator<@Nullable String> stringToUppercase() {
return (string) -> (string != null) ? string.toUpperCase(Locale.ROOT) : null;
}
private static UnaryOperator<@Nullable Object> objectToUppercase() {
return (string) -> (string != null) ? string.toString().toUpperCase(Locale.ROOT) : null;
}
private static UnaryOperator<@Nullable String> stringCapitalize() {
return (string) -> (string != null) ? StringUtils.capitalize(string) : null;
}
private JsonWriter<String> simpleWriterWithUppercaseProcessor() {
return JsonWriter.of((members) -> {
members.add();
UnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null)
? string.toUpperCase(Locale.ROOT) : null;
members.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase));
});
}
}
record Person(String firstName, @Nullable String lastName, int age) {
@Override
public String toString() {
return "%s %s (%s)".formatted(this.firstName, this.lastName, this.age);
}
}
record Couple(Person person1, Person person2) {
}
}
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free