All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bluecatcode.common.contract.Checks Maven / Gradle / Ivy

package com.bluecatcode.common.contract;

import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;

import javax.annotation.Nullable;
import java.util.regex.Pattern;

import static com.bluecatcode.common.exceptions.Exceptions.*;
import static com.bluecatcode.common.predicates.Predicates.*;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Predicates.not;
import static com.google.common.base.Splitter.on;
import static java.lang.String.format;
import static java.util.regex.Pattern.compile;

/**
 * Use these methods to throw recoverable exceptions if validation fails.
 * Recoverable exceptions are exceptions that a correct program can and should catch and recover from.
 * (Recoverable exceptions may be checked or unchecked.)
 * 

* Checks is an extension to {@link com.google.common.base.Preconditions} *

* In performance critical contexts it is probably better to use hand-written checks, but measure first!. *

*
    *
  • check - Performs check with a predicate
  • *
  • checkNotEmpty - Performs emptiness and nullness check for: * String, CharSequence, Optional, Collection, Iterable, Map, Object[], prim[]
  • *
  • checkMatches - Performs check against a regular expression or a hamcrest matcher
  • *
* * @see com.google.common.base.Preconditions */ public final class Checks { public static final Object[] EMPTY_ERROR_MESSAGE_ARGS = new Object[]{}; private static final String REGEXP_HOSTNAME = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])\\.?$"; /** * Performs check of the condition. * * @param condition condition to check * @param the exception type * @throws IllegalArgumentException if the {@code throwable} is null * @throws IllegalArgumentException if the {@code throwableType} cannot be instantiated * @throws E if the {@code reference} doesn't match provided predicate */ @Beta public static void check(boolean condition, E throwable) throws E { checkArgument(throwable != null, "Expected non-null reference"); if (!condition) { throw throwable; } } /** * Performs check with the predicate. * * @param reference reference to check * @param predicate the predicate to use * @param throwable the throwable to throw * @param the reference type * @param the exception type * @return the original reference * @throws IllegalArgumentException if the {@code reference}, {@code predicate} or {@code throwableType} is null * @throws IllegalArgumentException if the {@code throwableType} cannot be instantiated * @throws E if the {@code reference} doesn't match provided predicate */ @Beta public static T check(T reference, Predicate predicate, E throwable) throws E { checkArgument(reference != null, "Expected non-null reference"); checkArgument(predicate != null, "Expected non-null predicate"); check(predicate.apply(reference), throwable); return reference; } /** * Performs check with the predicate. * * @param reference reference to check * @param predicate the predicate to use * @param throwable the throwable to throw * @param the reference type * @param the exception type * @return the original reference * @throws IllegalArgumentException if the {@code reference}, {@code predicate} or {@code throwableType} is null * @throws IllegalArgumentException if the {@code throwableType} cannot be instantiated * @throws E if the {@code reference} doesn't match provided predicate */ @Beta public static T check(T reference, Predicate predicate, Supplier throwable) throws E { checkArgument(reference != null, "Expected non-null reference"); checkArgument(predicate != null, "Expected non-null predicate"); checkArgument(throwable != null, "Expected non-null throwable supplier"); check(reference, predicate, throwable.get()); return reference; } /** * Performs check with the predicate. * * @param reference reference to check * @param predicate the predicate to use * @param throwableType the throwable type to throw * @param errorMessageTemplate a template for the exception message should the * check fail. The message is formed by replacing each {@code %s} * placeholder in the template with an argument. These are matched by * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. * Unmatched arguments will be appended to the formatted message in square * braces. Unmatched placeholders will be left as-is. * @param errorMessageArgs the arguments to be substituted into the message * template. Arguments are converted to strings using * {@link String#valueOf(Object)}. * @param the reference type * @param the exception type * @return the original reference * @throws IllegalArgumentException if the {@code reference}, {@code predicate} or {@code throwableType} is null * @throws IllegalArgumentException if the {@code throwableType} cannot be instantiated * @throws E if the {@code reference} doesn't match provided predicate */ @Beta public static T check(T reference, Predicate predicate, Class throwableType, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) throws E { checkArgument(reference != null, "Expected non-null reference"); checkArgument(predicate != null, "Expected non-null predicate"); checkArgument(throwableType != null, "Expected non-null throwableType"); check(reference, predicate, (Supplier) () -> throwable( throwableType, parameters(String.class), arguments(messageFromNullable(errorMessageTemplate, errorMessageArgs))) ); return reference; } /** * Performs check with the predicate. * * @param reference reference to check * @param predicate the predicate to use * @param throwableType the throwable type to throw * @param errorMessage the exception message to use if the check fails; will * be converted to a string using {@link String#valueOf(Object)} * @param the reference type * @param the exception type * @return the original reference * @throws IllegalArgumentException if the {@code reference}, {@code predicate} or {@code throwableType} is null * @throws IllegalArgumentException if the {@code throwableType} cannot be instantiated * @throws E if the {@code reference} doesn't match provided predicate */ @Beta public static T check(T reference, Predicate predicate, Class throwableType, @Nullable String errorMessage) throws E { check(reference, predicate, throwableType, String.valueOf(errorMessage), EMPTY_ERROR_MESSAGE_ARGS); return reference; } /** * Performs check with the predicate. * * @param reference reference to check * @param predicate the predicate to use * @param throwableType the throwable type to throw * @param the reference type * @param the exception type * @return the original reference * @throws IllegalArgumentException if the {@code reference}, {@code predicate} or {@code throwableType} is null * @throws IllegalArgumentException if the {@code throwableType} cannot be instantiated * @throws E if the {@code reference} doesn't match provided predicate */ @Beta public static T check(T reference, Predicate predicate, Class throwableType) throws E { check(reference, predicate, throwableType, "Expected to fulfill the predicate, got %s", reference); return reference; } /** * Performs check with the predicate. * * @param reference reference to check * @param predicate the predicate to use * @param errorMessageTemplate a template for the exception message should the * check fail. The message is formed by replacing each {@code %s} * placeholder in the template with an argument. These are matched by * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. * Unmatched arguments will be appended to the formatted message in square * braces. Unmatched placeholders will be left as-is. * @param errorMessageArgs the arguments to be substituted into the message * template. Arguments are converted to strings using * {@link String#valueOf(Object)}. * @param the reference type * @return the original reference * @throws IllegalArgumentException if the {@code reference} or {@code predicate} is null * @throws IllegalArgumentException if the {@code reference} doesn't match provided predicate */ public static T check(T reference, Predicate predicate, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) { checkArgument(reference != null, "Expected non-null reference"); checkArgument(predicate != null, "Expected non-null predicate"); checkArgument(predicate.apply(reference), messageFromNullable(errorMessageTemplate, errorMessageArgs)); return reference; } /** * Performs check with the predicate. * * @param reference the reference to check * @param predicate the predicate to use * @param errorMessage the exception message to use if the check fails; will * be converted to a string using {@link String#valueOf(Object)} * @param the reference type * @return the original reference * @throws IllegalArgumentException if the {@code reference} is empty * @throws NullPointerException if the {@code reference} is null * @see #checkNotEmpty(Object, String, Object...) */ public static T check(T reference, Predicate predicate, @Nullable Object errorMessage) { check(reference, predicate, String.valueOf(errorMessage), EMPTY_ERROR_MESSAGE_ARGS); return reference; } /** * Performs check with the predicate. * * @param reference the reference to check * @param predicate the predicate to use * @param the reference type * @return the original reference * @throws IllegalArgumentException if the {@code reference} is empty * @throws NullPointerException if the {@code reference} is null * @see #checkNotEmpty(Object, String, Object...) */ public static T check(T reference, Predicate predicate) { check(reference, predicate, "Expected to fulfill the predicate, got %s", reference); return reference; } /** * Performs emptiness and nullness check. *

