diff --git a/src/main/java/org/opentripplanner/framework/collection/CollectionUtils.java b/src/main/java/org/opentripplanner/framework/collection/CollectionUtils.java
new file mode 100644
index 00000000000..40f69f56595
--- /dev/null
+++ b/src/main/java/org/opentripplanner/framework/collection/CollectionUtils.java
@@ -0,0 +1,35 @@
+package org.opentripplanner.framework.collection;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+public class CollectionUtils {
+
+ /**
+ * A null-safe version of toString() for a collections.
+ *
+ * If the collection is {@code null} the given {@code nullText} is returned.
+ *
+ * All elements are also converted to a sting using the {@code toString()} method or if
+ * {@code null} to the given {@code nullText}.
+ *
+ * If the collection is a set, but not a SortedSet then the elements are sorted. This is done
+ * to return the elements in a deterministic manner, witch is important if this is used in
+ * for example a unit-test.
+ *
+ * The final result string examples: {@code "[]", "[a]", "[a, b, c]"}
+ */
+ public static String toString(@Nullable Collection c, String nullText) {
+ if (c == null) {
+ return nullText;
+ }
+ var stream = c.stream().map(it -> it == null ? nullText : it.toString());
+ if (c instanceof Set && !(c instanceof SortedSet)) {
+ stream = stream.sorted();
+ }
+ return stream.collect(Collectors.joining(", ", "[", "]"));
+ }
+}
diff --git a/src/test/java/org/opentripplanner/framework/collection/CollectionUtilsTest.java b/src/test/java/org/opentripplanner/framework/collection/CollectionUtilsTest.java
new file mode 100644
index 00000000000..ae33e493bcc
--- /dev/null
+++ b/src/test/java/org/opentripplanner/framework/collection/CollectionUtilsTest.java
@@ -0,0 +1,43 @@
+package org.opentripplanner.framework.collection;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.google.type.Month;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.junit.jupiter.api.Test;
+
+class CollectionUtilsTest {
+
+ public static final String NULL_STRING = "";
+
+ @Test
+ void testToString() {
+ assertEquals("", CollectionUtils.toString(null, NULL_STRING));
+ assertEquals("[]", CollectionUtils.toString(Set.of(), NULL_STRING));
+ assertEquals("[]", CollectionUtils.toString(List.of(), NULL_STRING));
+ assertEquals("[JUNE]", CollectionUtils.toString(EnumSet.of(Month.JUNE), NULL_STRING));
+ assertEquals(
+ "[APRIL, JANUARY, JUNE]",
+ CollectionUtils.toString(EnumSet.of(Month.JANUARY, Month.JUNE, Month.APRIL), "#")
+ );
+
+ // Given a list of objects
+ List