Example usage for java.util LinkedList addFirst

List of usage examples for java.util LinkedList addFirst

Introduction

In this page you can find the example usage for java.util LinkedList addFirst.

Prototype

public void addFirst(E e) 

Source Link

Document

Inserts the specified element at the beginning of this list.

Usage

From source file:org.eclipse.flux.jdt.services.Utils.java

public static JSONArray editsToJsonArray(TextEdit edit) {
    final LinkedList<JSONObject> list = new LinkedList<JSONObject>();

    edit.accept(new TextEditVisitor() {

        @Override//  w ww  .j a  v  a 2  s  . co  m
        public boolean visit(DeleteEdit delete) {
            try {
                JSONObject json = new JSONObject();
                json.put("offset", delete.getOffset());
                json.put("length", delete.getLength());
                json.put("text", "");
                list.addFirst(json);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return super.visit(delete);
        }

        @Override
        public boolean visit(InsertEdit insert) {
            try {
                JSONObject json = new JSONObject();
                json.put("offset", insert.getOffset());
                json.put("length", 0);
                json.put("text", insert.getText());
                list.addFirst(json);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return super.visit(insert);
        }

        @Override
        public boolean visit(ReplaceEdit replace) {
            try {
                JSONObject json = new JSONObject();
                json.put("offset", replace.getOffset());
                json.put("length", replace.getLength());
                json.put("text", replace.getText());
                list.addFirst(json);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return super.visit(replace);
        }

    });

    return new JSONArray(list);
}

From source file:com.haulmont.cuba.gui.ComponentsHelper.java

public static String getFullFrameId(Frame frame) {
    LinkedList<String> frameIds = new LinkedList<>();
    frameIds.addFirst(frame.getId());
    while (frame != null && !(frame instanceof Window) && frame != frame.getFrame()) {
        frame = frame.getFrame();//w w  w . j  a  v  a  2  s  . co m
        if (frame != null)
            frameIds.addFirst(frame.getId());
    }
    return StringUtils.join(frameIds, '.');
}

From source file:marytts.modules.ModuleRegistry.java

/**
 * This method recursively calls itself.
 * It forward-constructs a list of seen types (upon test),
 * and backward-constructs a list of required modules (upon success).
 *
 * @param sourceType/* w  w w  . ja v a  2  s  .  com*/
 * @param targetType
 * @param locale
 * @param voice
 * @param seenTypes
 * @return
 */
private static LinkedList<MaryModule> modulesRequiredForProcessing(MaryDataType sourceType,
        MaryDataType targetType, Locale locale, Voice voice, LinkedList<MaryDataType> seenTypes) {
    // Terminating condition:
    if (sourceType.equals(targetType)) {
        logger.debug("found path through modules");
        return new LinkedList<MaryModule>();
    }
    // Recursion step:
    // Any voice-specific modules?
    List<MaryModule> candidates = null;
    // TODO: the following should be obsolete as soon as we are properly using the voice index in ModuleRegistry
    if (voice != null)
        candidates = voice.getPreferredModulesAcceptingType(sourceType);
    if (candidates == null || candidates.isEmpty()) { // default: use all available modules
        candidates = get(sourceType, locale, voice);
    }
    if (candidates == null || candidates.isEmpty()) {
        // no module can handle this type
        return null;
    }
    for (Iterator<MaryModule> it = candidates.iterator(); it.hasNext();) {
        MaryModule candidate = it.next();
        MaryDataType outputType = candidate.outputType();
        // Ignore candidates that would bring us to a data type that we
        // have already seen (i.e., that would lead to a loop):
        if (!seenTypes.contains(outputType)) {
            seenTypes.add(outputType);
            logger.debug("Module " + candidate.name() + " converts " + sourceType.name() + " into " + outputType
                    + " (locale " + locale + ", voice " + voice + ")");
            // recursive call:
            LinkedList<MaryModule> path = modulesRequiredForProcessing(outputType, targetType, locale, voice,
                    seenTypes);
            if (path != null) {
                // success, found a path of which candidate is the first
                // step
                path.addFirst(candidate);
                return path;
            } // else, try next candidate
            seenTypes.removeLast();
        }
    }
    // We get here only if none of the candidates lead to a valid path
    return null; // failure
}

From source file:org.mule.config.ExceptionHelper.java

public static <T> T traverseCauseHierarchy(Throwable e, ExceptionEvaluator<T> evaluator) {
    LinkedList<Throwable> exceptions = new LinkedList<Throwable>();
    exceptions.add(e);//from   w  w w .  ja  va2s  . c o m
    while (e.getCause() != null && !e.getCause().equals(e)) {
        exceptions.addFirst(e.getCause());
        e = e.getCause();
    }
    for (Throwable exception : exceptions) {
        T value = evaluator.evaluate(exception);
        if (value != null) {
            return value;
        }
    }
    return null;
}

From source file:org.dcm4che3.conf.core.misc.DeepEquals.java

/**
 * Get a deterministic hashCode (int) value for an Object, regardless of
 * when it was created or where it was loaded into memory.  The problem
 * with java.lang.Object.hashCode() is that it essentially relies on
 * memory location of an object (what identity it was assigned), whereas
 * this method will produce the same hashCode for any object graph, regardless
 * of how many times it is created.<br/><br/>
 *
 * This method will handle cycles correctly (A->B->C->A).  In this case,
 * Starting with object A, B, or C would yield the same hashCode.  If an
 * object encountered (root, suboject, etc.) has a hashCode() method on it
 * (that is not Object.hashCode()), that hashCode() method will be called
 * and it will stop traversal on that branch.
 * @param obj Object who hashCode is desired.
 * @return the 'deep' hashCode value for the passed in object.
 *///from  ww  w .jav a  2  s  .com
public static int deepHashCode(Object obj) {
    Set visited = new HashSet();
    LinkedList<Object> stack = new LinkedList<Object>();
    stack.addFirst(obj);
    int hash = 0;

    while (!stack.isEmpty()) {
        obj = stack.removeFirst();
        if (obj == null || visited.contains(obj)) {
            continue;
        }

        visited.add(obj);

        if (obj.getClass().isArray()) {
            int len = Array.getLength(obj);
            for (int i = 0; i < len; i++) {
                stack.addFirst(Array.get(obj, i));
            }
            continue;
        }

        if (obj instanceof Collection) {
            stack.addAll(0, (Collection) obj);
            continue;
        }

        if (obj instanceof Map) {
            stack.addAll(0, ((Map) obj).keySet());
            stack.addAll(0, ((Map) obj).values());
            continue;
        }

        if (hasCustomHashCode(obj.getClass())) { // A real hashCode() method exists, call it.
            hash += obj.hashCode();
            continue;
        }

        Collection<Field> fields = getDeepDeclaredFields(obj.getClass());
        for (Field field : fields) {
            try {
                stack.addFirst(field.get(obj));
            } catch (Exception ignored) {
            }
        }
    }
    return hash;
}

From source file:org.jahia.services.content.JCRVersionService.java

/**
 * Finds the closest version in a version history to a specific date.
 *
 * @param vh          the version history in which to lookup versions
 * @param versionDate the date to compare with. Note that it will find the closest version at OR BEFORE the date
 * @return the closest version at or before the date specified.
 * @throws RepositoryException/*from  ww w .  j  a va2s.  c  o  m*/
 */
public static Version findClosestVersion(VersionHistory vh, Date versionDate) throws RepositoryException {
    VersionIterator vi = null;
    try {
        vi = vh.getAllLinearVersions();
    } catch (ItemNotFoundException e) {
        String[] labels = vh.getVersionLabels();
        for (String label : labels) {
            if (label.startsWith(vh.getSession().getWorkspace().getName() + "_removed")) {
                try {
                    Date removedAt = DATE_FORMAT.parseDateTime(StringUtils.substringAfter(label,
                            vh.getSession().getWorkspace().getName() + "_removed_at_")).toDate();
                    if (removedAt.before(versionDate)) {
                        return null;
                    }
                } catch (IllegalArgumentException e1) {
                    logger.error("Cannot parse deletion date for label " + label, e1);
                    return null;
                }
                Version base = vh.getVersionByLabel(label);
                LinkedList<Version> versions = new LinkedList<Version>();
                while (base != null) {
                    versions.addFirst(base);
                    Version[] preds = base.getPredecessors();
                    if (preds.length == 0) {
                        base = null;
                    } else {
                        base = preds[0];
                    }
                }
                vi = new VersionIteratorImpl(versions.iterator(), versions.size());
                break;
            }
        }
        if (vi == null) {
            return null;
        }
    }

    if (vi.getSize() <= 1) {
        return null;
    }

    Version lastVersion = null;
    Version closestVersion = null;
    if (vi.hasNext()) {
        vi.nextVersion();
        // the first is the root version, which has no properties, so we will ignore it.
    }
    String nodeTitle = null;
    StringBuilder propertyString = null;
    while (vi.hasNext()) {
        Version v = vi.nextVersion();
        if (logger.isDebugEnabled()) {
            try {
                Node frozenNode = v.getFrozenNode();
                propertyString = new StringBuilder();
                PropertyIterator propertyIterator = frozenNode.getProperties();
                while (propertyIterator.hasNext()) {
                    Property property = propertyIterator.nextProperty();
                    propertyString.append("  ");
                    propertyString.append(property.getName());
                    propertyString.append("=");
                    if (property.isMultiple()) {
                        for (Value value : property.getValues()) {
                            propertyString.append(value.getString());
                            propertyString.append(",");
                        }
                    } else {
                        propertyString.append(property.getValue().getString());
                    }
                    propertyString.append("\n");
                }
            } catch (IllegalStateException e) {
                propertyString.append(e.getMessage()).append("\n");
            }
        }
        Date checkinDate = null;
        boolean checkinDateAvailable = false;
        if (v.getCreated().getTime().compareTo(versionDate) > 0) {
            // this can happen if we have a checkinDate, but try to resolve using the creation date.
            closestVersion = lastVersion;
            break;
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Version " + v.getName() + " checkinDateAvailable=" + checkinDateAvailable
                    + " checkinDate=" + checkinDate + " created=" + v.getCreated().getTime() + " properties:"
                    + propertyString.toString());
        }
        lastVersion = v;
    }
    if (closestVersion == null && lastVersion != null) {
        // if we haven't found anything, maybe it's the last version that we should be using ?
        if (lastVersion.getCreated().getTime().compareTo(versionDate) <= 0) {
            closestVersion = lastVersion;
        }
    }
    if (closestVersion != null && logger.isDebugEnabled()) {
        logger.debug("Resolved date " + versionDate + " for node title " + nodeTitle + " to closest version "
                + closestVersion.getName() + " createdTime=" + closestVersion.getCreated().getTime());
    }
    return closestVersion;
}

From source file:eulermind.importer.LineNode.java

private static LinkedList<LineNode> popSameBlankLineNodes(LinkedList<LineNode> stack) {
    int lastBlankLines = stack.peekLast().m_blankLines;
    LinkedList<LineNode> lastSameLineNodes = new LinkedList<LineNode>();

    while (!stack.isEmpty() && stack.peekLast().m_blankLines == lastBlankLines) {
        //pollLast? addFirst??
        lastSameLineNodes.addFirst(stack.pollLast());
    }/*from  ww w .  j av  a  2s  .c  o  m*/
    return lastSameLineNodes;
}

From source file:org.dcm4che3.conf.core.misc.DeepEquals.java

/**
 * Compare two objects with a 'deep' comparison.  This will traverse the
 * Object graph and perform either a field-by-field comparison on each
 * object (if no .equals() method has been overridden from Object), or it
 * will call the customized .equals() method if it exists.  This method will
 * allow object graphs loaded at different times (with different object ids)
 * to be reliably compared.  Object.equals() / Object.hashCode() rely on the
 * object's identity, which would not consider to equivalent objects necessarily
 * equals.  This allows graphs containing instances of Classes that did no
 * overide .equals() / .hashCode() to be compared.  For example, testing for
 * existence in a cache.  Relying on an objects identity will not locate an
 * object in cache, yet relying on it being equivalent will.<br/><br/>
 *
 * This method will handle cycles correctly, for example A->B->C->A.  Suppose a and
 * a' are two separate instances of the A with the same values for all fields on
 * A, B, and C.  Then a.deepEquals(a') will return true.  It uses cycle detection
 * storing visited objects in a Set to prevent endless loops.
 * @param a Object one to compare//from   ww  w  .  j  a v  a2  s  . c o m
 * @param b Object two to compare
 * @return true if a is equivalent to b, false otherwise.  Equivalent means that
 * all field values of both subgraphs are the same, either at the field level
 * or via the respectively encountered overridden .equals() methods during
 * traversal.
 */
public static boolean deepEquals(Object a, Object b) {
    Set visited = new HashSet<DualKey>();
    LinkedList<DualKey> stack = new LinkedList<DualKey>();
    stack.addFirst(new DualKey(a, b));

    while (!stack.isEmpty()) {

        DualKey dualKey = stack.removeFirst();
        lastDualKey = dualKey;

        visited.add(dualKey);

        if (dualKey._key1 == dualKey._key2) { // Same instance is always equal to itself.
            continue;
        }

        if (dualKey._key1 == null || dualKey._key2 == null) {
            // check if one is null and another is an empty array

            if (dualKey._key1 == null) {
                if (dualKey._key2.getClass().isArray() && ((Object[]) dualKey._key2).length == 0)
                    continue;
            }
            if (dualKey._key2 == null) {
                if (dualKey._key1.getClass().isArray() && ((Object[]) dualKey._key1).length == 0)
                    continue;
            }

            // If either one is null, not equal (both can't be null, due to above comparison).
            return false;
        }

        if (!dualKey._key1.getClass().equals(dualKey._key2.getClass())) { // Must be same class
            return false;
        }

        // Handle all [] types.  In order to be equal, the arrays must be the same 
        // length, be of the same type, be in the same order, and all elements within
        // the array must be deeply equivalent.
        if (dualKey._key1.getClass().isArray()) {
            if (!compareArrays(dualKey._key1, dualKey._key2, stack, visited)) {
                return false;
            }
            continue;
        }

        // Special handle SortedSets because they are fast to compare because their
        // elements must be in the same order to be equivalent Sets.
        if (dualKey._key1 instanceof SortedSet) {
            if (!compareOrderedCollection((Collection) dualKey._key1, (Collection) dualKey._key2, stack,
                    visited)) {
                return false;
            }
            continue;
        }

        // Handled unordered Sets.  This is a slightly more expensive comparison because order cannot
        // be assumed, a temporary Map must be created, however the comparison still runs in O(N) time.
        if (dualKey._key1 instanceof Set) {
            if (!compareUnorderedCollection((Collection) dualKey._key1, (Collection) dualKey._key2, stack,
                    visited)) {
                return false;
            }
            continue;
        }

        // Check any Collection that is not a Set.  In these cases, element order
        // matters, therefore this comparison is faster than using unordered comparison.
        if (dualKey._key1 instanceof Collection) {
            if (!compareOrderedCollection((Collection) dualKey._key1, (Collection) dualKey._key2, stack,
                    visited)) {
                return false;
            }
            continue;
        }

        // Compare two SortedMaps.  This takes advantage of the fact that these
        // Maps can be compared in O(N) time due to their ordering.
        if (dualKey._key1 instanceof SortedMap) {
            if (!compareSortedMap((SortedMap) dualKey._key1, (SortedMap) dualKey._key2, stack, visited)) {
                return false;
            }
            continue;
        }

        // Compare two Unordered Maps. This is a slightly more expensive comparison because
        // order cannot be assumed, therefore a temporary Map must be created, however the
        // comparison still runs in O(N) time.
        if (dualKey._key1 instanceof Map) {
            if (!compareUnorderedMap((Map) dualKey._key1, (Map) dualKey._key2, stack, visited)) {
                return false;
            }
            continue;
        }

        if (hasCustomEquals(dualKey._key1.getClass())) {
            if (!dualKey._key1.equals(dualKey._key2)) {
                return false;
            }
            continue;
        }

        lastClass = dualKey._key1.getClass().toString();

        // check if we have a custom deepequals method for this class
        CustomDeepEquals de = customDeepEquals.get(dualKey._key1.getClass());
        if (de != null) {
            if (!de.deepEquals(dualKey._key1, dualKey._key2))
                return false;
        } else {
            Collection<Field> fields = getDeepDeclaredFields(dualKey._key1.getClass());

            for (Field field : fields) {
                try {

                    DualKey dk = new DualKey(field.get(dualKey._key1), field.get(dualKey._key2),
                            field.getName());
                    if (!visited.contains(dk)) {
                        stack.addFirst(dk);
                    }
                } catch (Exception ignored) {
                }
            }
        }
    }

    return true;
}

From source file:org.dcm4chee.storage.conf.DeepEquals.java

/**
 * Compare two objects with a 'deep' comparison.  This will traverse the
 * Object graph and perform either a field-by-field comparison on each
 * object (if no .equals() method has been overridden from Object), or it
 * will call the customized .equals() method if it exists.  This method will
 * allow object graphs loaded at different times (with different object ids)
 * to be reliably compared.  Object.equals() / Object.hashCode() rely on the
 * object's identity, which would not consider to equivalent objects necessarily
 * equals.  This allows graphs containing instances of Classes that did no
 * overide .equals() / .hashCode() to be compared.  For example, testing for
 * existence in a cache.  Relying on an objects identity will not locate an
 * object in cache, yet relying on it being equivalent will.<br/><br/>
 *
 * This method will handle cycles correctly, for example A->B->C->A.  Suppose a and
 * a' are two separate instances of the A with the same values for all fields on
 * A, B, and C.  Then a.deepEquals(a') will return true.  It uses cycle detection
 * storing visited objects in a Set to prevent endless loops.
 * @param a Object one to compare/*from w  w  w  .  j  a  v  a 2 s.c om*/
 * @param b Object two to compare
 * @return true if a is equivalent to b, false otherwise.  Equivalent means that
 * all field values of both subgraphs are the same, either at the field level
 * or via the respectively encountered overridden .equals() methods during
 * traversal.
 */
public static boolean deepEquals(Object a, Object b) {

    Set visited = new HashSet<DualKey>();
    LinkedList<DualKey> stack = new LinkedList<DualKey>();
    stack.addFirst(new DualKey(a, b));

    while (!stack.isEmpty()) {

        DualKey dualKey = stack.removeFirst();
        lastDualKey = dualKey;

        visited.add(dualKey);

        if (dualKey._key1 == dualKey._key2) { // Same instance is always equal to itself.
            continue;
        }

        if (dualKey._key1 == null || dualKey._key2 == null) {
            // check if one is null and another is an empty array

            if (dualKey._key1 == null) {
                if (dualKey._key2.getClass().isArray() && ((Object[]) dualKey._key2).length == 0)
                    continue;
            }
            if (dualKey._key2 == null) {
                if (dualKey._key1.getClass().isArray() && ((Object[]) dualKey._key1).length == 0)
                    continue;
            }

            // If either one is null, not equal (both can't be null, due to above comparison).
            return false;
        }

        if (dualKey._key1 instanceof Map && dualKey._key2 instanceof Map) {
            // if they are maps - forget about comparing exact classes 
        } else if (!dualKey._key1.getClass().equals(dualKey._key2.getClass())) { // Must be same class
            return false;
        }

        // Handle all [] types.  In order to be equal, the arrays must be the same 
        // length, be of the same type, be in the same order, and all elements within
        // the array must be deeply equivalent.
        if (dualKey._key1.getClass().isArray()) {
            if (!compareArrays(dualKey._key1, dualKey._key2, stack, visited)) {
                return false;
            }
            continue;
        }

        // Special handle SortedSets because they are fast to compare because their
        // elements must be in the same order to be equivalent Sets.
        if (dualKey._key1 instanceof SortedSet) {
            if (!compareOrderedCollection((Collection) dualKey._key1, (Collection) dualKey._key2, stack,
                    visited)) {
                return false;
            }
            continue;
        }

        // Handled unordered Sets.  This is a slightly more expensive comparison because order cannot
        // be assumed, a temporary Map must be created, however the comparison still runs in O(N) time.
        if (dualKey._key1 instanceof Set) {
            if (!compareUnorderedCollection((Collection) dualKey._key1, (Collection) dualKey._key2, stack,
                    visited)) {
                return false;
            }
            continue;
        }

        // Check any Collection that is not a Set.  In these cases, element order
        // matters, therefore this comparison is faster than using unordered comparison.
        if (dualKey._key1 instanceof Collection) {
            if (!compareOrderedCollection((Collection) dualKey._key1, (Collection) dualKey._key2, stack,
                    visited)) {
                return false;
            }
            continue;
        }

        // Compare two SortedMaps.  This takes advantage of the fact that these
        // Maps can be compared in O(N) time due to their ordering.
        if (dualKey._key1 instanceof SortedMap) {
            if (!compareSortedMap((Map) dualKey._key1, (Map) dualKey._key2, stack, visited)) {
                return false;
            }
            continue;
        }

        // Compare two Unordered Maps. This is a slightly more expensive comparison because
        // order cannot be assumed, therefore a temporary Map must be created, however the
        // comparison still runs in O(N) time.
        if (dualKey._key1 instanceof Map) {
            if (!compareUnorderedMap((Map) dualKey._key1, (Map) dualKey._key2, stack, visited)) {
                return false;
            }
            continue;
        }

        if (hasCustomEquals(dualKey._key1.getClass())) {
            if (!dualKey._key1.equals(dualKey._key2)) {
                return false;
            }
            continue;
        }

        lastObject = dualKey._key1;

        // check if we have a custom deepequals method for this class
        CustomDeepEquals de = customDeepEquals.get(dualKey._key1.getClass());
        if (de != null) {
            if (!de.deepEquals(dualKey._key1, dualKey._key2))
                return false;
        } else {
            Collection<Field> fields = getDeepDeclaredFields(dualKey._key1.getClass());

            for (Field field : fields) {
                try {

                    DualKey dk = new DualKey(field.get(dualKey._key1), field.get(dualKey._key2),
                            field.getName());
                    if (!visited.contains(dk)) {
                        stack.addFirst(dk);
                    }
                } catch (Exception ignored) {
                }
            }
        }
    }

    return true;
}

From source file:org.dcm4chee.archive.conf.defaults.DeepEquals.java

/**
 * Compare two objects with a 'deep' comparison.  This will traverse the
 * Object graph and perform either a field-by-field comparison on each
 * object (if no .equals() method has been overridden from Object), or it
 * will call the customized .equals() method if it exists.  This method will
 * allow object graphs loaded at different times (with different object ids)
 * to be reliably compared.  Object.equals() / Object.hashCode() rely on the
 * object's identity, which would not consider to equivalent objects necessarily
 * equals.  This allows graphs containing instances of Classes that did no
 * overide .equals() / .hashCode() to be compared.  For example, testing for
 * existence in a cache.  Relying on an objects identity will not locate an
 * object in cache, yet relying on it being equivalent will.<br/><br/>
 *
 * This method will handle cycles correctly, for example A->B->C->A.  Suppose a and
 * a' are two separate instances of the A with the same values for all fields on
 * A, B, and C.  Then a.deepEquals(a') will return true.  It uses cycle detection
 * storing visited objects in a Set to prevent endless loops.
 * @param a Object one to compare/*from  w  w w  .j a  va2s .  co  m*/
 * @param b Object two to compare
 * @return true if a is equivalent to b, false otherwise.  Equivalent means that
 * all field values of both subgraphs are the same, either at the field level
 * or via the respectively encountered overridden .equals() methods during
 * traversal.
 */
public static boolean deepEquals(Object a, Object b) {
    Set visited = new HashSet<DualKey>();
    LinkedList<DualKey> stack = new LinkedList<DualKey>();
    stack.addFirst(new DualKey(a, b, null));

    while (!stack.isEmpty()) {
        DualKey dualKey = stack.removeFirst();
        lastDualKey = dualKey;

        visited.add(dualKey);

        if (dualKey._key1 == dualKey._key2) { // Same instance is always equal to itself.
            continue;
        }

        if (dualKey._key1 == null || dualKey._key2 == null) {
            // check if one is null and another is an empty array

            if (dualKey._key1 == null) {
                if (dualKey._key2.getClass().isArray() && ((Object[]) dualKey._key2).length == 0)
                    continue;
            }
            if (dualKey._key2 == null) {
                if (dualKey._key1.getClass().isArray() && ((Object[]) dualKey._key1).length == 0)
                    continue;
            }

            // If either one is null, not equal (both can't be null, due to above comparison).
            return false;
        }

        if (!dualKey._key1.getClass().equals(dualKey._key2.getClass())) { // Must be same class
            return false;
        }

        // Handle all [] types.  In order to be equal, the arrays must be the same 
        // length, be of the same type, be in the same order, and all elements within
        // the array must be deeply equivalent.
        if (dualKey._key1.getClass().isArray()) {
            if (!compareArrays(dualKey, stack, visited)) {
                return false;
            }
            continue;
        }

        // Special handle SortedSets because they are fast to compare because their
        // elements must be in the same order to be equivalent Sets.
        if (dualKey._key1 instanceof SortedSet) {
            if (!compareOrderedCollection(dualKey, stack, visited)) {
                return false;
            }
            continue;
        }

        // Handled unordered Sets.  This is a slightly more expensive comparison because order cannot
        // be assumed, a temporary Map must be created, however the comparison still runs in O(N) time.
        if (dualKey._key1 instanceof Set) {
            if (!compareUnorderedCollection(dualKey, stack, visited)) {
                return false;
            }
            continue;
        }

        // Check any Collection that is not a Set.  In these cases, element order
        // matters, therefore this comparison is faster than using unordered comparison.
        if (dualKey._key1 instanceof Collection) {
            if (!compareOrderedCollection(dualKey, stack, visited)) {
                return false;
            }
            continue;
        }

        // Compare two SortedMaps.  This takes advantage of the fact that these
        // Maps can be compared in O(N) time due to their ordering.
        if (dualKey._key1 instanceof SortedMap) {
            if (!compareSortedMap(dualKey, stack, visited)) {
                return false;
            }
            continue;
        }

        // Compare two Unordered Maps. This is a slightly more expensive comparison because
        // order cannot be assumed, therefore a temporary Map must be created, however the
        // comparison still runs in O(N) time.
        if (dualKey._key1 instanceof Map) {
            if (!compareUnorderedMap(dualKey, stack, visited)) {
                return false;
            }
            continue;
        }

        if (hasCustomEquals(dualKey._key1.getClass())) {
            if (!dualKey._key1.equals(dualKey._key2)) {
                return false;
            }
            continue;
        }

        lastClass = dualKey._key1.getClass().toString();

        // check if we have a custom deepequals method for this class
        CustomDeepEquals de = customDeepEquals.get(dualKey._key1.getClass());
        if (de != null) {
            if (!de.deepEquals(dualKey._key1, dualKey._key2))
                return false;
        } else {
            Collection<Field> fields = getDeepDeclaredFields(dualKey._key1.getClass());

            for (Field field : fields) {
                try {

                    DualKey dk = new DualKey(field.get(dualKey._key1), field.get(dualKey._key2),
                            field.getName(), dualKey);
                    if (!visited.contains(dk)) {
                        stack.addFirst(dk);
                    }
                } catch (Exception ignored) {
                }
            }
        }
    }

    return true;
}