gt: 		if (lhs == rhs)
context: package org.areasy.common.data.workers.builders;
  
  /*
   * Copyright (c) 2007-2020 AREasy Runtime
   *
   * This library, AREasy Runtime and API for BMC Remedy AR System, is free software ("Licensed Software");
   * you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either version 2.1 of the License,
   * or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
   * including but not limited to, the implied warranty of MERCHANTABILITY, NONINFRINGEMENT,
   * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
   */
  
  import java.lang.reflect.AccessibleObject;
  import java.lang.reflect.Field;
  import java.lang.reflect.Modifier;
  
  /**
   * <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
   * <p/>
   * <p> This class provides methods to build a good equals method for any
   * class. It follows rules laid out in
   * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
   * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
   * <code>floats</code>, and arrays can be tricky. Also, making sure that
   * <code>equals()</code> and <code>hashCode()</code> are consistent can be
   * difficult.</p>
   * <p/>
   * <p>Two Objects that compare as equals must generate the same hash code,
   * but two Objects with the same hash code do not have to be equal.</p>
   * <p/>
   * <p>All relevant fields should be included in the calculation of equals.
   * Derived fields may be ignored. In particular, any field used in
   * generating a hash code must be used in the equals method, and vice
   * versa.</p>
   * <p/>
   * <p>Typical use for the code is as follows:</p>
   * <pre>
   * public boolean equals(Object obj) {
   *   if (obj instanceof MyClass == false) {
   *     return false;
   *   }
   *   if (this == obj) {
   *     return true;
   *   }
   *   MyClass rhs = (MyClass) obj;
   *   return new EqualsBuilder()
   *                 .appendSuper(super.equals(obj))
   *                 .append(field1, rhs.field1)
   *                 .append(field2, rhs.field2)
   *                 .append(field3, rhs.field3)
   *                 .isEquals();
   *  }
   * </pre>
   * <p/>
   * <p> Alternatively, there is a method that uses reflection to determine
   * the fields to test. Because these fields are usually private, the method,
   * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
   * change the visibility of the fields. This will fail under a security
   * manager, unless the appropriate permissions are set up correctly. It is
   * also slower than testing explicitly.</p>
   * <p/>
   * <p> A typical invocation for this method would look like:</p>
   * <pre>
   * public boolean equals(Object obj) {
   *   return EqualsBuilder.reflectionEquals(this, obj);
   * }
   * </pre>
   *
   * @version $Id: EqualsBuilder.java,v 1.2 2008/05/14 09:32:34 swd\stefan.damian Exp $
   */
  public class EqualsBuilder
  {
  
  	/**
  	 * If the fields tested are equals.
  	 * The default value is <code>true</code>.
  	 */
  	private boolean isEquals = true;
  
  	/**
  	 * <p>Constructor for EqualsBuilder.</p>
  	 * <p/>
  	 * <p>Starts off assuming that equals is <code>true</code>.</p>
  	 *
  	 * @see Object#equals(Object)
  	 */
  	public EqualsBuilder()
  	{
  		// do nothing for now.
  	}
  
  
  	/**
  	 * <p>This method uses reflection to determine if the two <code>Object</code>s
  	 * are equal.</p>
  	 * <p/>
  	 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
  	 * fields. This means that it will throw a security exception if run under
  	 * a security manager, if the permissions are not set up correctly. It is also
  	 * not as efficient as testing explicitly.</p>
  	 * <p/>
  	 * <p>Transient members will be not be tested, as they are likely derived
  	 * fields, and not part of the value of the Object.</p>
  	 * <p/>
  	 * <p>Static fields will not be tested. Superclass fields will be included.</p>
  	 *
  	 * @param lhs <code>this</code> object
  	 * @param rhs the other object
  	 * @return <code>true</code> if the two Objects have tested equals.
  	 */
  	public static boolean reflectionEquals(Object lhs, Object rhs)
  	{
  		return reflectionEquals(lhs, rhs, false, null);
  	}
  
  	/**
  	 * <p>This method uses reflection to determine if the two <code>Object</code>s
  	 * are equal.</p>
  	 * <p/>
  	 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
  	 * fields. This means that it will throw a security exception if run under
  	 * a security manager, if the permissions are not set up correctly. It is also
  	 * not as efficient as testing explicitly.</p>
  	 * <p/>
  	 * <p>If the TestTransients parameter is set to <code>true</code>, transient
  	 * members will be tested, otherwise they are ignored, as they are likely
  	 * derived fields, and not part of the value of the <code>Object</code>.</p>
  	 * <p/>
  	 * <p>Static fields will not be tested. Superclass fields will be included.</p>
  	 *
  	 * @param lhs            <code>this</code> object
  	 * @param rhs            the other object
  	 * @param testTransients whether to include transient fields
  	 * @return <code>true</code> if the two Objects have tested equals.
  	 */
  	public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients)
  	{
  		return reflectionEquals(lhs, rhs, testTransients, null);
  	}
  
  	/**
  	 * <p>This method uses reflection to determine if the two <code>Object</code>s
  	 * are equal.</p>
  	 * <p/>
  	 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
  	 * fields. This means that it will throw a security exception if run under
  	 * a security manager, if the permissions are not set up correctly. It is also
  	 * not as efficient as testing explicitly.</p>
  	 * <p/>
  	 * <p>If the testTransients parameter is set to <code>true</code>, transient
  	 * members will be tested, otherwise they are ignored, as they are likely
  	 * derived fields, and not part of the value of the <code>Object</code>.</p>
  	 * <p/>
  	 * <p>Static fields will not be included. Superclass fields will be appended
  	 * up to and including the specified superclass. A null superclass is treated
  	 * as java.lang.Object.</p>
  	 *
  	 * @param lhs              <code>this</code> object
  	 * @param rhs              the other object
  	 * @param testTransients   whether to include transient fields
  	 * @param reflectUpToClass the superclass to reflect up to (inclusive),
  	 *                         may be <code>null</code>
  	 * @return <code>true</code> if the two Objects have tested equals.
  	 */
  	public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass)
  	{
  		if (lhs == rhs)
  		{
  			return true;
  		}
  		if (lhs == null || rhs == null)
  		{
  			return false;
  		}
  		// Find the leaf class since there may be transients in the leaf
  		// class or in classes between the leaf and root.
  		// If we are not testing transients or a subclass has no ivars,
  		// then a subclass can test equals to a superclass.
  		Class lhsClass = lhs.getClass();
  		Class rhsClass = rhs.getClass();
  		Class testClass;
  		if (lhsClass.isInstance(rhs))
  		{
  			testClass = lhsClass;
  			if (!rhsClass.isInstance(lhs))
  			{
  				// rhsClass is a subclass of lhsClass
  				testClass = rhsClass;
  			}
  		}
  		else if (rhsClass.isInstance(lhs))
  		{
  			testClass = rhsClass;
  			if (!lhsClass.isInstance(rhs))
  			{
  				// lhsClass is a subclass of rhsClass
  				testClass = lhsClass;
  			}
  		}
  		else
  		{
  			// The two classes are not related.
  			return false;
  		}
  		EqualsBuilder equalsBuilder = new EqualsBuilder();
  		try
  		{
  			reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
  			while (testClass.getSuperclass() != null && testClass != reflectUpToClass)
  			{
  				testClass = testClass.getSuperclass();
  				reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
  			}
  		}
  		catch (IllegalArgumentException e)
  		{
  			// In this case, we tried to test a subclass vs. a superclass and
  			// the subclass has ivars or the ivars are transient and
  			// we are testing transients.
  			// If a subclass has ivars that we are trying to test them, we get an
  			// exception and we know that the objects are not equal.
  			return false;
  		}
  		return equalsBuilder.isEquals();
  	}
  
  	/**
  	 * <p>Appends the fields and values defined by the given object of the
  	 * given Class.</p>
  	 *
  	 * @param lhs           the left hand object
  	 * @param rhs           the right hand object
  	 * @param clazz         the class to append details of
  	 * @param builder       the builder to append to
  	 * @param useTransients whether to test transient fields
  	 */
  	private static void reflectionAppend(Object lhs,
  										 Object rhs,
  										 Class clazz,
  										 EqualsBuilder builder,
  										 boolean useTransients)
  	{
  		Field[] fields = clazz.getDeclaredFields();
  		AccessibleObject.setAccessible(fields, true);
  		for (int i = 0; i < fields.length && builder.isEquals; i++)
  		{
  			Field f = fields[i];
  			if ((f.getName().indexOf('$') == -1)
  					&& (useTransients || !Modifier.isTransient(f.getModifiers()))
  					&& (!Modifier.isStatic(f.getModifiers())))
  			{
  				try
  				{
  					builder.append(f.get(lhs), f.get(rhs));
  				}
  				catch (IllegalAccessException e)
  				{
  					//this can't happen. Would get a Security exception instead
  					//throw a runtime exception in case the impossible happens.
  					throw new InternalError("Unexpected IllegalAccessException");
  				}
  			}
  		}
  	}
  
  
  	/**
  	 * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
  	 *
  	 * @param superEquals the result of calling <code>super.equals()</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder appendSuper(boolean superEquals)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		isEquals = superEquals;
  		return this;
  	}
  
  
  	/**
  	 * <p>Test if two <code>Object</code>s are equal using their
  	 * <code>equals</code> method.</p>
  	 *
  	 * @param lhs the left hand object
  	 * @param rhs the right hand object
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(Object lhs, Object rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		if (lhs == rhs)
  		{
  			return this;
  		}
  		if (lhs == null || rhs == null)
  		{
  			this.setEquals(false);
  			return this;
  		}
  		Class lhsClass = lhs.getClass();
  		if (!lhsClass.isArray())
  		{
  			// The simple case, not an array, just test the element
  			isEquals = lhs.equals(rhs);
  		}
  		else if (lhs.getClass() != rhs.getClass())
  		{
  			// Here when we compare different dimensions, for example: a boolean[][] to a boolean[]
  			this.setEquals(false);
  		}
  		// 'Switch' on type of array, to dispatch to the correct handler
  		// This handles multi dimensional arrays of the same depth
  		else if (lhs instanceof long[])
  		{
  			append((long[]) lhs, (long[]) rhs);
  		}
  		else if (lhs instanceof int[])
  		{
  			append((int[]) lhs, (int[]) rhs);
  		}
  		else if (lhs instanceof short[])
  		{
  			append((short[]) lhs, (short[]) rhs);
  		}
  		else if (lhs instanceof char[])
  		{
  			append((char[]) lhs, (char[]) rhs);
  		}
  		else if (lhs instanceof byte[])
  		{
  			append((byte[]) lhs, (byte[]) rhs);
  		}
  		else if (lhs instanceof double[])
  		{
  			append((double[]) lhs, (double[]) rhs);
  		}
  		else if (lhs instanceof float[])
  		{
  			append((float[]) lhs, (float[]) rhs);
  		}
  		else if (lhs instanceof boolean[])
  		{
  			append((boolean[]) lhs, (boolean[]) rhs);
  		}
  		else
  		{
  			// Not an array of primitives
  			append((Object[]) lhs, (Object[]) rhs);
  		}
  		return this;
  	}
  
  	/**
  	 * <p/>
  	 * Test if two <code>long</code> s are equal.
  	 * </p>
  	 *
  	 * @param lhs the left hand <code>long</code>
  	 * @param rhs the right hand <code>long</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(long lhs, long rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		isEquals = (lhs == rhs);
  		return this;
  	}
  
  	/**
  	 * <p>Test if two <code>int</code>s are equal.</p>
  	 *
  	 * @param lhs the left hand <code>int</code>
  	 * @param rhs the right hand <code>int</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(int lhs, int rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		isEquals = (lhs == rhs);
  		return this;
  	}
  
  	/**
  	 * <p>Test if two <code>short</code>s are equal.</p>
  	 *
  	 * @param lhs the left hand <code>short</code>
  	 * @param rhs the right hand <code>short</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(short lhs, short rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		isEquals = (lhs == rhs);
  		return this;
  	}
  
  	/**
  	 * <p>Test if two <code>char</code>s are equal.</p>
  	 *
  	 * @param lhs the left hand <code>char</code>
  	 * @param rhs the right hand <code>char</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(char lhs, char rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		isEquals = (lhs == rhs);
  		return this;
  	}
  
  	/**
  	 * <p>Test if two <code>byte</code>s are equal.</p>
  	 *
  	 * @param lhs the left hand <code>byte</code>
  	 * @param rhs the right hand <code>byte</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(byte lhs, byte rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		isEquals = (lhs == rhs);
  		return this;
  	}
  
  	/**
  	 * <p>Test if two <code>double</code>s are equal by testing that the
  	 * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
  	 * <p/>
  	 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
  	 * <p/>
  	 * <p>It is compatible with the hash code generated by
  	 * <code>HashCodeBuilder</code>.</p>
  	 *
  	 * @param lhs the left hand <code>double</code>
  	 * @param rhs the right hand <code>double</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(double lhs, double rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
  	}
  
  	/**
  	 * <p>Test if two <code>float</code>s are equal byt testing that the
  	 * pattern of bits returned by doubleToLong are equal.</p>
  	 * <p/>
  	 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
  	 * <p/>
  	 * <p>It is compatible with the hash code generated by
  	 * <code>HashCodeBuilder</code>.</p>
  	 *
  	 * @param lhs the left hand <code>float</code>
  	 * @param rhs the right hand <code>float</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(float lhs, float rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
  	}
  
  	/**
  	 * <p>Test if two <code>booleans</code>s are equal.</p>
  	 *
  	 * @param lhs the left hand <code>boolean</code>
  	 * @param rhs the right hand <code>boolean</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(boolean lhs, boolean rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		isEquals = (lhs == rhs);
  		return this;
  	}
  
  	/**
  	 * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
  	 * <p/>
  	 * <p>This also will be called for the top level of
  	 * multi-dimensional, ragged, and multi-typed arrays.</p>
  	 *
  	 * @param lhs the left hand <code>Object[]</code>
  	 * @param rhs the right hand <code>Object[]</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(Object[] lhs, Object[] rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		if (lhs == rhs)
  		{
  			return this;
  		}
  		if (lhs == null || rhs == null)
  		{
  			this.setEquals(false);
  			return this;
  		}
  		if (lhs.length != rhs.length)
  		{
  			this.setEquals(false);
  			return this;
  		}
  		for (int i = 0; i < lhs.length && isEquals; ++i)
  		{
  			append(lhs[i], rhs[i]);
  		}
  		return this;
  	}
  
  	/**
  	 * <p>Deep comparison of array of <code>long</code>. Length and all
  	 * values are compared.</p>
  	 * <p/>
  	 * <p>The method {@link #append(long, long)} is used.</p>
  	 *
  	 * @param lhs the left hand <code>long[]</code>
  	 * @param rhs the right hand <code>long[]</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(long[] lhs, long[] rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  		if (lhs == rhs)
  		{
  			return this;
  		}
  		if (lhs == null || rhs == null)
  		{
  			this.setEquals(false);
  			return this;
  		}
  		if (lhs.length != rhs.length)
  		{
  			this.setEquals(false);
  			return this;
  		}
  		for (int i = 0; i < lhs.length && isEquals; ++i)
  		{
  			append(lhs[i], rhs[i]);
  		}
  		return this;
  	}
  
  	/**
  	 * <p>Deep comparison of array of <code>int</code>. Length and all
  	 * values are compared.</p>
  	 * <p/>
  	 * <p>The method {@link #append(int, int)} is used.</p>
  	 *
  	 * @param lhs the left hand <code>int[]</code>
  	 * @param rhs the right hand <code>int[]</code>
  	 * @return EqualsBuilder - used to chain calls.
  	 */
  	public EqualsBuilder append(int[] lhs, int[] rhs)
  	{
  		if (isEquals == false)
  		{
  			return this;
  		}
  