From aacb8c0d850660502326b4ddbec6859fda5714fe Mon Sep 17 00:00:00 2001 From: Divanshu Goyal Date: Tue, 13 Jan 2026 17:43:19 +0530 Subject: [PATCH] SLING-12824 Add ResourceUtil.isRoot(String path) method Add a convenience method to check if a path represents the root path. This makes it more intuitive to determine if a path is root rather than checking if getParent() returns null. --- .../sling/api/resource/ResourceUtil.java | 29 +++++++++++++++++++ .../sling/api/resource/ResourceUtilTest.java | 29 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/main/java/org/apache/sling/api/resource/ResourceUtil.java b/src/main/java/org/apache/sling/api/resource/ResourceUtil.java index e3355cf0..9e4f2a81 100644 --- a/src/main/java/org/apache/sling/api/resource/ResourceUtil.java +++ b/src/main/java/org/apache/sling/api/resource/ResourceUtil.java @@ -195,6 +195,35 @@ private static int countDotsSegment(final String segment) { return parentPath; } + /** + * Utility method to check whether the given path represents + * the root path. The path is normalized by {@link #normalize(String)} before + * checking. + * + * @param path The path to check. + * @return true if the path represents the root path after + * normalization, false otherwise. + * @throws IllegalArgumentException If the path cannot be normalized by the + * {@link #normalize(String)} method. + * @throws NullPointerException If path is null. + * @since 2.15.0 (Sling API Bundle 3.1.0) + */ + public static boolean isRoot(@NotNull String path) { + // quick check for obvious root + if ("/".equals(path)) { + return true; + } + + // normalize path (remove . and ..) + String normalizedPath = normalize(path); + if (normalizedPath == null) { + throw new IllegalArgumentException( + String.format("normalizing path '%s' resolves to a path higher than root", path)); + } + + return "/".equals(normalizedPath); + } + /** * Utility method returns the ancestor's path at the given level * relative to path, which is normalized by {@link #normalize(String)} diff --git a/src/test/java/org/apache/sling/api/resource/ResourceUtilTest.java b/src/test/java/org/apache/sling/api/resource/ResourceUtilTest.java index b957bd0c..c1622ec9 100644 --- a/src/test/java/org/apache/sling/api/resource/ResourceUtilTest.java +++ b/src/test/java/org/apache/sling/api/resource/ResourceUtilTest.java @@ -449,4 +449,33 @@ public void testEscapeAndUnescapeNameWithDots() { assertEquals(nameWithSpecialChars, ResourceUtil.unescapeName(escapedName)); assertFalse(escapedName.contains(".")); } + + @Test + public void testIsRoot() { + // root path + assertTrue(ResourceUtil.isRoot("/")); + + // paths that normalize to root + assertTrue(ResourceUtil.isRoot("///")); + assertTrue(ResourceUtil.isRoot("/a/..")); + assertTrue(ResourceUtil.isRoot("/a/b/../..")); + assertTrue(ResourceUtil.isRoot("/.")); + + // non-root paths + assertFalse(ResourceUtil.isRoot("/a")); + assertFalse(ResourceUtil.isRoot("/a/b")); + assertFalse(ResourceUtil.isRoot("/a/b/c")); + assertFalse(ResourceUtil.isRoot("/a/b/..")); + + // relative paths (not root) + assertFalse(ResourceUtil.isRoot("a")); + assertFalse(ResourceUtil.isRoot("a/b")); + + // null should throw NullPointerException + assertThrows(NullPointerException.class, () -> ResourceUtil.isRoot(null)); + + // paths that cannot be normalized should throw IllegalArgumentException + assertThrows(IllegalArgumentException.class, () -> ResourceUtil.isRoot("/..")); + assertThrows(IllegalArgumentException.class, () -> ResourceUtil.isRoot("/a/../..")); + } }