class EqualityUtils {

  public static boolean isEqual(Object o1, Object o2) {
    if (o1 == null || o2 == null) {
      return o1 == o2; //NOPMD comparing objects using ==; one of these is null so PMD is being dumb
    }
    final Class<?> classA = o1.getClass();
    final Class<?> classB = o2.getClass();

    // check arrays
    if (classA.isArray() && classB.isArray()) {
      final Class<?> typeA = classA.getComponentType();
      final Class<?> typeB = classB.getComponentType();
      if (typeA.equals(typeB)) {
        final Class<?> arrayType = typeA;
        if (arrayType.isPrimitive()) {
          // Primitive arrays
          if (arrayType == int.class) {
            return Arrays.equals((int[]) o1, (int[]) o2);
          } else if (arrayType == double.class) {
            return Arrays.equals((double[]) o1, (double[]) o2);
          } else if (arrayType == byte.class) {
            return Arrays.equals((byte[]) o1, (byte[]) o2);
          } else if (arrayType == short.class) {
            return Arrays.equals((short[]) o1, (short[]) o2);
          } else if (arrayType == char.class) {
            return Arrays.equals((char[]) o1, (char[]) o2);
          } else if (arrayType == boolean.class) {
            return Arrays.equals((boolean[]) o1, (boolean[]) o2);
          } else if (arrayType == float.class) {
            return Arrays.equals((float[]) o1, (float[]) o2);
          }
          throw new UnsupportedOperationException(
              "Cannot compare primitive arrays of type " + arrayType.getSimpleName());
        } else {
          // Object or multi-dimensional arrays
          return isEqual((Object[]) o1, (Object[]) o2);
        }
      } else {
        // Different component types eg int[] and String[]
        return false;
      }
    }

    return Objects.equals(o1, o2);
  }

  private  EqualityUtils();

}