This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 1f4f57dc6f StringUtils improvements
1f4f57dc6f is described below
commit 1f4f57dc6f2b8edc4faa93fb4a5b08cf8f1ca458
Author: James Bognar <[email protected]>
AuthorDate: Sun Nov 30 11:20:54 2025 -0500
StringUtils improvements
---
.../org/apache/juneau/bean/openapi3/Items.java | 6 +-
.../org/apache/juneau/bean/openapi3/Parameter.java | 6 +-
.../juneau/bean/openapi3/SecuritySchemeInfo.java | 6 +-
.../apache/juneau/common/utils/StringUtils.java | 129 +++++++++++++++------
.../juneau/common/utils/StringUtils_Test.java | 8 +-
5 files changed, 105 insertions(+), 50 deletions(-)
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
index f857952275..9f3f272b13 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
@@ -19,7 +19,7 @@ package org.apache.juneau.bean.openapi3;
import static org.apache.juneau.common.utils.AssertionUtils.*;
import static org.apache.juneau.common.utils.CollectionUtils.*;
import static org.apache.juneau.common.utils.StringUtils.*;
-import static org.apache.juneau.common.utils.StringUtils.containsAny;
+import static org.apache.juneau.common.utils.StringUtils.contains;
import static org.apache.juneau.common.utils.ThrowableUtils.*;
import static org.apache.juneau.common.utils.Utils.*;
import static org.apache.juneau.internal.ConverterUtils.*;
@@ -434,7 +434,7 @@ public class Items extends OpenApiElement {
* @return This object
*/
public Items setCollectionFormat(String value) {
- if (isStrict() && ! containsAny(value,
VALID_COLLECTION_FORMATS))
+ if (isStrict() && ! contains(value, VALID_COLLECTION_FORMATS))
throw rex("Invalid value passed in to
setCollectionFormat(String). Value=''{0}'', valid values=[{1}]", value,
toCdl(VALID_COLLECTION_FORMATS));
collectionFormat = value;
return this;
@@ -706,7 +706,7 @@ public class Items extends OpenApiElement {
* @return This object
*/
public Items setType(String value) {
- if (isStrict() && ! containsAny(value, VALID_TYPES))
+ if (isStrict() && ! contains(value, VALID_TYPES))
throw illegalArg("Invalid value passed in to
setType(String). Value=''{0}'', valid values={1}", value,
Json5Serializer.DEFAULT.toString(VALID_TYPES));
type = value;
return this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
index b29125c287..c3c7bc4184 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
@@ -18,7 +18,7 @@ package org.apache.juneau.bean.openapi3;
import static org.apache.juneau.common.utils.AssertionUtils.*;
import static org.apache.juneau.common.utils.CollectionUtils.*;
-import static org.apache.juneau.common.utils.StringUtils.containsAny;
+import static org.apache.juneau.common.utils.StringUtils.contains;
import static org.apache.juneau.common.utils.ThrowableUtils.*;
import static org.apache.juneau.common.utils.Utils.*;
import static org.apache.juneau.internal.ConverterUtils.*;
@@ -357,7 +357,7 @@ public class Parameter extends OpenApiElement {
* @return This object.
*/
public Parameter setIn(String value) {
- if (isStrict() && ! containsAny(value, VALID_IN))
+ if (isStrict() && ! contains(value, VALID_IN))
throw rex("Invalid value passed in to setIn(String).
Value=''{0}'', valid values={1}", value, Json5.of(VALID_IN));
this.in = value;
return this;
@@ -403,7 +403,7 @@ public class Parameter extends OpenApiElement {
* @return This object.
*/
public Parameter setStyle(String value) {
- if (isStrict() && ! containsAny(value, VALID_STYLES))
+ if (isStrict() && ! contains(value, VALID_STYLES))
throw rex("Invalid value passed in to setStyle(String).
Value=''{0}'', valid values={1}", value, Json5.of(VALID_STYLES));
this.style = value;
return this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
index 1a1ec0fe3b..78e153178b 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
@@ -19,7 +19,7 @@ package org.apache.juneau.bean.openapi3;
import static org.apache.juneau.common.utils.AssertionUtils.*;
import static org.apache.juneau.common.utils.CollectionUtils.*;
import static org.apache.juneau.common.utils.StringUtils.*;
-import static org.apache.juneau.common.utils.StringUtils.containsAny;
+import static org.apache.juneau.common.utils.StringUtils.contains;
import static org.apache.juneau.common.utils.ThrowableUtils.*;
import static org.apache.juneau.common.utils.Utils.*;
import static org.apache.juneau.internal.ConverterUtils.*;
@@ -341,7 +341,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
* @return This object
*/
public SecuritySchemeInfo setIn(String value) {
- if (isStrict() && ! containsAny(value, VALID_IN))
+ if (isStrict() && ! contains(value, VALID_IN))
throw rex("Invalid value passed in to setIn(String).
Value=''{0}'', valid values=[{1}]", value, toCdl(VALID_IN));
in = value;
return this;
@@ -431,7 +431,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
* @return This object
*/
public SecuritySchemeInfo setType(String value) {
- if (isStrict() && ! containsAny(value, VALID_TYPES))
+ if (isStrict() && ! contains(value, VALID_TYPES))
throw rex("Invalid value passed in to setType(String).
Value=''{0}'', valid values=[{1}]", value, toCdl(VALID_TYPES));
type = value;
return this;
diff --git
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
index 2b4cf29fdc..e3f5dd903b 100644
---
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
+++
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
@@ -388,13 +388,32 @@ public class StringUtils {
}
/**
- * Null-safe {@link String#contains(CharSequence)} operation.
+ * Checks if a string contains any of the specified substrings.
+ *
+ * <p>
+ * This is a null-safe operation that returns <jk>false</jk> if:
+ * <ul>
+ * <li>The string is <jk>null</jk></li>
+ * <li>The values array is <jk>null</jk> or empty</li>
+ * <li>None of the specified substrings are found in the string</li>
+ * </ul>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * containsAny(<js>"Hello World"</js>, <js>"Hello"</js>,
<js>"Foo"</js>); <jc>// true (contains "Hello")</jc>
+ * containsAny(<js>"Hello World"</js>, <js>"Foo"</js>,
<js>"Bar"</js>); <jc>// false</jc>
+ * containsAny(<jk>null</jk>, <js>"Hello"</js>);
<jc>// false</jc>
+ * containsAny(<js>"Hello"</js>);
<jc>// false (no values to check)</jc>
+ * </p>
*
* @param s The string to check.
* @param values The substrings to check for.
* @return <jk>true</jk> if the string contains any of the specified
substrings.
+ * @see #contains(String, CharSequence)
+ * @see #contains(String, char...)
+ * @see #notContains(String, String...)
*/
- public static boolean containsAny(String s, String...values) {
+ public static boolean contains(String s, String...values) {
if (s == null || values == null || values.length == 0)
return false;
for (var v : values) {
@@ -404,27 +423,6 @@ public class StringUtils {
return false;
}
- /**
- * Returns <jk>true</jk> if the specified string contains any of the
specified characters.
- *
- * @param s The string to test.
- * @param chars The characters to look for.
- * @return
- * <jk>true</jk> if the specified string contains any of the
specified characters.
- * <br><jk>false</jk> if the string is <jk>null</jk>.
- */
- public static boolean containsAny(String s, char...chars) {
- if (s == null)
- return false;
- for (int i = 0, j = s.length(); i < j; i++) {
- var c = s.charAt(i);
- for (var c2 : chars)
- if (c == c2)
- return true;
- }
- return false;
- }
-
/**
* Counts the number of the specified character in the specified string.
*
@@ -2909,18 +2907,29 @@ public class StringUtils {
}
/**
- * Compares two strings for equality, ignoring case.
+ * Tests two strings for case-insensitive equality, but gracefully
handles nulls.
+ *
+ * <p>
+ * This method handles <jk>null</jk> values gracefully:
+ * <ul>
+ * <li>Both <jk>null</jk> → returns <jk>true</jk> (same reference
check)</li>
+ * <li>One <jk>null</jk> → returns <jk>false</jk></li>
+ * <li>Neither <jk>null</jk> → compares strings ignoring case</li>
+ * </ul>
*
* <h5 class='section'>Example:</h5>
* <p class='bjava'>
* equalsIgnoreCase(<js>"Hello"</js>, <js>"hello"</js>);
<jc>// true</jc>
* equalsIgnoreCase(<js>"Hello"</js>, <js>"WORLD"</js>);
<jc>// false</jc>
* equalsIgnoreCase(<jk>null</jk>, <jk>null</jk>);
<jc>// true</jc>
+ * equalsIgnoreCase(<js>"Hello"</js>, <jk>null</jk>);
<jc>// false</jc>
* </p>
*
* @param str1 The first string.
* @param str2 The second string.
* @return <jk>true</jk> if the strings are equal ignoring case,
<jk>false</jk> otherwise.
+ * @see #equalsIgnoreCase(Object, Object)
+ * @see Utils#eqic(String, String)
*/
public static boolean equalsIgnoreCase(String str1, String str2) {
if (str1 == str2)
@@ -4961,7 +4970,7 @@ public class StringUtils {
if (isEmpty(s))
return a();
- if (! containsAny(s, ' ', '\t', '\'', '"'))
+ if (! contains(s, ' ', '\t', '\'', '"'))
return a(s);
// S1: Looking for start of token.
@@ -6768,20 +6777,30 @@ public class StringUtils {
//------------------------------------------------------------------------------------------------------------------
/**
+ * Null-safe convenience method for {@link String#toLowerCase()}.
+ *
+ * <p>
* Converts the string to lowercase if not null.
*
* @param s The string to convert.
* @return The lowercase string, or <jk>null</jk> if the input was
<jk>null</jk>.
+ * @see #upperCase(String)
+ * @see Utils#lc(String)
*/
public static String lowerCase(String s) {
return s == null ? null : s.toLowerCase();
}
/**
+ * Null-safe convenience method for {@link String#toUpperCase()}.
+ *
+ * <p>
* Converts the string to uppercase if not null.
*
* @param s The string to convert.
* @return The uppercase string, or <jk>null</jk> if the input was
<jk>null</jk>.
+ * @see #lowerCase(String)
+ * @see Utils#uc(String)
*/
public static String upperCase(String s) {
return s == null ? null : s.toUpperCase();
@@ -6790,11 +6809,29 @@ public class StringUtils {
/**
* Tests two objects for case-insensitive string equality.
*
- * <p>Converts both objects to strings using {@link Object#toString()}
before comparison.
+ * <p>
+ * Converts both objects to strings using {@link Object#toString()}
before comparison.
+ * This method handles <jk>null</jk> values gracefully:
+ * <ul>
+ * <li>Both <jk>null</jk> → returns <jk>true</jk></li>
+ * <li>One <jk>null</jk> → returns <jk>false</jk></li>
+ * <li>Neither <jk>null</jk> → compares string representations
ignoring case</li>
+ * </ul>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * equalsIgnoreCase(<js>"Hello"</js>, <js>"HELLO"</js>);
<jc>// true</jc>
+ * equalsIgnoreCase(<js>"Hello"</js>, <js>"World"</js>);
<jc>// false</jc>
+ * equalsIgnoreCase(<jk>null</jk>, <jk>null</jk>);
<jc>// true</jc>
+ * equalsIgnoreCase(<js>"Hello"</js>, <jk>null</jk>);
<jc>// false</jc>
+ * equalsIgnoreCase(123, <js>"123"</js>);
<jc>// true (converts 123 to "123")</jc>
+ * </p>
*
* @param a Object 1.
* @param b Object 2.
* @return <jk>true</jk> if both objects are equal ignoring case.
+ * @see #equalsIgnoreCase(String, String)
+ * @see Utils#eqic(Object, Object)
*/
public static boolean equalsIgnoreCase(Object a, Object b) {
if (a == null && b == null)
@@ -6817,6 +6854,35 @@ public class StringUtils {
return (vowels.contains(subject.charAt(0)) ? "an " : "a ") +
subject;
}
+ /**
+ * Returns <jk>true</jk> if the string does not contain any of the
specified substrings.
+ *
+ * <p>
+ * This is the inverse of {@link #contains(String, String...)}.
+ * Returns <jk>true</jk> if:
+ * <ul>
+ * <li>The string is <jk>null</jk></li>
+ * <li>The values array is <jk>null</jk> or empty</li>
+ * <li>None of the specified substrings are found in the string</li>
+ * </ul>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * notContains(<js>"Hello World"</js>, <js>"Foo"</js>,
<js>"Bar"</js>); <jc>// true</jc>
+ * notContains(<js>"Hello World"</js>, <js>"Hello"</js>,
<js>"Foo"</js>); <jc>// false (contains "Hello")</jc>
+ * notContains(<jk>null</jk>, <js>"Hello"</js>);
<jc>// true</jc>
+ * </p>
+ *
+ * @param s The string to search.
+ * @param values The values to search for.
+ * @return <jk>true</jk> if the string does not contain any of the
values.
+ * @see #contains(String, String...)
+ * @see #notContains(String, char...)
+ */
+ public static boolean notContains(String s, String...values) {
+ return ! contains(s, values);
+ }
+
/**
* Returns the first non-blank string in the array.
*
@@ -6861,17 +6927,6 @@ public class StringUtils {
return joine(toList(values), ',');
}
- /**
- * Null-safe not-contains check for multiple string values.
- *
- * @param s The string to search.
- * @param values The values to search for.
- * @return <jk>true</jk> if the string does not contain any of the
values.
- */
- public static boolean notContains(String s, String...values) {
- return ! containsAny(s, values);
- }
-
/**
* Converts a comma-delimited string to a set.
*
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/common/utils/StringUtils_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/common/utils/StringUtils_Test.java
index 11c4000bdb..2c3a36453c 100755
---
a/juneau-utest/src/test/java/org/apache/juneau/common/utils/StringUtils_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/common/utils/StringUtils_Test.java
@@ -20,7 +20,7 @@ import static org.apache.juneau.TestUtils.*;
import static org.apache.juneau.common.utils.CollectionUtils.*;
import static org.apache.juneau.common.utils.StringUtils.*;
import static org.apache.juneau.common.utils.StringUtils.compare;
-import static org.apache.juneau.common.utils.StringUtils.containsAny;
+import static org.apache.juneau.common.utils.StringUtils.contains;
import static org.apache.juneau.common.utils.StringUtils.reverse;
import static org.apache.juneau.common.utils.Utils.eqic;
import static org.apache.juneau.junit.bct.BctAssertions.*;
@@ -3234,11 +3234,11 @@ class StringUtils_Test extends TestBase {
assertTrue(contains("test", "te"));
assertTrue(contains("test", "st"));
assertTrue(contains("test", "test"));
- assertTrue(containsAny("test", "te", "xx"));
+ assertTrue(contains("test", "te", "xx"));
assertFalse(contains("test", "xx"));
- assertFalse(containsAny("test", "xx", "yy"));
+ assertFalse(contains("test", "xx", "yy"));
assertFalse(contains(null, "test"));
- assertFalse(containsAny("test", (String[])null));
+ assertFalse(contains("test", (String[])null));
}
@Test