Browse Source

Support arrays, collections, & maps in ObjectUtils.nullSafeConciseToString()

Prior to this commit, there was no explicit support for arrays,
collections, and maps in nullSafeConciseToString(). This lead to string
representations such as the following, regardless of whether the array,
collection, or map was empty.

- char[]@1623b78d
- java.util.ImmutableCollections$List12@74fe5c40
- java.util.ImmutableCollections$MapN@10e31a9a

This commit introduces explicit support for arrays, collections, and
maps in nullSafeConciseToString(), which results in the following
empty/non-empty string representations.

- array: {} / {...}
- collection: [] / [...]
- map: {} / {...}

The reason a string representation of an array uses "{}" instead of
"[]" (like in Arrays.toString(...)) is that
ObjectUtils.nullSafeToString(<array>) already follows that convention,
and the implementation of nullSafeConciseToString() aligns with that
for the sake of consistency.

Closes gh-30811
pull/30971/head
Sam Brannen 3 years ago
parent
commit
a3907a64e5
  1. 13
      spring-core/src/main/java/org/springframework/util/ObjectUtils.java
  2. 49
      spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java

13
spring-core/src/main/java/org/springframework/util/ObjectUtils.java

@ -69,6 +69,9 @@ public abstract class ObjectUtils {
private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END; private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END;
private static final String ARRAY_ELEMENT_SEPARATOR = ", "; private static final String ARRAY_ELEMENT_SEPARATOR = ", ";
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
private static final String NON_EMPTY_ARRAY = ARRAY_START + "..." + ARRAY_END;
private static final String EMPTY_COLLECTION = "[]";
private static final String NON_EMPTY_COLLECTION = "[...]";
/** /**
@ -967,6 +970,16 @@ public abstract class ObjectUtils {
return (!optional.isPresent() ? "Optional.empty" : return (!optional.isPresent() ? "Optional.empty" :
String.format("Optional[%s]", nullSafeConciseToString(optional.get()))); String.format("Optional[%s]", nullSafeConciseToString(optional.get())));
} }
if (obj.getClass().isArray()) {
return (Array.getLength(obj) == 0 ? EMPTY_ARRAY : NON_EMPTY_ARRAY);
}
if (obj instanceof Collection<?>) {
return (((Collection<?>) obj).isEmpty() ? EMPTY_COLLECTION : NON_EMPTY_COLLECTION);
}
if (obj instanceof Map<?, ?>) {
// EMPTY_ARRAY and NON_EMPTY_ARRAY are also used for maps.
return (((Map<?, ?>) obj).isEmpty() ? EMPTY_ARRAY : NON_EMPTY_ARRAY);
}
if (obj instanceof Class<?>) { if (obj instanceof Class<?>) {
return ((Class<?>) obj).getName(); return ((Class<?>) obj).getName();
} }

49
spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java

@ -30,7 +30,6 @@ import java.nio.file.Paths;
import java.sql.SQLException; import java.sql.SQLException;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Currency; import java.util.Currency;
@ -39,6 +38,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
@ -1059,20 +1059,49 @@ class ObjectUtilsTests {
} }
@Test @Test
void nullSafeConciseToStringForArraysAndCollections() { void nullSafeConciseToStringForEmptyArrays() {
List<String> list = Arrays.asList("a", "b", "c"); assertThat(ObjectUtils.nullSafeConciseToString(new char[] {})).isEqualTo("{}");
assertThat(ObjectUtils.nullSafeConciseToString(new int[][] {{1, 2}, {3, 4}})).startsWith(prefix(int[][].class)); assertThat(ObjectUtils.nullSafeConciseToString(new int[][] {})).isEqualTo("{}");
assertThat(ObjectUtils.nullSafeConciseToString(list.toArray(new Object[0]))).startsWith(prefix(Object[].class)); assertThat(ObjectUtils.nullSafeConciseToString(new String[] {})).isEqualTo("{}");
assertThat(ObjectUtils.nullSafeConciseToString(list.toArray(new String[0]))).startsWith(prefix(String[].class)); assertThat(ObjectUtils.nullSafeConciseToString(new Integer[][] {})).isEqualTo("{}");
assertThat(ObjectUtils.nullSafeConciseToString(new ArrayList<>(list))).startsWith(prefix(ArrayList.class));
assertThat(ObjectUtils.nullSafeConciseToString(new HashSet<>(list))).startsWith(prefix(HashSet.class));
} }
@Test @Test
void nullSafeConciseToStringForMaps() { void nullSafeConciseToStringForNonEmptyArrays() {
assertThat(ObjectUtils.nullSafeConciseToString(new char[] {'a'})).isEqualTo("{...}");
assertThat(ObjectUtils.nullSafeConciseToString(new int[][] {{1}, {2}})).isEqualTo("{...}");
assertThat(ObjectUtils.nullSafeConciseToString(new String[] {"enigma"})).isEqualTo("{...}");
assertThat(ObjectUtils.nullSafeConciseToString(new Integer[][] {{1}, {2}})).isEqualTo("{...}");
}
@Test
void nullSafeConciseToStringForEmptyCollections() {
List<String> list = Collections.emptyList();
Set<Integer> set = Collections.emptySet();
assertThat(ObjectUtils.nullSafeConciseToString(list)).isEqualTo("[]");
assertThat(ObjectUtils.nullSafeConciseToString(set)).isEqualTo("[]");
}
@Test
void nullSafeConciseToStringForNonEmptyCollections() {
List<String> list = Arrays.asList("a", "b");
Set<String> set = new HashSet<>();
set.add("foo");
assertThat(ObjectUtils.nullSafeConciseToString(list)).isEqualTo("[...]");
assertThat(ObjectUtils.nullSafeConciseToString(set)).isEqualTo("[...]");
}
@Test
void nullSafeConciseToStringForEmptyMaps() {
Map<String, Object> map = Collections.emptyMap();
assertThat(ObjectUtils.nullSafeConciseToString(map)).isEqualTo("{}");
}
@Test
void nullSafeConciseToStringForNonEmptyMaps() {
HashMap<String, Object> map = new HashMap<>(); HashMap<String, Object> map = new HashMap<>();
map.put("foo", 42L); map.put("foo", 42L);
assertThat(ObjectUtils.nullSafeConciseToString(map)).startsWith(prefix(map.getClass())); assertThat(ObjectUtils.nullSafeConciseToString(map)).isEqualTo("{...}");
} }
@Test @Test

Loading…
Cancel
Save