0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: package org.apache.commons.lang.builder;
0018:
0019: import java.lang.reflect.AccessibleObject;
0020: import java.lang.reflect.Field;
0021: import java.lang.reflect.Modifier;
0022: import java.util.Arrays;
0023: import java.util.Collections;
0024: import java.util.Collection;
0025: import java.util.Comparator;
0026: import java.util.List;
0027:
0028: import org.apache.commons.lang.math.NumberUtils;
0029:
0030: /**
0031: * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods.
0032: *
0033: * It is consistent with <code>equals(Object)</code> and
0034: * <code>hashcode()</code> built with {@link EqualsBuilder} and
0035: * {@link HashCodeBuilder}.</p>
0036: *
0037: * <p>Two Objects that compare equal using <code>equals(Object)</code> should normally
0038: * also compare equal using <code>compareTo(Object)</code>.</p>
0039: *
0040: * <p>All relevant fields should be included in the calculation of the
0041: * comparison. Derived fields may be ignored. The same fields, in the same
0042: * order, should be used in both <code>compareTo(Object)</code> and
0043: * <code>equals(Object)</code>.</p>
0044: *
0045: * <p>To use this class write code as follows:</p>
0046: *
0047: * <pre>
0048: * public class MyClass {
0049: * String field1;
0050: * int field2;
0051: * boolean field3;
0052: *
0053: * ...
0054: *
0055: * public int compareTo(Object o) {
0056: * MyClass myClass = (MyClass) o;
0057: * return new CompareToBuilder()
0058: * .appendSuper(super.compareTo(o)
0059: * .append(this.field1, myClass.field1)
0060: * .append(this.field2, myClass.field2)
0061: * .append(this.field3, myClass.field3)
0062: * .toComparison();
0063: * }
0064: * }
0065: * </pre>
0066: *
0067: * <p>Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use
0068: * reflection to determine the fields to append. Because fields can be private,
0069: * <code>reflectionCompare</code> uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to
0070: * bypass normal access control checks. This will fail under a security manager,
0071: * unless the appropriate permissions are set up correctly. It is also
0072: * slower than appending explicitly.</p>
0073: *
0074: * <p>A typical implementation of <code>compareTo(Object)</code> using
0075: * <code>reflectionCompare</code> looks like:</p>
0076:
0077: * <pre>
0078: * public int compareTo(Object o) {
0079: * return CompareToBuilder.reflectionCompare(this, o);
0080: * }
0081: * </pre>
0082: *
0083: * @see java.lang.Comparable
0084: * @see java.lang.Object#equals(Object)
0085: * @see java.lang.Object#hashCode()
0086: * @see EqualsBuilder
0087: * @see HashCodeBuilder
0088: * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
0089: * @author Stephen Colebourne
0090: * @author Gary Gregory
0091: * @author Pete Gieser
0092: * @since 1.0
0093: * @version $Id: CompareToBuilder.java 447139 2006-09-17 20:36:53Z bayard $
0094: */
0095: public class CompareToBuilder {
0096:
0097: /**
0098: * Current state of the comparison as appended fields are checked.
0099: */
0100: private int comparison;
0101:
0102: /**
0103: * <p>Constructor for CompareToBuilder.</p>
0104: *
0105: * <p>Starts off assuming that the objects are equal. Multiple calls are
0106: * then made to the various append methods, followed by a call to
0107: * {@link #toComparison} to get the result.</p>
0108: */
0109: public CompareToBuilder() {
0110: super ();
0111: comparison = 0;
0112: }
0113:
0114: //-----------------------------------------------------------------------
0115: /**
0116: * <p>Compares two <code>Object</code>s via reflection.</p>
0117: *
0118: * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
0119: * is used to bypass normal access control checks. This will fail under a
0120: * security manager unless the appropriate permissions are set.</p>
0121: *
0122: * <ul>
0123: * <li>Static fields will not be compared</li>
0124: * <li>Transient members will be not be compared, as they are likely derived
0125: * fields</li>
0126: * <li>Superclass fields will be compared</li>
0127: * </ul>
0128: *
0129: * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
0130: * they are considered equal.</p>
0131: *
0132: * @param lhs left-hand object
0133: * @param rhs right-hand object
0134: * @return a negative integer, zero, or a positive integer as <code>lhs</code>
0135: * is less than, equal to, or greater than <code>rhs</code>
0136: * @throws NullPointerException if either (but not both) parameters are
0137: * <code>null</code>
0138: * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
0139: * with <code>lhs</code>
0140: */
0141: public static int reflectionCompare(Object lhs, Object rhs) {
0142: return reflectionCompare(lhs, rhs, false, null, null);
0143: }
0144:
0145: /**
0146: * <p>Compares two <code>Object</code>s via reflection.</p>
0147: *
0148: * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
0149: * is used to bypass normal access control checks. This will fail under a
0150: * security manager unless the appropriate permissions are set.</p>
0151: *
0152: * <ul>
0153: * <li>Static fields will not be compared</li>
0154: * <li>If <code>compareTransients</code> is <code>true</code>,
0155: * compares transient members. Otherwise ignores them, as they
0156: * are likely derived fields.</li>
0157: * <li>Superclass fields will be compared</li>
0158: * </ul>
0159: *
0160: * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
0161: * they are considered equal.</p>
0162: *
0163: * @param lhs left-hand object
0164: * @param rhs right-hand object
0165: * @param compareTransients whether to compare transient fields
0166: * @return a negative integer, zero, or a positive integer as <code>lhs</code>
0167: * is less than, equal to, or greater than <code>rhs</code>
0168: * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
0169: * (but not both) is <code>null</code>
0170: * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
0171: * with <code>lhs</code>
0172: */
0173: public static int reflectionCompare(Object lhs, Object rhs,
0174: boolean compareTransients) {
0175: return reflectionCompare(lhs, rhs, compareTransients, null,
0176: null);
0177: }
0178:
0179: /**
0180: * <p>Compares two <code>Object</code>s via reflection.</p>
0181: *
0182: * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
0183: * is used to bypass normal access control checks. This will fail under a
0184: * security manager unless the appropriate permissions are set.</p>
0185: *
0186: * <ul>
0187: * <li>Static fields will not be compared</li>
0188: * <li>If <code>compareTransients</code> is <code>true</code>,
0189: * compares transient members. Otherwise ignores them, as they
0190: * are likely derived fields.</li>
0191: * <li>Superclass fields will be compared</li>
0192: * </ul>
0193: *
0194: * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
0195: * they are considered equal.</p>
0196: *
0197: * @param lhs left-hand object
0198: * @param rhs right-hand object
0199: * @param excludeFields Collection of String fields to exclude
0200: * @return a negative integer, zero, or a positive integer as <code>lhs</code>
0201: * is less than, equal to, or greater than <code>rhs</code>
0202: * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
0203: * (but not both) is <code>null</code>
0204: * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
0205: * with <code>lhs</code>
0206: * @since 2.2
0207: */
0208: public static int reflectionCompare(Object lhs, Object rhs,
0209: Collection /*String*/excludeFields) {
0210: return reflectionCompare(lhs, rhs, ReflectionToStringBuilder
0211: .toNoNullStringArray(excludeFields));
0212: }
0213:
0214: /**
0215: * <p>Compares two <code>Object</code>s via reflection.</p>
0216: *
0217: * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
0218: * is used to bypass normal access control checks. This will fail under a
0219: * security manager unless the appropriate permissions are set.</p>
0220: *
0221: * <ul>
0222: * <li>Static fields will not be compared</li>
0223: * <li>If <code>compareTransients</code> is <code>true</code>,
0224: * compares transient members. Otherwise ignores them, as they
0225: * are likely derived fields.</li>
0226: * <li>Superclass fields will be compared</li>
0227: * </ul>
0228: *
0229: * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
0230: * they are considered equal.</p>
0231: *
0232: * @param lhs left-hand object
0233: * @param rhs right-hand object
0234: * @param excludeFields array of fields to exclude
0235: * @return a negative integer, zero, or a positive integer as <code>lhs</code>
0236: * is less than, equal to, or greater than <code>rhs</code>
0237: * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
0238: * (but not both) is <code>null</code>
0239: * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
0240: * with <code>lhs</code>
0241: * @since 2.2
0242: */
0243: public static int reflectionCompare(Object lhs, Object rhs,
0244: String[] excludeFields) {
0245: return reflectionCompare(lhs, rhs, false, null, excludeFields);
0246: }
0247:
0248: /**
0249: * <p>Compares two <code>Object</code>s via reflection.</p>
0250: *
0251: * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
0252: * is used to bypass normal access control checks. This will fail under a
0253: * security manager unless the appropriate permissions are set.</p>
0254: *
0255: * <ul>
0256: * <li>Static fields will not be compared</li>
0257: * <li>If the <code>compareTransients</code> is <code>true</code>,
0258: * compares transient members. Otherwise ignores them, as they
0259: * are likely derived fields.</li>
0260: * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>.
0261: * If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
0262: * </ul>
0263: *
0264: * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
0265: * they are considered equal.</p>
0266: *
0267: * @param lhs left-hand object
0268: * @param rhs right-hand object
0269: * @param compareTransients whether to compare transient fields
0270: * @param reflectUpToClass last superclass for which fields are compared
0271: * @return a negative integer, zero, or a positive integer as <code>lhs</code>
0272: * is less than, equal to, or greater than <code>rhs</code>
0273: * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
0274: * (but not both) is <code>null</code>
0275: * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
0276: * with <code>lhs</code>
0277: * @since 2.0
0278: */
0279: public static int reflectionCompare(Object lhs, Object rhs,
0280: boolean compareTransients, Class reflectUpToClass) {
0281: return reflectionCompare(lhs, rhs, false, reflectUpToClass,
0282: null);
0283: }
0284:
0285: /**
0286: * <p>Compares two <code>Object</code>s via reflection.</p>
0287: *
0288: * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
0289: * is used to bypass normal access control checks. This will fail under a
0290: * security manager unless the appropriate permissions are set.</p>
0291: *
0292: * <ul>
0293: * <li>Static fields will not be compared</li>
0294: * <li>If the <code>compareTransients</code> is <code>true</code>,
0295: * compares transient members. Otherwise ignores them, as they
0296: * are likely derived fields.</li>
0297: * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>.
0298: * If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
0299: * </ul>
0300: *
0301: * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
0302: * they are considered equal.</p>
0303: *
0304: * @param lhs left-hand object
0305: * @param rhs right-hand object
0306: * @param compareTransients whether to compare transient fields
0307: * @param reflectUpToClass last superclass for which fields are compared
0308: * @param excludeFields fields to exclude
0309: * @return a negative integer, zero, or a positive integer as <code>lhs</code>
0310: * is less than, equal to, or greater than <code>rhs</code>
0311: * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
0312: * (but not both) is <code>null</code>
0313: * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
0314: * with <code>lhs</code>
0315: * @since 2.2
0316: */
0317: public static int reflectionCompare(Object lhs, Object rhs,
0318: boolean compareTransients, Class reflectUpToClass,
0319: String[] excludeFields) {
0320:
0321: if (lhs == rhs) {
0322: return 0;
0323: }
0324: if (lhs == null || rhs == null) {
0325: throw new NullPointerException();
0326: }
0327: Class lhsClazz = lhs.getClass();
0328: if (!lhsClazz.isInstance(rhs)) {
0329: throw new ClassCastException();
0330: }
0331: CompareToBuilder compareToBuilder = new CompareToBuilder();
0332: reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder,
0333: compareTransients, excludeFields);
0334: while (lhsClazz.getSuperclass() != null
0335: && lhsClazz != reflectUpToClass) {
0336: lhsClazz = lhsClazz.getSuperclass();
0337: reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder,
0338: compareTransients, excludeFields);
0339: }
0340: return compareToBuilder.toComparison();
0341: }
0342:
0343: /**
0344: * <p>Appends to <code>builder</code> the comparison of <code>lhs</code>
0345: * to <code>rhs</code> using the fields defined in <code>clazz</code>.</p>
0346: *
0347: * @param lhs left-hand object
0348: * @param rhs right-hand object
0349: * @param clazz <code>Class</code> that defines fields to be compared
0350: * @param builder <code>CompareToBuilder</code> to append to
0351: * @param useTransients whether to compare transient fields
0352: * @param excludeFields fields to exclude
0353: */
0354: private static void reflectionAppend(Object lhs, Object rhs,
0355: Class clazz, CompareToBuilder builder,
0356: boolean useTransients, String[] excludeFields) {
0357:
0358: Field[] fields = clazz.getDeclaredFields();
0359: List excludedFieldList = excludeFields != null ? Arrays
0360: .asList(excludeFields) : Collections.EMPTY_LIST;
0361: AccessibleObject.setAccessible(fields, true);
0362: for (int i = 0; i < fields.length && builder.comparison == 0; i++) {
0363: Field f = fields[i];
0364: if (!excludedFieldList.contains(f.getName())
0365: && (f.getName().indexOf('$') == -1)
0366: && (useTransients || !Modifier.isTransient(f
0367: .getModifiers()))
0368: && (!Modifier.isStatic(f.getModifiers()))) {
0369: try {
0370: builder.append(f.get(lhs), f.get(rhs));
0371: } catch (IllegalAccessException e) {
0372: // This can't happen. Would get a Security exception instead.
0373: // Throw a runtime exception in case the impossible happens.
0374: throw new InternalError(
0375: "Unexpected IllegalAccessException");
0376: }
0377: }
0378: }
0379: }
0380:
0381: //-----------------------------------------------------------------------
0382: /**
0383: * <p>Appends to the <code>builder</code> the <code>compareTo(Object)</code>
0384: * result of the superclass.</p>
0385: *
0386: * @param superCompareTo result of calling <code>super.compareTo(Object)</code>
0387: * @return this - used to chain append calls
0388: * @since 2.0
0389: */
0390: public CompareToBuilder appendSuper(int super CompareTo) {
0391: if (comparison != 0) {
0392: return this ;
0393: }
0394: comparison = super CompareTo;
0395: return this ;
0396: }
0397:
0398: //-----------------------------------------------------------------------
0399: /**
0400: * <p>Appends to the <code>builder</code> the comparison of
0401: * two <code>Object</code>s.</p>
0402: *
0403: * <ol>
0404: * <li>Check if <code>lhs == rhs</code></li>
0405: * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
0406: * a <code>null</code> object is less than a non-<code>null</code> object</li>
0407: * <li>Check the object contents</li>
0408: * </ol>
0409: *
0410: * <p><code>lhs</code> must either be an array or implement {@link Comparable}.</p>
0411: *
0412: * @param lhs left-hand object
0413: * @param rhs right-hand object
0414: * @return this - used to chain append calls
0415: * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
0416: * with <code>lhs</code>
0417: */
0418: public CompareToBuilder append(Object lhs, Object rhs) {
0419: return append(lhs, rhs, null);
0420: }
0421:
0422: /**
0423: * <p>Appends to the <code>builder</code> the comparison of
0424: * two <code>Object</code>s.</p>
0425: *
0426: * <ol>
0427: * <li>Check if <code>lhs == rhs</code></li>
0428: * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
0429: * a <code>null</code> object is less than a non-<code>null</code> object</li>
0430: * <li>Check the object contents</li>
0431: * </ol>
0432: *
0433: * <p>If <code>lhs</code> is an array, array comparison methods will be used.
0434: * Otherwise <code>comparator</code> will be used to compare the objects.
0435: * If <code>comparator</code> is <code>null</code>, <code>lhs</code> must
0436: * implement {@link Comparable} instead.</p>
0437: *
0438: * @param lhs left-hand object
0439: * @param rhs right-hand object
0440: * @param comparator <code>Comparator</code> used to compare the objects,
0441: * <code>null</code> means treat lhs as <code>Comparable</code>
0442: * @return this - used to chain append calls
0443: * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
0444: * with <code>lhs</code>
0445: * @since 2.0
0446: */
0447: public CompareToBuilder append(Object lhs, Object rhs,
0448: Comparator comparator) {
0449: if (comparison != 0) {
0450: return this ;
0451: }
0452: if (lhs == rhs) {
0453: return this ;
0454: }
0455: if (lhs == null) {
0456: comparison = -1;
0457: return this ;
0458: }
0459: if (rhs == null) {
0460: comparison = +1;
0461: return this ;
0462: }
0463: if (lhs.getClass().isArray()) {
0464: // switch on type of array, to dispatch to the correct handler
0465: // handles multi dimensional arrays
0466: // throws a ClassCastException if rhs is not the correct array type
0467: if (lhs instanceof long[]) {
0468: append((long[]) lhs, (long[]) rhs);
0469: } else if (lhs instanceof int[]) {
0470: append((int[]) lhs, (int[]) rhs);
0471: } else if (lhs instanceof short[]) {
0472: append((short[]) lhs, (short[]) rhs);
0473: } else if (lhs instanceof char[]) {
0474: append((char[]) lhs, (char[]) rhs);
0475: } else if (lhs instanceof byte[]) {
0476: append((byte[]) lhs, (byte[]) rhs);
0477: } else if (lhs instanceof double[]) {
0478: append((double[]) lhs, (double[]) rhs);
0479: } else if (lhs instanceof float[]) {
0480: append((float[]) lhs, (float[]) rhs);
0481: } else if (lhs instanceof boolean[]) {
0482: append((boolean[]) lhs, (boolean[]) rhs);
0483: } else {
0484: // not an array of primitives
0485: // throws a ClassCastException if rhs is not an array
0486: append((Object[]) lhs, (Object[]) rhs, comparator);
0487: }
0488: } else {
0489: // the simple case, not an array, just test the element
0490: if (comparator == null) {
0491: comparison = ((Comparable) lhs).compareTo(rhs);
0492: } else {
0493: comparison = comparator.compare(lhs, rhs);
0494: }
0495: }
0496: return this ;
0497: }
0498:
0499: //-------------------------------------------------------------------------
0500: /**
0501: * Appends to the <code>builder</code> the comparison of
0502: * two <code>long</code>s.
0503: *
0504: * @param lhs left-hand value
0505: * @param rhs right-hand value
0506: * @return this - used to chain append calls
0507: */
0508: public CompareToBuilder append(long lhs, long rhs) {
0509: if (comparison != 0) {
0510: return this ;
0511: }
0512: comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
0513: return this ;
0514: }
0515:
0516: /**
0517: * Appends to the <code>builder</code> the comparison of
0518: * two <code>int</code>s.
0519: *
0520: * @param lhs left-hand value
0521: * @param rhs right-hand value
0522: * @return this - used to chain append calls
0523: */
0524: public CompareToBuilder append(int lhs, int rhs) {
0525: if (comparison != 0) {
0526: return this ;
0527: }
0528: comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
0529: return this ;
0530: }
0531:
0532: /**
0533: * Appends to the <code>builder</code> the comparison of
0534: * two <code>short</code>s.
0535: *
0536: * @param lhs left-hand value
0537: * @param rhs right-hand value
0538: * @return this - used to chain append calls
0539: */
0540: public CompareToBuilder append(short lhs, short rhs) {
0541: if (comparison != 0) {
0542: return this ;
0543: }
0544: comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
0545: return this ;
0546: }
0547:
0548: /**
0549: * Appends to the <code>builder</code> the comparison of
0550: * two <code>char</code>s.
0551: *
0552: * @param lhs left-hand value
0553: * @param rhs right-hand value
0554: * @return this - used to chain append calls
0555: */
0556: public CompareToBuilder append(char lhs, char rhs) {
0557: if (comparison != 0) {
0558: return this ;
0559: }
0560: comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
0561: return this ;
0562: }
0563:
0564: /**
0565: * Appends to the <code>builder</code> the comparison of
0566: * two <code>byte</code>s.
0567: *
0568: * @param lhs left-hand value
0569: * @param rhs right-hand value
0570: * @return this - used to chain append calls
0571: */
0572: public CompareToBuilder append(byte lhs, byte rhs) {
0573: if (comparison != 0) {
0574: return this ;
0575: }
0576: comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
0577: return this ;
0578: }
0579:
0580: /**
0581: * <p>Appends to the <code>builder</code> the comparison of
0582: * two <code>double</code>s.</p>
0583: *
0584: * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
0585: *
0586: * <p>It is compatible with the hash code generated by
0587: * <code>HashCodeBuilder</code>.</p>
0588: *
0589: * @param lhs left-hand value
0590: * @param rhs right-hand value
0591: * @return this - used to chain append calls
0592: */
0593: public CompareToBuilder append(double lhs, double rhs) {
0594: if (comparison != 0) {
0595: return this ;
0596: }
0597: comparison = NumberUtils.compare(lhs, rhs);
0598: return this ;
0599: }
0600:
0601: /**
0602: * <p>Appends to the <code>builder</code> the comparison of
0603: * two <code>float</code>s.</p>
0604: *
0605: * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
0606: *
0607: * <p>It is compatible with the hash code generated by
0608: * <code>HashCodeBuilder</code>.</p>
0609: *
0610: * @param lhs left-hand value
0611: * @param rhs right-hand value
0612: * @return this - used to chain append calls
0613: */
0614: public CompareToBuilder append(float lhs, float rhs) {
0615: if (comparison != 0) {
0616: return this ;
0617: }
0618: comparison = NumberUtils.compare(lhs, rhs);
0619: return this ;
0620: }
0621:
0622: /**
0623: * Appends to the <code>builder</code> the comparison of
0624: * two <code>booleans</code>s.
0625: *
0626: * @param lhs left-hand value
0627: * @param rhs right-hand value
0628: * @return this - used to chain append calls
0629: */
0630: public CompareToBuilder append(boolean lhs, boolean rhs) {
0631: if (comparison != 0) {
0632: return this ;
0633: }
0634: if (lhs == rhs) {
0635: return this ;
0636: }
0637: if (lhs == false) {
0638: comparison = -1;
0639: } else {
0640: comparison = +1;
0641: }
0642: return this ;
0643: }
0644:
0645: //-----------------------------------------------------------------------
0646: /**
0647: * <p>Appends to the <code>builder</code> the deep comparison of
0648: * two <code>Object</code> arrays.</p>
0649: *
0650: * <ol>
0651: * <li>Check if arrays are the same using <code>==</code></li>
0652: * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
0653: * <li>Check array length, a short length array is less than a long length array</li>
0654: * <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
0655: * </ol>
0656: *
0657: * <p>This method will also will be called for the top level of multi-dimensional,
0658: * ragged, and multi-typed arrays.</p>
0659: *
0660: * @param lhs left-hand array
0661: * @param rhs right-hand array
0662: * @return this - used to chain append calls
0663: * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
0664: * with <code>lhs</code>
0665: */
0666: public CompareToBuilder append(Object[] lhs, Object[] rhs) {
0667: return append(lhs, rhs, null);
0668: }
0669:
0670: /**
0671: * <p>Appends to the <code>builder</code> the deep comparison of
0672: * two <code>Object</code> arrays.</p>
0673: *
0674: * <ol>
0675: * <li>Check if arrays are the same using <code>==</code></li>
0676: * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
0677: * <li>Check array length, a short length array is less than a long length array</li>
0678: * <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
0679: * </ol>
0680: *
0681: * <p>This method will also will be called for the top level of multi-dimensional,
0682: * ragged, and multi-typed arrays.</p>
0683: *
0684: * @param lhs left-hand array
0685: * @param rhs right-hand array
0686: * @param comparator <code>Comparator</code> to use to compare the array elements,
0687: * <code>null</code> means to treat <code>lhs</code> elements as <code>Comparable</code>.
0688: * @return this - used to chain append calls
0689: * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
0690: * with <code>lhs</code>
0691: * @since 2.0
0692: */
0693: public CompareToBuilder append(Object[] lhs, Object[] rhs,
0694: Comparator comparator) {
0695: if (comparison != 0) {
0696: return this ;
0697: }
0698: if (lhs == rhs) {
0699: return this ;
0700: }
0701: if (lhs == null) {
0702: comparison = -1;
0703: return this ;
0704: }
0705: if (rhs == null) {
0706: comparison = +1;
0707: return this ;
0708: }
0709: if (lhs.length != rhs.length) {
0710: comparison = (lhs.length < rhs.length) ? -1 : +1;
0711: return this ;
0712: }
0713: for (int i = 0; i < lhs.length && comparison == 0; i++) {
0714: append(lhs[i], rhs[i], comparator);
0715: }
0716: return this ;
0717: }
0718:
0719: /**
0720: * <p>Appends to the <code>builder</code> the deep comparison of
0721: * two <code>long</code> arrays.</p>
0722: *
0723: * <ol>
0724: * <li>Check if arrays are the same using <code>==</code></li>
0725: * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
0726: * <li>Check array length, a shorter length array is less than a longer length array</li>
0727: * <li>Check array contents element by element using {@link #append(long, long)}</li>
0728: * </ol>
0729: *
0730: * @param lhs left-hand array
0731: * @param rhs right-hand array
0732: * @return this - used to chain append calls
0733: */
0734: public CompareToBuilder append(long[] lhs, long[] rhs) {
0735: if (comparison != 0) {
0736: return this ;
0737: }
0738: if (lhs == rhs) {
0739: return this ;
0740: }
0741: if (lhs == null) {
0742: comparison = -1;
0743: return this ;
0744: }
0745: if (rhs == null) {
0746: comparison = +1;
0747: return this ;
0748: }
0749: if (lhs.length != rhs.length) {
0750: comparison = (lhs.length < rhs.length) ? -1 : +1;
0751: return this ;
0752: }
0753: for (int i = 0; i < lhs.length && comparison == 0; i++) {
0754: append(lhs[i], rhs[i]);
0755: }
0756: return this ;
0757: }
0758:
0759: /**
0760: * <p>Appends to the <code>builder</code> the deep comparison of
0761: * two <code>int</code> arrays.</p>
0762: *
0763: * <ol>
0764: * <li>Check if arrays are the same using <code>==</code></li>
0765: * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
0766: * <li>Check array length, a shorter length array is less than a longer length array</li>
0767: * <li>Check array contents element by element using {@link #append(int, int)}</li>
0768: * </ol>
0769: *
0770: * @param lhs left-hand array
0771: * @param rhs right-hand array
0772: * @return this - used to chain append calls
0773: */
0774: public CompareToBuilder append(int[] lhs, int[] rhs) {
0775: if (comparison != 0) {
0776: return this ;
0777: }
0778: if (lhs == rhs) {
0779: return this ;
0780: }
0781: if (lhs == null) {
0782: comparison = -1;
0783: return this ;
0784: }
0785: if (rhs == null) {
0786: comparison = +1;
0787: return this ;
0788: }
0789: if (lhs.length != rhs.length) {
0790: comparison = (lhs.length < rhs.length) ? -1 : +1;
0791: return this ;
0792: }
0793: for (int i = 0; i < lhs.length && comparison == 0; i++) {
0794: append(lhs[i], rhs[i]);
0795: }
0796: return this ;
0797: }
0798:
0799: /**
0800: * <p>Appends to the <code>builder</code> the deep comparison of
0801: * two <code>short</code> arrays.</p>
0802: *
0803: * <ol>
0804: * <li>Check if arrays are the same using <code>==</code></li>
0805: * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
0806: * <li>Check array length, a shorter length array is less than a longer length array</li>
0807: * <li>Check array contents element by element using {@link #append(short, short)}</li>
0808: * </ol>
0809: *
0810: * @param lhs left-hand array
0811: * @param rhs right-hand array
0812: * @return this - used to chain append calls
0813: */
0814: public CompareToBuilder append(short[] lhs, short[] rhs) {
0815: if (comparison != 0) {
0816: return this ;
0817: }
0818: if (lhs == rhs) {
0819: return this ;
0820: }
0821: if (lhs == null) {
0822: comparison = -1;
0823: return this ;
0824: }
0825: if (rhs == null) {
0826: comparison = +1;
0827: return this ;
0828: }
0829: if (lhs.length != rhs.length) {
0830: comparison = (lhs.length < rhs.length) ? -1 : +1;
0831: return this ;
0832: }
0833: for (int i = 0; i < lhs.length && comparison == 0; i++) {
0834: append(lhs[i], rhs[i]);
0835: }
0836: return this ;
0837: }
0838:
0839: /**
0840: * <p>Appends to the <code>builder</code> the deep comparison of
0841: * two <code>char</code> arrays.</p>
0842: *
0843: * <ol>
0844: * <li>Check if arrays are the same using <code>==</code></li>
0845: * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
0846: * <li>Check array length, a shorter length array is less than a longer length array</li>
0847: * <li>Check array contents element by element using {@link #append(char, char)}</li>
0848: * </ol>
0849: *
0850: * @param lhs left-hand array
0851: * @param rhs right-hand array
0852: * @return this - used to chain append calls
0853: */
0854: public CompareToBuilder append(char[] lhs, char[] rhs) {
0855: if (comparison != 0) {
0856: return this ;
0857: }
0858: if (lhs == rhs) {
0859: return this ;
0860: }
0861: if (lhs == null) {
0862: comparison = -1;
0863: return this ;
0864: }
0865: if (rhs == null) {
0866: comparison = +1;
0867: return this ;
0868: }
0869: if (lhs.length != rhs.length) {
0870: comparison = (lhs.length < rhs.length) ? -1 : +1;
0871: return this ;
0872: }
0873: for (int i = 0; i < lhs.length && comparison == 0; i++) {
0874: append(lhs[i], rhs[i]);
0875: }
0876: return this ;
0877: }
0878:
0879: /**
0880: * <p>Appends to the <code>builder</code> the deep comparison of
0881: * two <code>byte</code> arrays.</p>
0882: *
0883: * <ol>
0884: * <li>Check if arrays are the same using <code>==</code></li>
0885: * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
0886: * <li>Check array length, a shorter length array is less than a longer length array</li>
0887: * <li>Check array contents element by element using {@link #append(byte, byte)}</li>
0888: * </ol>
0889: *
0890: * @param lhs left-hand array
0891: * @param rhs right-hand array
0892: * @return this - used to chain append calls
0893: */
0894: public CompareToBuilder append(byte[] lhs, byte[] rhs) {
0895: if (comparison != 0) {
0896: return this ;
0897: }
0898: if (lhs == rhs) {
0899: return this ;
0900: }
0901: if (lhs == null) {
0902: comparison = -1;
0903: return this ;
0904: }
0905: if (rhs == null) {
0906: comparison = +1;
0907: return this ;
0908: }
0909: if (lhs.length != rhs.length) {
0910: comparison = (lhs.length < rhs.length) ? -1 : +1;
0911: return this ;
0912: }
0913: for (int i = 0; i < lhs.length && comparison == 0; i++) {
0914: append(lhs[i], rhs[i]);
0915: }
0916: return this ;
0917: }
0918:
0919: /**
0920: * <p>Appends to the <code>builder</code> the deep comparison of
0921: * two <code>double</code> arrays.</p>
0922: *
0923: * <ol>
0924: * <li>Check if arrays are the same using <code>==</code></li>
0925: * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
0926: * <li>Check array length, a shorter length array is less than a longer length array</li>
0927: * <li>Check array contents element by element using {@link #append(double, double)}</li>
0928: * </ol>
0929: *
0930: * @param lhs left-hand array
0931: * @param rhs right-hand array
0932: * @return this - used to chain append calls
0933: */
0934: public CompareToBuilder append(double[] lhs, double[] rhs) {
0935: if (comparison != 0) {
0936: return this ;
0937: }
0938: if (lhs == rhs) {
0939: return this ;
0940: }
0941: if (lhs == null) {
0942: comparison = -1;
0943: return this ;
0944: }
0945: if (rhs == null) {
0946: comparison = +1;
0947: return this ;
0948: }
0949: if (lhs.length != rhs.length) {
0950: comparison = (lhs.length < rhs.length) ? -1 : +1;
0951: return this ;
0952: }
0953: for (int i = 0; i < lhs.length && comparison == 0; i++) {
0954: append(lhs[i], rhs[i]);
0955: }
0956: return this ;
0957: }
0958:
0959: /**
0960: * <p>Appends to the <code>builder</code> the deep comparison of
0961: * two <code>float</code> arrays.</p>
0962: *
0963: * <ol>
0964: * <li>Check if arrays are the same using <code>==</code></li>
0965: * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
0966: * <li>Check array length, a shorter length array is less than a longer length array</li>
0967: * <li>Check array contents element by element using {@link #append(float, float)}</li>
0968: * </ol>
0969: *
0970: * @param lhs left-hand array
0971: * @param rhs right-hand array
0972: * @return this - used to chain append calls
0973: */
0974: public CompareToBuilder append(float[] lhs, float[] rhs) {
0975: if (comparison != 0) {
0976: return this ;
0977: }
0978: if (lhs == rhs) {
0979: return this ;
0980: }
0981: if (lhs == null) {
0982: comparison = -1;
0983: return this ;
0984: }
0985: if (rhs == null) {
0986: comparison = +1;
0987: return this ;
0988: }
0989: if (lhs.length != rhs.length) {
0990: comparison = (lhs.length < rhs.length) ? -1 : +1;
0991: return this ;
0992: }
0993: for (int i = 0; i < lhs.length && comparison == 0; i++) {
0994: append(lhs[i], rhs[i]);
0995: }
0996: return this ;
0997: }
0998:
0999: /**
1000: * <p>Appends to the <code>builder</code> the deep comparison of
1001: * two <code>boolean</code> arrays.</p>
1002: *
1003: * <ol>
1004: * <li>Check if arrays are the same using <code>==</code></li>
1005: * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
1006: * <li>Check array length, a shorter length array is less than a longer length array</li>
1007: * <li>Check array contents element by element using {@link #append(boolean, boolean)}</li>
1008: * </ol>
1009: *
1010: * @param lhs left-hand array
1011: * @param rhs right-hand array
1012: * @return this - used to chain append calls
1013: */
1014: public CompareToBuilder append(boolean[] lhs, boolean[] rhs) {
1015: if (comparison != 0) {
1016: return this ;
1017: }
1018: if (lhs == rhs) {
1019: return this ;
1020: }
1021: if (lhs == null) {
1022: comparison = -1;
1023: return this ;
1024: }
1025: if (rhs == null) {
1026: comparison = +1;
1027: return this ;
1028: }
1029: if (lhs.length != rhs.length) {
1030: comparison = (lhs.length < rhs.length) ? -1 : +1;
1031: return this ;
1032: }
1033: for (int i = 0; i < lhs.length && comparison == 0; i++) {
1034: append(lhs[i], rhs[i]);
1035: }
1036: return this ;
1037: }
1038:
1039: //-----------------------------------------------------------------------
1040: /**
1041: * Returns a negative integer, a positive integer, or zero as
1042: * the <code>builder</code> has judged the "left-hand" side
1043: * as less than, greater than, or equal to the "right-hand"
1044: * side.
1045: *
1046: * @return final comparison result
1047: */
1048: public int toComparison() {
1049: return comparison;
1050: }
1051:
1052: }
|