diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/Preconditions.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/Preconditions.java index 67d6e6cc9f..0cded9a5e6 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/Preconditions.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/Preconditions.java @@ -44,6 +44,8 @@ public final class Preconditions { private static final String VALIDATE_IS_NOT_NULL_EX_MESSAGE = "The argument object is NULL"; + private static final String CHECK_ARGUMENT_EX_MESSAGE = + "The argument expression is false"; private Preconditions() { } @@ -122,7 +124,7 @@ public static T checkNotNull(final T obj, final String message, } /** - *

Preconditions that the specified argument is not {@code null}, + * Preconditions that the specified argument is not {@code null}, * throwing a NPE exception otherwise. * *

The message of the exception is {@code msgSupplier.get()}.

@@ -156,8 +158,95 @@ public static T checkNotNull(final T obj, return obj; } + /** + * Ensures the truth of an expression involving one or more parameters to the calling method. + * + * @param expression a boolean expression + * @throws IllegalArgumentException if {@code expression} is false + */ + public static void checkArgument(final boolean expression) { + if (!expression) { + throw new IllegalArgumentException(); + } + } + + /** + * Ensures the truth of an expression involving one or more parameters to the calling method. + * + * @param expression a boolean expression + * @param errorMessage the exception message to use if the check fails; will be converted to a + * string using {@link String#valueOf(Object)} + * @throws IllegalArgumentException if {@code expression} is false + */ + public static void checkArgument(final boolean expression, final Object errorMessage) { + if (!expression) { + throw new IllegalArgumentException(String.valueOf(errorMessage)); + } + } + + /** + * Ensures the truth of an expression involving one or more parameters to the calling method. + * + *

The message of the exception is {@code String.format(f, m)}.

+ * + * @param expression a boolean expression + * @param errorMsg the {@link String#format(String, Object...)} + * exception message if valid. Otherwise, + * the message is {@link #CHECK_ARGUMENT_EX_MESSAGE} + * @param errorMsgArgs the optional values for the formatted exception message. + * @throws IllegalArgumentException if {@code expression} is false + */ + public static void checkArgument( + final boolean expression, + final String errorMsg, + Object... errorMsgArgs) { + if (!expression) { + String msg; + try { + msg = String.format(errorMsg, errorMsgArgs); + } catch (Exception e) { + LOG.debug("Error formatting message", e); + msg = CHECK_ARGUMENT_EX_MESSAGE; + } + throw new IllegalArgumentException(msg); + } + } + + /** + * Preconditions that the expression involving one or more parameters to the calling method. + * + *

The message of the exception is {@code msgSupplier.get()}.

+ * + * @param expression a boolean expression + * @param msgSupplier the {@link Supplier#get()} set the + * exception message if valid. Otherwise, + * the message is {@link #CHECK_ARGUMENT_EX_MESSAGE} + * @throws IllegalArgumentException if {@code expression} is false + */ + public static void checkArgument( + final boolean expression, + final Supplier msgSupplier) { + if (!expression) { + String msg; + try { + // note that we can get NPE evaluating the message itself; + // but we do not want this to override the actual NPE. + msg = msgSupplier.get(); + } catch (Exception e) { + LOG.debug("Error formatting message", e); + msg = CHECK_ARGUMENT_EX_MESSAGE; + } + throw new IllegalArgumentException(msg); + } + } + /* @VisibleForTesting */ static String getDefaultNullMSG() { return VALIDATE_IS_NOT_NULL_EX_MESSAGE; } + + /* @VisibleForTesting */ + static String getDefaultCheckArgumentMSG() { + return CHECK_ARGUMENT_EX_MESSAGE; + } } diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestPreconditions.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestPreconditions.java index 7feffc3163..47917662ad 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestPreconditions.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestPreconditions.java @@ -18,6 +18,8 @@ package org.apache.hadoop.util; +import java.util.function.Supplier; + import org.junit.Test; import org.apache.hadoop.test.LambdaTestUtils; @@ -119,4 +121,104 @@ public void testCheckNotNullFailure() throws Exception { () -> Preconditions.checkNotNull(null, () -> String.format(NULL_FORMATTER, NON_NULL_STRING))); } + + @Test + public void testCheckArgumentWithSuccess() throws Exception { + // success + Preconditions.checkArgument(true); + // null supplier + Preconditions.checkArgument(true, null); + // null message + Preconditions.checkArgument(true, (String) null); + Preconditions.checkArgument(true, NON_NULL_STRING); + // null in string format + Preconditions.checkArgument(true, EXPECTED_ERROR_MSG_ARGS, null, null); + // illegalformat + Preconditions.checkArgument(true, EXPECTED_ERROR_MSG_ARGS, 1, 2); + // ill-formated string supplier + Preconditions.checkArgument(true, ()-> String.format("%d", + NON_INT_STRING)); + // null pattern to string formatter + Preconditions.checkArgument(true, NULL_FORMATTER, null, 1); + // null arguments to string formatter + Preconditions.checkArgument(true, EXPECTED_ERROR_MSG_ARGS, + null, null); + // illegal format exception + Preconditions.checkArgument(true, "message %d %d", + NON_INT_STRING, 1); + // insufficient arguments + Preconditions.checkArgument(true, EXPECTED_ERROR_MSG_ARGS, + NON_INT_STRING); + // null format in string supplier + Preconditions.checkArgument(true, + () -> String.format(NULL_FORMATTER, NON_INT_STRING)); + } + + @Test + public void testCheckArgumentWithFailure() throws Exception { + // failure without message + LambdaTestUtils.intercept(IllegalArgumentException.class, + () -> Preconditions.checkArgument(false)); + errorMessage = null; + // failure with Null message + LambdaTestUtils.intercept(IllegalArgumentException.class, + null, + () -> Preconditions.checkArgument(false, errorMessage)); + // failure with message + errorMessage = EXPECTED_ERROR_MSG; + LambdaTestUtils.intercept(IllegalArgumentException.class, + errorMessage, + () -> Preconditions.checkArgument(false, errorMessage)); + + // failure with message format + errorMessage = EXPECTED_ERROR_MSG + " %s"; + String arg = "IllegalArgExcep"; + String expectedMSG = String.format(errorMessage, arg); + LambdaTestUtils.intercept(IllegalArgumentException.class, + expectedMSG, + () -> Preconditions.checkArgument(false, errorMessage, arg)); + + // failure with multiple arg message format + errorMessage = EXPECTED_ERROR_MSG_ARGS; + expectedMSG = + String.format(errorMessage, arg, 1); + LambdaTestUtils.intercept(IllegalArgumentException.class, + expectedMSG, + () -> Preconditions.checkArgument(false, errorMessage, arg, 1)); + + // ignore illegal format will be thrown if the case is not handled correctly + LambdaTestUtils.intercept(IllegalArgumentException.class, + Preconditions.getDefaultCheckArgumentMSG(), + () -> Preconditions.checkArgument(false, + errorMessage, 1, NON_INT_STRING)); + + // ignore illegal format will be thrown for insufficient Insufficient Args + LambdaTestUtils.intercept(IllegalArgumentException.class, + Preconditions.getDefaultCheckArgumentMSG(), + () -> Preconditions.checkArgument(false, errorMessage, NON_NULL_STRING)); + + // failure with Null supplier + final Supplier nullSupplier = null; + LambdaTestUtils.intercept(IllegalArgumentException.class, + null, + () -> Preconditions.checkArgument(false, nullSupplier)); + + // ignore illegal format in supplier + LambdaTestUtils.intercept(IllegalArgumentException.class, + Preconditions.getDefaultCheckArgumentMSG(), + () -> Preconditions.checkArgument(false, + () -> String.format(errorMessage, 1, NON_INT_STRING))); + + // ignore insufficient arguments in string Supplier + LambdaTestUtils.intercept(IllegalArgumentException.class, + Preconditions.getDefaultCheckArgumentMSG(), + () -> Preconditions.checkArgument(false, + () -> String.format(errorMessage, NON_NULL_STRING))); + + // ignore null formatter + LambdaTestUtils.intercept(IllegalArgumentException.class, + Preconditions.getDefaultCheckArgumentMSG(), + () -> Preconditions.checkArgument(false, + () -> String.format(NULL_FORMATTER, NON_NULL_STRING))); + } }