Пример #1
0
  /** 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;
  }
Пример #2
0
  /**
   * If a comparison between two AutoBeans is currently pending, this method will skip their
   * comparison.
   */
  private static boolean sameOrEquals(
      AutoBean<?> value, AutoBean<?> otherValue, Map<PendingComparison, Comparison> pending) {
    if (value == otherValue) {
      // Simple case
      return true;
    } else if (!value.getType().equals(otherValue.getType())) {
      // Beans of different types
      return false;
    }

    /*
     * The PendingComparison key allows us to break reference cycles when
     * crawling the graph. Since the entire operation is essentially a
     * concatenated && operation, it's ok to speculatively return true for
     * repeated a.equals(b) tests.
     */
    PendingComparison key = new PendingComparison(value, otherValue);
    Comparison previous = pending.get(key);
    if (previous == null) {
      // Prevent the same comparison from being made
      pending.put(key, Comparison.PENDING);

      // Compare each property
      Map<String, Object> beanProperties = AutoBeanUtils.getAllProperties(value);
      Map<String, Object> otherProperties = AutoBeanUtils.getAllProperties(otherValue);
      for (Map.Entry<String, Object> entry : beanProperties.entrySet()) {
        Object property = entry.getValue();
        Object otherProperty = otherProperties.get(entry.getKey());
        if (!sameOrEquals(property, otherProperty, pending)) {
          pending.put(key, Comparison.FALSE);
          return false;
        }
      }
      pending.put(key, Comparison.TRUE);
      return true;
    } else {
      // Return true for TRUE or PENDING
      return !Comparison.FALSE.equals(previous);
    }
  }