From 24e64686834ecd4a0dda80c91b53b15e227fc898 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 4 Nov 2019 17:53:58 -0500 Subject: [PATCH] [LANG-1498] Add support of lambda value evaluation for defaulting methods #416. --- .../org/apache/commons/lang3/ObjectUtils.java | 54 +++++++------- .../org/apache/commons/lang3/StringUtils.java | 61 +++++++++++++++- .../apache/commons/lang3/ObjectUtilsTest.java | 12 ++-- .../apache/commons/lang3/StringUtilsTest.java | 71 ++++++++++++++++--- 4 files changed, 157 insertions(+), 41 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/ObjectUtils.java b/src/main/java/org/apache/commons/lang3/ObjectUtils.java index 175f3c033..3b83ce16c 100644 --- a/src/main/java/org/apache/commons/lang3/ObjectUtils.java +++ b/src/main/java/org/apache/commons/lang3/ObjectUtils.java @@ -154,30 +154,6 @@ public static boolean isNotEmpty(final Object object) { return !isEmpty(object); } - /** - *

Returns the given {@code object} is it is non-null, otherwise returns the Supplier's get value.

- * - *

The caller responsible for thread-safety and exception handling of default value supplier.

- * - *
-     * ObjectUtils.getIfNull(null, () -> null)        = null
-     * ObjectUtils.getIfNull(null, null)              = null
-     * ObjectUtils.getIfNull(null, () -> "")          = ""
-     * ObjectUtils.getIfNull(null, () -> "zz")        = "zz"
-     * ObjectUtils.getIfNull("abc", *)                = "abc"
-     * ObjectUtils.getIfNull(Boolean.TRUE, *)         = Boolean.TRUE
-     * 
- * - * @param the type of the object - * @param object the {@code Object} to test, may be {@code null} - * @param defaultSupplier the default value to return, may be {@code null} - * @return {@code object} if it is not {@code null}, {@code defaultValueSupplier.get()} otherwise - * @since 3.10 - */ - public static T defaultIfNull(final T object, final Supplier defaultSupplier) { - return object != null ? object : defaultSupplier == null ? null : defaultSupplier.get(); - } - /** *

Returns a default value if the object passed is {@code null}.

* @@ -193,6 +169,7 @@ public static T defaultIfNull(final T object, final Supplier defaultSuppl * @param object the {@code Object} to test, may be {@code null} * @param defaultValue the default value to return, may be {@code null} * @return {@code object} if it is not {@code null}, defaultValue otherwise + * TODO Rename to getIfNull in 4.0 */ public static T defaultIfNull(final T object, final T defaultValue) { return object != null ? object : defaultValue; @@ -232,6 +209,35 @@ public static T firstNonNull(final T... values) { return null; } + /** + *

+ * Returns the given {@code object} is it is non-null, otherwise returns the Supplier's {@link Supplier#get()} + * value. + *

+ * + *

+ * The caller responsible for thread-safety and exception handling of default value supplier. + *

+ * + *
+     * ObjectUtils.getIfNull(null, () -> null)     = null
+     * ObjectUtils.getIfNull(null, null)              = null
+     * ObjectUtils.getIfNull(null, () -> "")       = ""
+     * ObjectUtils.getIfNull(null, () -> "zz")     = "zz"
+     * ObjectUtils.getIfNull("abc", *)                = "abc"
+     * ObjectUtils.getIfNull(Boolean.TRUE, *)         = Boolean.TRUE
+     * 
+ * + * @param the type of the object + * @param object the {@code Object} to test, may be {@code null} + * @param defaultSupplier the default value to return, may be {@code null} + * @return {@code object} if it is not {@code null}, {@code defaultValueSupplier.get()} otherwise + * @since 3.10 + */ + public static T getIfNull(final T object, final Supplier defaultSupplier) { + return object != null ? object : defaultSupplier == null ? null : defaultSupplier.get(); + } + /** * Checks if any value in the given array is not {@code null}. * diff --git a/src/main/java/org/apache/commons/lang3/StringUtils.java b/src/main/java/org/apache/commons/lang3/StringUtils.java index fe2d78fec..ea991276f 100644 --- a/src/main/java/org/apache/commons/lang3/StringUtils.java +++ b/src/main/java/org/apache/commons/lang3/StringUtils.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.function.Supplier; import java.util.regex.Pattern; /** @@ -1481,7 +1482,6 @@ public static T defaultIfBlank(final T str, final T def return isBlank(str) ? defaultStr : str; } - /** *

Returns either the passed in CharSequence, or if the CharSequence is * empty or {@code null}, the value of {@code defaultStr}.

@@ -1504,8 +1504,6 @@ public static T defaultIfEmpty(final T str, final T def return isEmpty(str) ? defaultStr : str; } - // Defaults - //----------------------------------------------------------------------- /** *

Returns either the passed in String, * or if the String is {@code null}, an empty String ("").

@@ -2148,6 +2146,63 @@ public static int getFuzzyDistance(final CharSequence term, final CharSequence q return score; } + /** + *

Returns either the passed in CharSequence, or if the CharSequence is + * whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}.

+ * + *

Whitespace is defined by {@link Character#isWhitespace(char)}.

+ * + *

Caller responsible for thread-safety and exception handling of default value supplier

+ * + *
+     * {@code
+     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
+     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
+     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
+     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
+     * StringUtils.getIfBlank("", () -> null)       = null
+     * StringUtils.getIfBlank("", null)             = null
+     * }
+ * @param the specific kind of CharSequence + * @param str the CharSequence to check, may be null + * @param defaultSupplier the supplier of default CharSequence to return + * if the input is whitespace, empty ("") or {@code null}, may be null + * @return the passed in CharSequence, or the default + * @see StringUtils#defaultString(String, String) + * @since 3.10 + */ + public static T getIfBlank(final T str, final Supplier defaultSupplier) { + return isBlank(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str; + } + + /** + *

Returns either the passed in CharSequence, or if the CharSequence is + * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.

+ * + *

Caller responsible for thread-safety and exception handling of default value supplier

+ * + *
+     * {@code
+     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
+     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
+     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
+     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
+     * StringUtils.getIfEmpty("", () -> null)        = null
+     * StringUtils.getIfEmpty("", null)              = null
+     * }
+     * 
+ * @param the specific kind of CharSequence + * @param str the CharSequence to check, may be null + * @param defaultSupplier the supplier of default CharSequence to return + * if the input is empty ("") or {@code null}, may be null + * @return the passed in CharSequence, or the default + * @see StringUtils#defaultString(String, String) + * @since 3.10 + */ + public static T getIfEmpty(final T str, final Supplier defaultSupplier) { + return isEmpty(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str; + } + /** *

Find the Jaro Winkler Distance which indicates the similarity score between two Strings.

* diff --git a/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java b/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java index 84059f4ab..b181524b0 100644 --- a/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java @@ -116,18 +116,18 @@ public void testDefaultIfNull() { final Object dflt = BAR; assertSame(dflt, ObjectUtils.defaultIfNull(null, dflt), "dflt was not returned when o was null"); assertSame(o, ObjectUtils.defaultIfNull(o, dflt), "dflt was returned when o was not null"); - assertSame(dflt, ObjectUtils.defaultIfNull(null, () -> dflt), "dflt was not returned when o was null"); - assertSame(o, ObjectUtils.defaultIfNull(o, () -> dflt), "dflt was returned when o was not null"); - assertSame(o, ObjectUtils.defaultIfNull(FOO, () -> dflt), "dflt was returned when o was not null"); - assertSame(o, ObjectUtils.defaultIfNull("foo", () -> dflt), "dflt was returned when o was not null"); + assertSame(dflt, ObjectUtils.getIfNull(null, () -> dflt), "dflt was not returned when o was null"); + assertSame(o, ObjectUtils.getIfNull(o, () -> dflt), "dflt was returned when o was not null"); + assertSame(o, ObjectUtils.getIfNull(FOO, () -> dflt), "dflt was returned when o was not null"); + assertSame(o, ObjectUtils.getIfNull("foo", () -> dflt), "dflt was returned when o was not null"); MutableInt callsCounter = new MutableInt(0); Supplier countingDefaultSupplier = () -> { callsCounter.increment(); return dflt; }; - ObjectUtils.defaultIfNull(o, countingDefaultSupplier); + ObjectUtils.getIfNull(o, countingDefaultSupplier); assertEquals(0, callsCounter.getValue()); - ObjectUtils.defaultIfNull(null, countingDefaultSupplier); + ObjectUtils.getIfNull(null, countingDefaultSupplier); assertEquals(1, callsCounter.getValue()); } diff --git a/src/test/java/org/apache/commons/lang3/StringUtilsTest.java b/src/test/java/org/apache/commons/lang3/StringUtilsTest.java index 9f36c6d5b..95e98afd0 100644 --- a/src/test/java/org/apache/commons/lang3/StringUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/StringUtilsTest.java @@ -39,8 +39,10 @@ import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.function.Supplier; import java.util.regex.PatternSyntaxException; +import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.text.WordUtils; import org.junit.jupiter.api.Test; @@ -622,7 +624,7 @@ public void testDefaultIfBlank_CharBuffers() { assertEquals("NULL", StringUtils.defaultIfBlank(CharBuffer.wrap(""), CharBuffer.wrap("NULL")).toString()); assertEquals("NULL", StringUtils.defaultIfBlank(CharBuffer.wrap(" "), CharBuffer.wrap("NULL")).toString()); assertEquals("abc", StringUtils.defaultIfBlank(CharBuffer.wrap("abc"), CharBuffer.wrap("NULL")).toString()); - assertNull(StringUtils.defaultIfBlank(CharBuffer.wrap(""), null)); + assertNull(StringUtils.defaultIfBlank(CharBuffer.wrap(""), (CharBuffer) null)); // Tests compatibility for the API return type final CharBuffer s = StringUtils.defaultIfBlank(CharBuffer.wrap("abc"), CharBuffer.wrap("NULL")); assertEquals("abc", s.toString()); @@ -633,7 +635,7 @@ public void testDefaultIfBlank_StringBuffers() { assertEquals("NULL", StringUtils.defaultIfBlank(new StringBuffer(""), new StringBuffer("NULL")).toString()); assertEquals("NULL", StringUtils.defaultIfBlank(new StringBuffer(" "), new StringBuffer("NULL")).toString()); assertEquals("abc", StringUtils.defaultIfBlank(new StringBuffer("abc"), new StringBuffer("NULL")).toString()); - assertNull(StringUtils.defaultIfBlank(new StringBuffer(""), null)); + assertNull(StringUtils.defaultIfBlank(new StringBuffer(""), (StringBuffer) null)); // Tests compatibility for the API return type final StringBuffer s = StringUtils.defaultIfBlank(new StringBuffer("abc"), new StringBuffer("NULL")); assertEquals("abc", s.toString()); @@ -644,7 +646,7 @@ public void testDefaultIfBlank_StringBuilders() { assertEquals("NULL", StringUtils.defaultIfBlank(new StringBuilder(""), new StringBuilder("NULL")).toString()); assertEquals("NULL", StringUtils.defaultIfBlank(new StringBuilder(" "), new StringBuilder("NULL")).toString()); assertEquals("abc", StringUtils.defaultIfBlank(new StringBuilder("abc"), new StringBuilder("NULL")).toString()); - assertNull(StringUtils.defaultIfBlank(new StringBuilder(""), null)); + assertNull(StringUtils.defaultIfBlank(new StringBuilder(""), (StringBuilder) null)); // Tests compatibility for the API return type final StringBuilder s = StringUtils.defaultIfBlank(new StringBuilder("abc"), new StringBuilder("NULL")); assertEquals("abc", s.toString()); @@ -656,17 +658,45 @@ public void testDefaultIfBlank_StringString() { assertEquals("NULL", StringUtils.defaultIfBlank("", "NULL")); assertEquals("NULL", StringUtils.defaultIfBlank(" ", "NULL")); assertEquals("abc", StringUtils.defaultIfBlank("abc", "NULL")); - assertNull(StringUtils.defaultIfBlank("", null)); + assertNull(StringUtils.defaultIfBlank("", (String) null)); // Tests compatibility for the API return type final String s = StringUtils.defaultIfBlank("abc", "NULL"); assertEquals("abc", s); } + + @Test + public void testGetIfBlank_StringStringSupplier() { + assertEquals("NULL", StringUtils.getIfBlank(null, () -> "NULL")); + assertEquals("NULL", StringUtils.getIfBlank("", () -> "NULL")); + assertEquals("NULL", StringUtils.getIfBlank(" ", () -> "NULL")); + assertEquals("abc", StringUtils.getIfBlank("abc", () -> "NULL")); + assertNull(StringUtils.getIfBlank("", () -> null)); + assertNull(StringUtils.defaultIfBlank("", (String) null)); + // Tests compatibility for the API return type + final String s = StringUtils.getIfBlank("abc", () -> "NULL"); + assertEquals("abc", s); + //Checking that default value supplied only on demand + MutableInt numberOfCalls = new MutableInt(0); + Supplier countingDefaultSupplier = () -> { + numberOfCalls.increment(); + return "NULL"; + }; + StringUtils.getIfBlank("abc", countingDefaultSupplier); + assertEquals(0, numberOfCalls.getValue()); + StringUtils.getIfBlank("", countingDefaultSupplier); + assertEquals(1, numberOfCalls.getValue()); + StringUtils.getIfBlank(" ", countingDefaultSupplier); + assertEquals(2, numberOfCalls.getValue()); + StringUtils.getIfBlank(null, countingDefaultSupplier); + assertEquals(3, numberOfCalls.getValue()); + } + @Test public void testDefaultIfEmpty_CharBuffers() { assertEquals("NULL", StringUtils.defaultIfEmpty(CharBuffer.wrap(""), CharBuffer.wrap("NULL")).toString()); assertEquals("abc", StringUtils.defaultIfEmpty(CharBuffer.wrap("abc"), CharBuffer.wrap("NULL")).toString()); - assertNull(StringUtils.defaultIfEmpty(CharBuffer.wrap(""), null)); + assertNull(StringUtils.defaultIfEmpty(CharBuffer.wrap(""), (CharBuffer) null)); // Tests compatibility for the API return type final CharBuffer s = StringUtils.defaultIfEmpty(CharBuffer.wrap("abc"), CharBuffer.wrap("NULL")); assertEquals("abc", s.toString()); @@ -677,7 +707,7 @@ public void testDefaultIfEmpty_CharBuffers() { public void testDefaultIfEmpty_StringBuffers() { assertEquals("NULL", StringUtils.defaultIfEmpty(new StringBuffer(""), new StringBuffer("NULL")).toString()); assertEquals("abc", StringUtils.defaultIfEmpty(new StringBuffer("abc"), new StringBuffer("NULL")).toString()); - assertNull(StringUtils.defaultIfEmpty(new StringBuffer(""), null)); + assertNull(StringUtils.defaultIfEmpty(new StringBuffer(""), (StringBuffer) null)); // Tests compatibility for the API return type final StringBuffer s = StringUtils.defaultIfEmpty(new StringBuffer("abc"), new StringBuffer("NULL")); assertEquals("abc", s.toString()); @@ -687,7 +717,7 @@ public void testDefaultIfEmpty_StringBuffers() { public void testDefaultIfEmpty_StringBuilders() { assertEquals("NULL", StringUtils.defaultIfEmpty(new StringBuilder(""), new StringBuilder("NULL")).toString()); assertEquals("abc", StringUtils.defaultIfEmpty(new StringBuilder("abc"), new StringBuilder("NULL")).toString()); - assertNull(StringUtils.defaultIfEmpty(new StringBuilder(""), null)); + assertNull(StringUtils.defaultIfEmpty(new StringBuilder(""), (StringBuilder) null)); // Tests compatibility for the API return type final StringBuilder s = StringUtils.defaultIfEmpty(new StringBuilder("abc"), new StringBuilder("NULL")); assertEquals("abc", s.toString()); @@ -698,12 +728,37 @@ public void testDefaultIfEmpty_StringString() { assertEquals("NULL", StringUtils.defaultIfEmpty(null, "NULL")); assertEquals("NULL", StringUtils.defaultIfEmpty("", "NULL")); assertEquals("abc", StringUtils.defaultIfEmpty("abc", "NULL")); - assertNull(StringUtils.defaultIfEmpty("", null)); + assertNull(StringUtils.getIfEmpty("", null)); // Tests compatibility for the API return type final String s = StringUtils.defaultIfEmpty("abc", "NULL"); assertEquals("abc", s); } + @Test + public void testGetIfEmpty_StringStringSupplier() { + assertEquals("NULL", StringUtils.getIfEmpty((String) null, () -> "NULL")); + assertEquals("NULL", StringUtils.getIfEmpty("", () -> "NULL")); + assertEquals("abc", StringUtils.getIfEmpty("abc", () -> "NULL")); + assertNull(StringUtils.getIfEmpty("", () -> null)); + assertNull(StringUtils.defaultIfEmpty("", (String) null)); + // Tests compatibility for the API return type + final String s = StringUtils.getIfEmpty("abc", () -> "NULL"); + assertEquals("abc", s); + //Checking that default value supplied only on demand + MutableInt numberOfCalls = new MutableInt(0); + Supplier countingDefaultSupplier = () -> { + numberOfCalls.increment(); + return "NULL"; + }; + StringUtils.getIfEmpty("abc", countingDefaultSupplier); + assertEquals(0, numberOfCalls.getValue()); + StringUtils.getIfEmpty("", countingDefaultSupplier); + assertEquals(1, numberOfCalls.getValue()); + StringUtils.getIfEmpty(null, countingDefaultSupplier); + assertEquals(2, numberOfCalls.getValue()); + } + + @Test public void testDeleteWhitespace_String() { assertNull(StringUtils.deleteWhitespace(null));