* Supports the following types: * String, CharSequence, Optional, Stream, Iterable, Collection, Map, Object[], primitive[] *

* * @param reference reference to check * @param errorMessageTemplate a template for the exception message should the * check fail. The message is formed by replacing each {@code %s} * placeholder in the template with an argument. These are matched by * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. * Unmatched arguments will be appended to the formatted message in square * braces. Unmatched placeholders will be left as-is. * @param errorMessageArgs the arguments to be substituted into the message * template. Arguments are converted to strings using * {@link String#valueOf(Object)}. * @param the reference type * @return the checked reference * @throws IllegalArgumentException if the {@code reference} is empty * or the reference type is not supported * @throws NullPointerException if the {@code reference} is null * or the check fails and either {@code errorMessageTemplate} or {@code errorMessageArgs} is null * (don't let this happen) */ public static T checkNotEmpty(T reference, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) { checkArgument(reference != null, "Expected non-null reference"); check(reference, not(isEmptyObject()), errorMessageTemplate, errorMessageArgs); return reference; } /** * Performs emptiness and nullness check. * * @param reference reference to check * @param errorMessage the exception message to use if the check fails; will * be converted to a string using {@link String#valueOf(Object)} * @param the reference type * @return the checked reference * @throws IllegalArgumentException if the {@code reference} is empty * @throws NullPointerException if the {@code reference} is null * @see #checkNotEmpty(Object, String, Object...) */ public static T checkNotEmpty(T reference, @Nullable Object errorMessage) { checkNotEmpty(reference, String.valueOf(errorMessage), EMPTY_ERROR_MESSAGE_ARGS); return reference; } /** * Performs emptiness and nullness check. * * @param reference String reference to check * @param the reference type * @return the original reference * @throws IllegalArgumentException if the {@code reference} is empty * @throws NullPointerException if the {@code reference} is null * @see #checkNotEmpty(Object, String, Object...) */ public static T checkNotEmpty(T reference) { return checkNotEmpty(reference, "Expected not empty object, got '%s'", reference); } /** * Performs check with the regular expression pattern. * * @param reference reference to check * @param pattern the regular expression pattern * @param errorMessageTemplate a template for the exception message should the * check fail. The message is formed by replacing each {@code %s} * placeholder in the template with an argument. These are matched by * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. * Unmatched arguments will be appended to the formatted message in square * braces. Unmatched placeholders will be left as-is. * @param errorMessageArgs the arguments to be substituted into the message * template. Arguments are converted to strings using {@link String#valueOf(Object)}. * @throws IllegalArgumentException if the {@code reference} doesn't match provided regular expression * @throws NullPointerException if the {@code reference} is null; also when the check fails and either * {@code errorMessageTemplate} or {@code errorMessageArgs} is null (don't let this happen) * @see java.util.regex.Pattern */ @Beta public static void checkMatches(String reference, Pattern pattern, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) { checkArgument(reference != null, "Expected non-null reference"); checkArgument(pattern != null, "Expected non-null pattern"); checkArgument(pattern.matcher(reference).matches(), errorMessageTemplate, errorMessageArgs); } /** * Performs check with the regular expression pattern. * * @param reference reference to check * @param pattern the regular expression pattern * @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 the {@code reference} doesn't match provided regular expression * @see Checks#checkMatches(String, java.util.regex.Pattern, String, Object...) */ @Beta public static void checkMatches(String reference, Pattern pattern, @Nullable Object errorMessage) { checkMatches(reference, pattern, String.valueOf(errorMessage), EMPTY_ERROR_MESSAGE_ARGS); } /** * Performs check with the regular expression pattern. * * @param reference reference to check * @param pattern the regular expression pattern * @throws IllegalArgumentException if the {@code reference} doesn't match provided regular expression * @see Checks#checkMatches(String, java.util.regex.Pattern, String, Object...) */ @Beta public static void checkMatches(String reference, Pattern pattern) { checkMatches(reference, pattern, "Expected %s to match '%s'", reference, pattern == null ? "null" : pattern.pattern()); } /** * Performs a runtime check if the reference is an instance of the provided class * * @param class_ the class to use * @param reference reference to check * @param errorMessageTemplate the exception message template to use if the check fails; will * be converted to a string using {@link String#valueOf(Object)} * @param errorMessageArgs the errorMessageTemplate arguments * @param the reference type * @return the original reference * @throws IllegalArgumentException if the {@code reference} is not an instance of provided class {@code class_} * @throws NullPointerException if the {@code reference} is null; also when the check fails and either * {@code errorMessageTemplate} or {@code errorMessageArgs} is null (don't let this happen) * @see Class#isInstance(Object) */ @Beta public static T checkIsInstance(Class class_, Object reference, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) { checkArgument(class_ != null, "Expected non-null class_"); checkArgument(reference != null, "Expected non-null reference"); checkArgument(class_.isInstance(reference), errorMessageTemplate, errorMessageArgs); //noinspection unchecked return (T) reference; } /** * Performs a runtime check if the reference is an instance of the provided class * * @param class_ the class to use * @param reference reference to check * @param errorMessage the exception message to use if the check fails; will * be converted to a string using {@link String#valueOf(Object)} * @param the reference type * @see Checks#checkIsInstance(Class, Object, String, Object...) */ @Beta public static T checkIsInstance(Class class_, Object reference, @Nullable String errorMessage) { return checkIsInstance(class_, reference, errorMessage, EMPTY_ERROR_MESSAGE_ARGS); } /** * Performs a runtime check if the reference is an instance of the provided class * * @param class_ the class to use * @param reference reference to check * @param the reference type * @see Checks#checkIsInstance(Class, Object, String, Object...) */ @Beta public static T checkIsInstance(Class class_, Object reference) { return checkIsInstance(class_, reference, "Expected reference to be instance of %s, got %s", class_ == null ? "null" : class_.getName(), reference == null ? "null" : reference.getClass().getName()); } /** * Performs URI check against RFC 2396 specification * * @param uri the URI to check * @return the checked uri * @throws IllegalArgumentException if the {@code uri} is invalid * @throws NullPointerException if the {@code uri} is null * @see java.net.URI */ public static String checkUri(String uri, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) { checkArgument(uri != null, "Expected non-null uri"); checkArgument(uri.length() > 0 && uri.length() < 2000, "Expected a email in range 1 to 2000 characters, got %s", uri.length()); return check(uri, isValidURI(), errorMessageTemplate, errorMessageArgs); } /** * Performs URI check against RFC 2396 specification * * @param uri the URI to check * @return the checked uri * @throws IllegalArgumentException if the {@code uri} is invalid * @throws NullPointerException if the {@code uri} is null * @see Checks#checkUri(String, String, Object...) */ public static String checkUri(String uri, @Nullable Object errorMessage) { return checkUri(uri, String.valueOf(errorMessage), EMPTY_ERROR_MESSAGE_ARGS); } /** * Performs URI check against RFC 2396 specification * * @param uri the URI to check * @return the checked uri * @throws IllegalArgumentException if the {@code uri} is invalid * @throws NullPointerException if the {@code uri} is null * @see Checks#checkUri(String, String, Object...) */ public static String checkUri(String uri) { return checkUri(uri, "Expected a valid URI, got %s", uri); } /** * Performs email address check against RFC 822 specification *

* TODO: RFC3696, RFC 5322 and RFC 5321 * * @param email an Email to check * @return checked Email * @throws IllegalArgumentException if the {@code email} is invalid * @see RFC3696 Errata */ public static String checkEmail(String email) { checkArgument(email != null, "Expected non-null email"); checkArgument(email.length() > 0 && email.length() < 255, "Expected a email in range 1 to 254 characters, got %s", email.length()); String[] split = email.split("@", 2); String localPart = split[0]; String domainPart = split[1]; checkArgument(localPart.length() > 0 && localPart.length() < 64, "Expected a email local part in range 1 to 63 characters, got %s", localPart.length()); checkArgument(domainPart.length() > 0 && domainPart.length() < 256, "Expected a email domain part in range 1 to 255 characters, got %s", domainPart.length()); return check(email, isValidEmail(), email); } /** * Performs a hostname check against: RFC 952, RFC 1123 and RFC 1034 * * @param hostname hostname to check * @return checked hostname * @throws IllegalArgumentException if the {@code hostname} is invalid * @throws NullPointerException if the {@code hostname} is null */ @Beta public static String checkHostname(String hostname, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) { String message = messageFromNullable(errorMessageTemplate, errorMessageArgs, "; "); checkArgument(hostname != null, "%sExpected non-null hostname", message); checkArgument(hostname.length() > 0 && hostname.length() < 256, "%sExpected a hostname in range 1 to 255 characters, got %s", message, hostname.length()); Iterable labels = on('.').split(hostname); for (String label : labels) { checkArgument(label.length() > 0 && label.length() < 64, "%sExpected a hostname label in range 1 to 63 characters, got %s", message, label.length()); } checkMatches(hostname, compile(REGEXP_HOSTNAME), "%sExpected a hostname to match expression %s, got: %s", message, REGEXP_HOSTNAME, hostname); return hostname; } /** * @see Checks#checkHostname(String, String, Object...) */ @Beta public static String checkHostname(String hostname) { return checkHostname(hostname, "", ""); } /** * @see Checks#checkHostname(String, String, Object...) */ @Beta public static String checkHostname(String hostname, @Nullable String errorMessageTemplate) { return checkHostname(hostname, errorMessageTemplate, EMPTY_ERROR_MESSAGE_ARGS); } @VisibleForTesting static String messageFromNullable(@Nullable String errorMessageTemplate, @Nullable Object[] errorMessageArgs) { return messageFromNullable(errorMessageTemplate, errorMessageArgs, ""); } @VisibleForTesting static String messageFromNullable(@Nullable String errorMessageTemplate, @Nullable Object[] errorMessageArgs, @Nullable String separator) { return format(safeTemplate(errorMessageTemplate), errorMessageArgs) + (separator == null ? "" : separator); } private static String safeTemplate(@Nullable String errorMessageTemplate) { return (errorMessageTemplate == null || errorMessageTemplate.isEmpty()) ? "%s" : errorMessageTemplate; } private Checks() { throw new UnsupportedOperationException("Private constructor"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy