com.bluecatcode.common.base.Preconditions Maven / Gradle / Ivy
package com.bluecatcode.common.base;
import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import javax.annotation.Nullable;
import java.util.regex.Pattern;
import static com.bluecatcode.common.base.Predicates.*;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
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;
/**
* Additional Preconditions as 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 Preconditions {
public static final Object[] EMPTY_ERROR_MESSAGE_ARGS = new Object[]{};
/**
* Performs check with the predicate.
*
* @param reference reference to check
* @param predicate 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)}.
* @param the reference type
* @return the original reference
* @throws IllegalArgumentException if the {@code reference} doesn't match provided predicate
* @throws NullPointerException if the {@code reference} or {@code predicate} is null
* @see java.util.regex.Pattern
*/
public static T check(T reference, Predicate predicate,
@Nullable String errorMessageTemplate,
@Nullable Object... errorMessageArgs) {
checkNotNull(predicate, errorMessageTemplate, errorMessageArgs);
checkNotNull(reference, errorMessageTemplate, errorMessageArgs);
checkArgument(predicate.apply(reference), errorMessageTemplate, errorMessageArgs);
return reference;
}
/**
* Performs check with the predicate.
*
* @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 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) {
checkNotNull(reference, "Expected not null object, got %s", reference);
check(reference, predicate, String.valueOf(errorMessage), EMPTY_ERROR_MESSAGE_ARGS);
return reference;
}
/**
* Performs check with the predicate.
*
* @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 check(T reference, Predicate predicate) {
checkNotNull(reference, "Expected not null object, got %s", reference);
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) {
checkNotNull(reference, errorMessageTemplate, errorMessageArgs);
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) {
checkNotNull(reference, "Expected not null object, got '%s'", reference);
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) {
checkNotNull(reference, "Expected not null object, got '%s'", reference);
checkNotEmpty(reference, "Expected not empty object, got '%s'", reference);
return 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) {
checkNotNull(pattern, "Expected a non-null pattern");
checkNotNull(reference, "Expected a non-null reference");
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 Preconditions#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 Preconditions#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.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) {
checkNotNull(class_, "Expected a non-null class_");
checkNotNull(reference, "Expected a 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 Preconditions#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 Preconditions#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_.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) {
checkNotEmpty(uri, "Expected non-null and non-empty uri, got %s", uri);
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 Preconditions#checkUri(String, String, Object...)
*/
public static String checkUri(String uri, @Nullable Object errorMessage) {
return check(uri, isValidURI(), 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 Preconditions#checkUri(String, String, Object...)
*/
public static String checkUri(String uri) {
return check(uri, isValidURI(), "Expected a valid URI, got %s", uri);
}
/**
* Performs email address check against RFC 822 specification
*
* TODO: RFC 5322 and RFC 5321
*
* @param email an Email to check
* @return checked Email
* @throws IllegalArgumentException if the {@code email} is invalid
*/
public static String checkEmail(String email) {
return check(email, isValidEmail(), email);
}
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 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, "; ");
checkNotEmpty(hostname, "%sExpected non-null and non-empty hostname, got %s", message, hostname);
checkArgument(hostname.length() > 0 && hostname.length() < 256,
"%sExpected a hostname in range 1 to 255 characters, got %s", message, hostname.length());
Iterable labels = on('.').omitEmptyStrings().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 Preconditions#checkHostname(String, String, Object...)
*/
@Beta
public static String checkHostname(String hostname) {
return checkHostname(hostname, "", "");
}
/**
* @see Preconditions#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 Preconditions() {
throw new UnsupportedOperationException("Private constructor");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy