/** Compare two AutoBeans, this method has the type fan-out. */ static boolean sameOrEquals( Object value, Object otherValue, Map<PendingComparison, Comparison> pending) { if (value == otherValue) { // Fast exit return true; } if (value instanceof Collection<?> && otherValue instanceof Collection<?>) { // Check collections return sameOrEquals((Collection<?>) value, (Collection<?>) otherValue, pending, null); } if (value instanceof Map<?, ?> && otherValue instanceof Map<?, ?>) { // Check maps return sameOrEquals((Map<?, ?>) value, (Map<?, ?>) otherValue, pending); } if (value instanceof Splittable && otherValue instanceof Splittable) { return sameOrEquals((Splittable) value, (Splittable) otherValue, pending); } // Possibly substitute the AutoBean for its shim { AutoBean<?> maybeValue = AutoBeanUtils.getAutoBean(value); AutoBean<?> maybeOther = AutoBeanUtils.getAutoBean(otherValue); if (maybeValue != null && maybeOther != null) { value = maybeValue; otherValue = maybeOther; } } if (value instanceof AutoBean<?> && otherValue instanceof AutoBean<?>) { // Check ValueProxies return sameOrEquals((AutoBean<?>) value, (AutoBean<?>) otherValue, pending); } if (value == null ^ otherValue == null) { // One is null, the other isn't return false; } if (value != null && !value.equals(otherValue)) { // Regular object equality return false; } return true; }