diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 712fd7e2d..dcb488581 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -46,6 +46,7 @@ The type attribute can be add,update,fix,remove. + Add APIs StringUtils.wrapIfMissing(String, char|String) TypeUtils.isAssignable throws NullPointerException when fromType has type variables and toType generic superclass specifies type variable StringUtils#normalizeSpace does not trim the string anymore SerializationUtils.ClassLoaderAwareObjectInputStream should use static initializer to initialize primitiveTypes map diff --git a/src/main/java/org/apache/commons/lang3/StringUtils.java b/src/main/java/org/apache/commons/lang3/StringUtils.java index 01d0f70d7..7fbddb122 100644 --- a/src/main/java/org/apache/commons/lang3/StringUtils.java +++ b/src/main/java/org/apache/commons/lang3/StringUtils.java @@ -8562,4 +8562,89 @@ public static String wrap(final String str, final String wrapWith) { return wrapWith.concat(str).concat(wrapWith); } + + /** + *

+ * Wraps a string with a char if that char is missing from the start or end of the given string. + *

+ * + *
+     * StringUtils.wrap(null, *)        = null
+     * StringUtils.wrap("", *)          = ""
+     * StringUtils.wrap("ab", '\0')     = "ab"
+     * StringUtils.wrap("ab", 'x')      = "xabx"
+     * StringUtils.wrap("ab", '\'')     = "'ab'"
+     * StringUtils.wrap("\"ab\"", '\"') = "\"ab\""
+     * StringUtils.wrap("/", '/')  = "/"
+     * StringUtils.wrap("a/b/c", '/')  = "/a/b/c/"
+     * StringUtils.wrap("/a/b/c", '/')  = "/a/b/c/"
+     * StringUtils.wrap("a/b/c/", '/')  = "/a/b/c/"
+     * 
+ * + * @param str + * the string to be wrapped, may be {@code null} + * @param wrapWith + * the char that will wrap {@code str} + * @return the wrapped string, or {@code null} if {@code str==null} + * @since 3.5 + */ + public static String wrapIfMissing(final String str, final char wrapWith) { + if (isEmpty(str) || wrapWith == '\0') { + return str; + } + StringBuilder builder = new StringBuilder(str.length() + 2); + if (str.charAt(0) != wrapWith) { + builder.append(wrapWith); + } + builder.append(str); + if (str.charAt(str.length() - 1) != wrapWith) { + builder.append(wrapWith); + } + return builder.toString(); + } + + /** + *

+ * Wraps a string with a string if that string is missing from the start or end of the given string. + *

+ * + *
+     * StringUtils.wrap(null, *)         = null
+     * StringUtils.wrap("", *)           = ""
+     * StringUtils.wrap("ab", null)      = "ab"
+     * StringUtils.wrap("ab", "x")       = "xabx"
+     * StringUtils.wrap("ab", "\"")      = "\"ab\""
+     * StringUtils.wrap("\"ab\"", "\"")  = "\"ab\""
+     * StringUtils.wrap("ab", "'")       = "'ab'"
+     * StringUtils.wrap("'abcd'", "'")   = "'abcd'"
+     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
+     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
+     * StringUtils.wrap("/", "/")  = "/"
+     * StringUtils.wrap("a/b/c", "/")  = "/a/b/c/"
+     * StringUtils.wrap("/a/b/c", "/")  = "/a/b/c/"
+     * StringUtils.wrap("a/b/c/", "/")  = "/a/b/c/"
+     * 
+ * + * @param str + * the string to be wrapped, may be {@code null} + * @param wrapWith + * the char that will wrap {@code str} + * @return the wrapped string, or {@code null} if {@code str==null} + * @since 3.5 + */ + public static String wrapIfMissing(final String str, final String wrapWith) { + if (isEmpty(str) || isEmpty(wrapWith)) { + return str; + } + StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length()); + if (!str.startsWith(wrapWith)) { + builder.append(wrapWith); + } + builder.append(str); + if (!str.endsWith(wrapWith)) { + builder.append(wrapWith); + } + return builder.toString(); + } + } diff --git a/src/test/java/org/apache/commons/lang3/StringUtilsTest.java b/src/test/java/org/apache/commons/lang3/StringUtilsTest.java index bd1b07d79..75cfa383e 100644 --- a/src/test/java/org/apache/commons/lang3/StringUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/StringUtilsTest.java @@ -2837,11 +2837,9 @@ public void testToEncodedString() { @Test public void testWrap_StringChar() { - assertNull(StringUtils.wrap(null, null)); assertNull(StringUtils.wrap(null, '\0')); assertNull(StringUtils.wrap(null, '1')); - assertEquals(null, StringUtils.wrap(null, null)); assertEquals("", StringUtils.wrap("", '\0')); assertEquals("xabx", StringUtils.wrap("ab", 'x')); assertEquals("\"ab\"", StringUtils.wrap("ab", '\"')); @@ -2852,6 +2850,48 @@ public void testWrap_StringChar() { assertEquals("\"'abcd'\"", StringUtils.wrap("'abcd'", '\"')); } + @Test + public void testWrapIfMissing_StringChar() { + assertNull(StringUtils.wrapIfMissing(null, '\0')); + assertNull(StringUtils.wrapIfMissing(null, '1')); + + assertEquals("", StringUtils.wrapIfMissing("", '\0')); + assertEquals("xabx", StringUtils.wrapIfMissing("ab", 'x')); + assertEquals("\"ab\"", StringUtils.wrapIfMissing("ab", '\"')); + assertEquals("\"ab\"", StringUtils.wrapIfMissing("\"ab\"", '\"')); + assertEquals("'ab'", StringUtils.wrapIfMissing("ab", '\'')); + assertEquals("'abcd'", StringUtils.wrapIfMissing("'abcd'", '\'')); + assertEquals("'\"abcd\"'", StringUtils.wrapIfMissing("\"abcd\"", '\'')); + assertEquals("\"'abcd'\"", StringUtils.wrapIfMissing("'abcd'", '\"')); + assertEquals("/x/", StringUtils.wrapIfMissing("x", '/')); + assertEquals("/x/y/z/", StringUtils.wrapIfMissing("x/y/z", '/')); + assertEquals("/x/y/z/", StringUtils.wrapIfMissing("/x/y/z", '/')); + assertEquals("/x/y/z/", StringUtils.wrapIfMissing("x/y/z/", '/')); + assertEquals("/", StringUtils.wrapIfMissing("/", '/')); + } + + @Test + public void testWrapIfMissing_StringString() { + assertNull(StringUtils.wrapIfMissing(null, "\0")); + assertNull(StringUtils.wrapIfMissing(null, "1")); + + assertEquals("", StringUtils.wrapIfMissing("", "\0")); + assertEquals("xabx", StringUtils.wrapIfMissing("ab", "x")); + assertEquals("\"ab\"", StringUtils.wrapIfMissing("ab", "\"")); + assertEquals("\"ab\"", StringUtils.wrapIfMissing("\"ab\"", "\"")); + assertEquals("'ab'", StringUtils.wrapIfMissing("ab", "\'")); + assertEquals("'abcd'", StringUtils.wrapIfMissing("'abcd'", "\'")); + assertEquals("'\"abcd\"'", StringUtils.wrapIfMissing("\"abcd\"", "\'")); + assertEquals("\"'abcd'\"", StringUtils.wrapIfMissing("'abcd'", "\"")); + assertEquals("/x/", StringUtils.wrapIfMissing("x", "/")); + assertEquals("/x/y/z/", StringUtils.wrapIfMissing("x/y/z", "/")); + assertEquals("/x/y/z/", StringUtils.wrapIfMissing("/x/y/z", "/")); + assertEquals("/x/y/z/", StringUtils.wrapIfMissing("x/y/z/", "/")); + assertEquals("/", StringUtils.wrapIfMissing("/", "/")); + assertEquals("ab/ab", StringUtils.wrapIfMissing("/", "ab")); + assertEquals("ab/ab", StringUtils.wrapIfMissing("ab/ab", "ab")); + } + @Test public void testWrap_StringString() { assertNull(StringUtils.wrap(null, null));