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

org.cp.elements.lang.ObjectUtils Maven / Gradle / Ivy

/*
 * Copyright 2011-Present Author or Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.cp.elements.lang;

import static org.cp.elements.lang.CheckedExceptionsFactory.newCloneNotSupportedException;
import static org.cp.elements.lang.RuntimeExceptionsFactory.newIllegalArgumentException;
import static org.cp.elements.lang.RuntimeExceptionsFactory.newIllegalStateException;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

import org.cp.elements.io.IOUtils;
import org.cp.elements.lang.annotation.NotNull;
import org.cp.elements.lang.annotation.NullSafe;
import org.cp.elements.lang.annotation.Nullable;
import org.cp.elements.lang.reflect.ConstructorNotFoundException;
import org.cp.elements.lang.reflect.ReflectionUtils;
import org.cp.elements.util.ArrayUtils;

/**
 * Abstract utility class used to perform operations on {@link Object Objects}.
 *
 * @author John J. Blum
 * @see java.lang.reflect.Constructor
 * @see java.lang.Object
 * @see java.util.Optional
 * @see org.cp.elements.lang.reflect.ReflectionUtils
 * @since 1.0.0
 */
@SuppressWarnings("unused")
public abstract class ObjectUtils extends ReflectionUtils {

  public static final Object NULL_OBJECT_REFERENCE = null;

  public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];

  /**
   * Null-safe method whether the array is {@literal null}, {@literal empty} or all values in the array
   * are {@literal null}.
   *
   * @param values an array of values being evaluated for null.
   * @return {@literal true} if and only if the array is {@literal null}, {@literal empty}
   * or all elements in the array are {@literal null}.
   * @see #areAnyNull(Object...)
   */
  @NullSafe
  @SuppressWarnings("all")
  public static boolean areAllNull(Object... values) {

    for (Object value : ArrayUtils.nullSafeArray(values)) {
      if (value != null) {
        return false;
      }
    }

    return true;
  }

  /**
   * Null-safe method to determine if any of the values in the array are null.
   *
   * @param values an array of values being evaluated for null
   * @return true if and only if the array is not null, not empty and contains 1 null element.
   * @see #areAllNull(Object...)
   */
  @NullSafe
  public static boolean areAnyNull(Object... values) {

    for (Object value : ArrayUtils.nullSafeArray(values)) {
      if (value == null) {
        return true;
      }
    }

    return false;
  }

  /**
   * Null-safe clone operation for {@link Object Objects} that implement the {@link Cloneable} interface
   * or implement a copy constructor.
   *
   * @param  {@link Cloneable} {@link Class} type of the object.
   * @param obj {@link Object} to clone.
   * @return a "clone" of a given {@link Object} if {@link Cloneable} or the given {@link Object Object's}
   * {@link Class} type contains a copy constructor.
   * @see java.lang.Cloneable
   */
  @NullSafe
  @SuppressWarnings("unchecked")
  public static @NotNull  T clone(@Nullable T obj) {

    if (obj instanceof Cloneable) {
      return (T) invoke(obj, CLONE_METHOD_NAME, obj.getClass());
    }
    else if (obj != null) {
      try {
        Class objectType = (Class) obj.getClass();

        Constructor copyConstructor = resolveConstructor(objectType, new Class[] { objectType }, obj);

        return copyConstructor.newInstance(obj);
      }
      // A copy constructor was not found in the Object's class type.
      catch (ConstructorNotFoundException ignore) {
        if (obj instanceof Serializable) {
          try {
            return IOUtils.deserialize(IOUtils.serialize(obj));
          }
          catch (ClassNotFoundException | IOException cause) {
            throw new CloneException("[clone] using [serialization] was unsuccessful", cause);
          }
        }
      }
      catch (Exception cause) {
        throw new CloneException("[clone] using [copy constructor] was unsuccessful", cause);
      }
    }

    throw new UnsupportedOperationException(newCloneNotSupportedException(
      "[clone] is not supported for object of type [%s]", getClassSimpleName(obj)));
  }

  /**
   * Safely executes the given {@link ThrowableOperation} and handles any {@link Throwable} thrown during the execution
   * of the operation by rethrowing an {@link IllegalStateException}.
   *
   * @param  {@link Class type} of the {@link Object return value}.
   * @param operation {@link ThrowableOperation} to execute.
   * @return the {@link Object result} of the {@link ThrowableOperation}.
   * @see #doOperationSafely(ThrowableOperation, Object)
   * @see org.cp.elements.lang.ThrowableOperation
   */
  public static @Nullable  T doOperationSafely(@NotNull ThrowableOperation operation) {
    return doOperationSafely(operation, (T) null);
  }

  /**
   * Safely executes the given {@link ThrowableOperation} and handles any {@link Throwable} thrown during the execution
   * of the operation by returning the given {@link Object default value} or rethrowing an {@link IllegalStateException}
   * if the {@link Object default value} is {@literal null}.
   *
   * @param  {@link Class type} of the {@link Object return value}.
   * @param operation {@link ThrowableOperation} to execute.
   * @param defaultValue {@link Object} to return if the {@link ThrowableOperation} throws a {@link Throwable}.
   * @return the {@link Object result} of the {@link ThrowableOperation} or the {@link Object default value}
   * if the {@link ThrowableOperation} throws a {@link Throwable}.
   * @see #doOperationSafely(ThrowableOperation, Supplier)
   * @see org.cp.elements.lang.ThrowableOperation
   */
  public static @Nullable  T doOperationSafely(@NotNull ThrowableOperation operation, @NotNull T defaultValue) {

    Supplier valueSupplier = () -> defaultValue;

    return doOperationSafely(operation, valueSupplier);
  }

  /**
   * Safely executes the given {@link ThrowableOperation} and handles any {@link Throwable} thrown during the execution
   * of the operation by returning a {@link Object value} from the given {@link Supplier} or rethrows an
   * {@link IllegalStateException} if the {@link Supplier supplied value} is {@literal null}.
   *
   * @param  {@link Class type} of the {@link Object return value}.
   * @param operation {@link ThrowableOperation} to execute.
   * @param valueSupplier {@link Supplier} used to supply a {@link Object value}
   * if the {@link ThrowableOperation} throws a {@link Throwable}.
   * @return the {@link Object result} of the {@link ThrowableOperation} or a {@link Object value} supplied by
   * the {@link Supplier} if the {@link ThrowableOperation} throws a {@link Throwable}.
   * @throws IllegalStateException if the {@link ThrowableOperation} throws a {@link Throwable} and the {@link Supplier}
   * supplies a {@literal null} {@link Object value}.
   * @see #returnValueOrThrowIfNull(Object, RuntimeException)
   * @see #doOperationSafely(ThrowableOperation, Function)
   * @see org.cp.elements.lang.ThrowableOperation
   * @see java.util.function.Supplier
   */
  public static @Nullable  T doOperationSafely(@NotNull ThrowableOperation operation,
      @NotNull Supplier valueSupplier) {

    Function throwableHandler = cause -> returnValueOrThrowIfNull(valueSupplier.get(),
      newIllegalStateException(cause, "Failed to execute operation [%s]", operation));

    return doOperationSafely(operation, throwableHandler);
  }

  /**
   * Safely executes the given {@link ThrowableOperation} returning the {@link Object result} and handling any
   * {@link Throwable} thrown by the operation during execution by invoking the given {@link Function}.
   *
   * @param  {@link Class type} of the {@link Object return value}.
   * @param operation {@link ThrowableOperation} to execute; must not be {@literal null}.
   * @param throwableHandler {@link Function} used to handle the {@link Throwable} thrown by
   * the {@link ThrowableOperation} during execution; must not be {@literal null}.
   * @return the {@link Object result} of the {@link ThrowableOperation}.
   * @see org.cp.elements.lang.ThrowableOperation
   * @see java.util.function.Function
   */
  public static @Nullable  T doOperationSafely(@NotNull ThrowableOperation operation,
      @NotNull Function throwableHandler) {

    try {
      return operation.run(EMPTY_OBJECT_ARRAY);
    }
    catch (Throwable cause) {
      return throwableHandler.apply(cause);
    }
  }

  /**
   * Requires the given {@link Object} reference.
   *
   * @param  {@link Class} type of the {@link Object}.
   * @param object {@link Object} reference to evaluate.
   * @param message {@link String} containing the message for the {@link IllegalArgumentException} thrown by
   * this method if the {@link Object} reference is {@literal null}.
   * @param args array of {@link Object arguments} used to resolve the placeholders in the {@link String message}.
   * @return the given {@link Object}.
   * @throws IllegalArgumentException if the {@link Object} is {@literal null}.
   * @see #requireState(Object, String, Object...)
   */
  public static @NotNull  T requireObject(T object, String message, Object... args) {
    Object[] resolvedArguments = ArrayUtils.isNotEmpty(args) ? args : ArrayUtils.asArray(object);
    Assert.notNull(object, message, resolvedArguments);
    return object;
  }

  /**
   * Requires the {@link Object} reference to have been initialized, that is, to not be {@literal null}.
   *
   * @param  {@link Class type} of {@link Object}.
   * @param object {@link Object} reference to evaluate.
   * @param message {@link String} containing the message for the {@link IllegalStateException} thrown by
   * this method if the {@link Object} reference is {@literal null}.
   * @param args array of {@link Object arguments} used to resolve the placeholders in the {@link String message}.
   * @return the given {@link Object}.
   * @throws IllegalStateException if the {@link Object} is {@literal null}.
   * @see #requireObject(Object, String, Object...)
   */
  public static @NotNull  T requireState(T object, String message, Object... args) {
    Object[] resolvedArguments = ArrayUtils.isNotEmpty(args) ? args : ArrayUtils.asArray(object);
    Assert.state(object != null, message, resolvedArguments);
    return object;
  }

  /**
   * Gets the first {@literal non-null} {@link Object value} in the array of values.
   *
   * @param  {@link Class type} of the {@link Object values} in the array.
   * @param values array of {@link Object values} from which the first {@literal non-null} {@link Object value}
   * will be returned; should not be {@literal null}.
   * @return the first {@literal non-null} {@link Object value} in the array of values.
   */
  @NullSafe
  @SuppressWarnings({ "unchecked", "varargs" })
  public static @Nullable  T returnFirstNonNullValue(T... values) {

    for (T value : ArrayUtils.nullSafeArray(values)) {
      if (value != null) {
        return value;
      }
    }

    return null;
  }

  /**
   * Returns the given {@code value} if not {@literal null} or returns the {@code defaultValue}.
   *
   * @param  {@link Class} type of the {@code value} and {@code defaultValue}.
   * @param value {@link Object} to evaluate for {@literal null}.
   * @param defaultValue {@link Object} value to return if {@code value} is {@literal null}.
   * @return the given {@code value} if not {@literal null} or returns the {@code defaultValue}.
   * @see #returnValueOrDefaultIfNull(Object, Supplier)
   */
  public static @Nullable  T returnValueOrDefaultIfNull(@Nullable T value, @Nullable T defaultValue) {
    return returnValueOrDefaultIfNull(value, () -> defaultValue);
  }

  /**
   * Returns the given {@code value} if not {@literal null} or call the given {@link Supplier} to supply a value.
   *
   * @param  {@link Class} type of the {@code value}.
   * @param value {@link Object} to evaluate for {@literal null}.
   * @param valueSupplier {@link Supplier} used to supply a value if {@code value} is {@literal null}.
   * @return the given {@code value} if not {@literal null} or call the given {@link Supplier} to supply a value.
   * @see java.util.function.Supplier
   */
  public static @Nullable  T returnValueOrDefaultIfNull(@Nullable T value, @NotNull Supplier valueSupplier) {
    return Optional.ofNullable(value).orElseGet(valueSupplier);
  }

  /**
   * Returns the given {@code value} if not {@literal null} or throws an {@link IllegalArgumentException}.
   *
   * @param  {@link Class} type of the {@code value}.
   * @param value {@link Object} value to evaluate.
   * @return the given {@code value} if not {@literal null} or throws an {@link IllegalArgumentException}.
   * @throws IllegalArgumentException if {@code value} is {@literal null}.
   * @see #returnValueOrThrowIfNull(Object, RuntimeException)
   */
  @NullSafe
  public static @NotNull  T returnValueOrThrowIfNull(@Nullable T value) {
    return returnValueOrThrowIfNull(value, newIllegalArgumentException("Value must not be null"));
  }

  /**
   * Returns the given {@code value} if not {@literal null} or throws the given {@link RuntimeException}.
   *
   * @param  {@link Class} type of the {@code value}.
   * @param value {@link Object} value to evaluate.
   * @param exception {@link RuntimeException} to throw if {@code value} is {@literal null}.
   * @return the given {@code value} if not {@literal null} or throws the given {@link RuntimeException}.
   * @throws IllegalArgumentException if {@code exception} is {@literal null}.
   * @throws RuntimeException if {@code value} is {@literal null}.
   */
  public static @NotNull  T returnValueOrThrowIfNull(@Nullable T value, @NotNull RuntimeException exception) {

    Assert.notNull(exception, "RuntimeException must not be null");

    return Optional.ofNullable(value).orElseThrow(() -> exception);
  }

  /**
   * Safely returns the value supplied by the given {@link Supplier}.  If an {@link Exception} or {@link Error} occurs,
   * then {@literal null} is returned.
   *
   * @param  {@link Class} type of the value to get.
   * @param valueSupplier {@link Supplier} of the value.
   * @return a value from the given {@link Supplier} in an error safe manner.
   * @see java.util.function.Supplier
   * @see #safeGetValue(Supplier, Object)
   */
  public static @Nullable  T safeGetValue(@NotNull Supplier valueSupplier) {
    return safeGetValue(valueSupplier, null);
  }

  /**
   * Safely returns the value supplied by the given {@link Supplier}.  If an {@link Exception} or {@link Error} occurs
   * then the {@code defaultValue} will be returned.
   *
   * @param  {@link Class} type of the value to get.
   * @param valueSupplier {@link Supplier} of the value.
   * @param defaultValue value to return if the {@link Supplier} is unable to supply the value.
   * @return a value from the given {@link Supplier} in an error safe manner.  If an {@link Exception} or {@link Error}
   * occurs then the {@code defaultValue} will be returned.
   * @see java.util.function.Supplier
   */
  public static @Nullable  T safeGetValue(@NotNull Supplier valueSupplier, @Nullable T defaultValue) {

    try {
      return valueSupplier.get();
    }
    catch (Throwable ignore) {
      return defaultValue;
    }
  }

  /**
   * Determines whether two objects are equal in value as determined by the Object.equals method in addition to
   * guarding against null values.  Both objects are considered equal if and only if both are non-null
   * and obj1.equals(obj2).
   *
   * @param obj1 the first Object in the equality comparison.
   * @param obj2 the second Object in the equality comparison.
   * @return a boolean value indicating whether the two Objects are equal in value.
   * @see java.lang.Object#equals(Object)
   */
  @NullSafe
  public static boolean equals(@Nullable Object obj1, @Nullable Object obj2) {
    return obj1 != null && obj1.equals(obj2);
  }

  /**
   * Determines whether two objects are equal in value as determined by the Object.equals method.  Both objects are
   * considered equal if and only if both are null or obj1.equals(obj2).
   *
   * @param obj1 the first Object in the equality comparison.
   * @param obj2 the second Object in the equality comparison.
   * @return a boolean value indicating whether the two Objects are equal in value where two null Object references
   * are considered equal as well.
   * @see java.lang.Object#equals(Object)
   */
  @NullSafe
  public static boolean equalsIgnoreNull(@Nullable Object obj1, @Nullable Object obj2) {
    return obj1 == null ? obj2 == null : obj1.equals(obj2);
  }

  /**
   * Determines whether {@code obj1} is {@literal null} or equal to {@code obj2}.
   *
   * @param obj1 {@link Object} being evaluated in the equality comparison.
   * @param obj2 {@link Object} to compare for equality with {@code obj1} if {@code obj1} is not {@literal null}.
   * @return a boolean value indicating whether {@code obj1} is {@literal null} or equal to {@code obj2}.
   * @see java.lang.Object#equals(Object)
   */
  @NullSafe
  public static boolean isNullOrEqualTo(@Nullable Object obj1, @Nullable Object obj2) {
    return obj1 == null || obj1.equals(obj2);
  }

  /**
   * Calculates the hash code of an object by invoking Object.hashCode for non-null objects and returning 0 if the
   * object is null.
   *
   * @param obj the Object who's hash code is computed and returned.
   * @return an integer value with the calculated hash code of the object.
   * @see java.lang.Object#hashCode()
   */
  @NullSafe
  public static int hashCode(@Nullable Object obj) {
    return obj != null ? obj.hashCode() : 0;
  }

  /**
   * Computes the {@link Integer hash code} for all the given {@link Object elements} of the array
   * using the standard hash code algorithm.
   *
   * The {@link Object elements} in the array can represent the individual properties of an {@link Object}
   * that makes up the hash code.
   *
   * @param array array of {@link Object elements} to use when computing the hash code.
   * @return the computed hash code.
   */
  @NullSafe
  public static int hashCodeOf(Object... array) {

    int hashCode = 17;

    for (Object obj : ArrayUtils.nullSafeArray(array)) {
      hashCode = 37 * hashCode + hashCode(obj);
    }

    return hashCode;
  }

  /**
   * Transforms the object into a String by invoking Object.toString for non-null objects and returning null for
   * null object references.
   *
   * @param obj the Object who's toString method will be called.
   * @return a String representation of the object.
   * @see java.lang.Object#toString()
   */
  @NullSafe
  public static @Nullable String toString(@Nullable Object obj) {
    return obj != null ? obj.toString() : null;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy