001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3.builder;
018
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.List;
022
023import org.apache.commons.lang3.ArrayUtils;
024
025/**
026 * <p>
027 * Assists in implementing {@link Diffable#diff(Object)} methods.
028 * </p>
029 * 
030 * <p>
031 * To use this class, write code as follows:
032 * </p>
033 * 
034 * <pre>
035 * public class Person implements Diffable&lt;Person&gt; {
036 *   String name;
037 *   int age;
038 *   boolean smoker;
039 *   
040 *   ...
041 *   
042 *   public DiffResult diff(Person obj) {
043 *     // No need for null check, as NullPointerException correct if obj is null
044 *     return new DiffBuilder(this, obj, ToStringStyle.SHORT_PREFIX_STYLE)
045 *       .append("name", this.name, obj.name)
046 *       .append("age", this.age, obj.age)
047 *       .append("smoker", this.smoker, obj.smoker)
048 *       .build();
049 *   }
050 * }
051 * </pre>
052 * 
053 * <p>
054 * The {@code ToStringStyle} passed to the constructor is embedded in the
055 * returned {@code DiffResult} and influences the style of the
056 * {@code DiffResult.toString()} method. This style choice can be overridden by
057 * calling {@link DiffResult#toString(ToStringStyle)}.
058 * </p>
059 * 
060 * @since 3.3
061 * @version $Id: DiffBuilder.java 1669782 2015-03-28 15:05:04Z britter $
062 * @see Diffable
063 * @see Diff
064 * @see DiffResult
065 * @see ToStringStyle
066 */
067public class DiffBuilder implements Builder<DiffResult> {
068
069    private final List<Diff<?>> diffs;
070    private final boolean objectsTriviallyEqual;
071    private final Object left;
072    private final Object right;
073    private final ToStringStyle style;
074
075    /**
076     * <p>
077     * Constructs a builder for the specified objects with the specified style.
078     * </p>
079     * 
080     * <p>
081     * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will
082     * not evaluate any calls to {@code append(...)} and will return an empty
083     * {@link DiffResult} when {@link #build()} is executed.
084     * </p>
085     * 
086     * @param lhs
087     *            {@code this} object
088     * @param rhs
089     *            the object to diff against
090     * @param style
091     *            the style will use when outputting the objects, {@code null}
092     *            uses the default
093     * @param testTriviallyEqual
094     *            If true, this will test if lhs and rhs are the same or equal.
095     *            All of the append(fieldName, lhs, rhs) methods will abort
096     *            without creating a field {@link Diff} if the trivially equal
097     *            test is enabled and returns true.  The result of this test
098     *            is never changed throughout the life of this {@link DiffBuilder}.
099     * @throws IllegalArgumentException
100     *             if {@code lhs} or {@code rhs} is {@code null}
101     * @since 3.4
102     */
103    public DiffBuilder(final Object lhs, final Object rhs,
104            final ToStringStyle style, final boolean testTriviallyEqual) {
105
106        if (lhs == null) {
107            throw new IllegalArgumentException("lhs cannot be null");
108        }
109        if (rhs == null) {
110            throw new IllegalArgumentException("rhs cannot be null");
111        }
112
113        this.diffs = new ArrayList<Diff<?>>();
114        this.left = lhs;
115        this.right = rhs;
116        this.style = style;
117
118        // Don't compare any fields if objects equal
119        this.objectsTriviallyEqual = testTriviallyEqual && (lhs == rhs || lhs.equals(rhs));
120    }
121
122    /**
123     * <p>
124     * Constructs a builder for the specified objects with the specified style.
125     * </p>
126     * 
127     * <p>
128     * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will
129     * not evaluate any calls to {@code append(...)} and will return an empty
130     * {@link DiffResult} when {@link #build()} is executed.
131     * </p>
132     * 
133     * <p>
134     * This delegates to {@link #DiffBuilder(Object, Object, ToStringStyle, boolean)}
135     * with the testTriviallyEqual flag enabled.
136     * </p>
137     *
138     * @param lhs
139     *            {@code this} object
140     * @param rhs
141     *            the object to diff against
142     * @param style
143     *            the style will use when outputting the objects, {@code null}
144     *            uses the default
145     * @throws IllegalArgumentException
146     *             if {@code lhs} or {@code rhs} is {@code null}
147     */
148    public DiffBuilder(final Object lhs, final Object rhs,
149            final ToStringStyle style) {
150
151            this(lhs, rhs, style, true);
152    }
153
154    /**
155     * <p>
156     * Test if two {@code boolean}s are equal.
157     * </p>
158     * 
159     * @param fieldName
160     *            the field name
161     * @param lhs
162     *            the left hand {@code boolean}
163     * @param rhs
164     *            the right hand {@code boolean}
165     * @return this
166     * @throws IllegalArgumentException
167     *             if field name is {@code null}
168     */
169    public DiffBuilder append(final String fieldName, final boolean lhs,
170            final boolean rhs) {
171        if (fieldName == null) {
172            throw new IllegalArgumentException("Field name cannot be null");
173        }
174
175        if (objectsTriviallyEqual) {
176            return this;
177        }
178        if (lhs != rhs) {
179            diffs.add(new Diff<Boolean>(fieldName) {
180                private static final long serialVersionUID = 1L;
181
182                @Override
183                public Boolean getLeft() {
184                    return Boolean.valueOf(lhs);
185                }
186
187                @Override
188                public Boolean getRight() {
189                    return Boolean.valueOf(rhs);
190                }
191            });
192        }
193        return this;
194    }
195
196    /**
197     * <p>
198     * Test if two {@code boolean[]}s are equal.
199     * </p>
200     * 
201     * @param fieldName
202     *            the field name
203     * @param lhs
204     *            the left hand {@code boolean[]}
205     * @param rhs
206     *            the right hand {@code boolean[]}
207     * @return this
208     * @throws IllegalArgumentException
209     *             if field name is {@code null}
210     */
211    public DiffBuilder append(final String fieldName, final boolean[] lhs,
212            final boolean[] rhs) {
213        if (fieldName == null) {
214            throw new IllegalArgumentException("Field name cannot be null");
215        }
216        if (objectsTriviallyEqual) {
217            return this;
218        }
219        if (!Arrays.equals(lhs, rhs)) {
220            diffs.add(new Diff<Boolean[]>(fieldName) {
221                private static final long serialVersionUID = 1L;
222
223                @Override
224                public Boolean[] getLeft() {
225                    return ArrayUtils.toObject(lhs);
226                }
227
228                @Override
229                public Boolean[] getRight() {
230                    return ArrayUtils.toObject(rhs);
231                }
232            });
233        }
234        return this;
235    }
236
237    /**
238     * <p>
239     * Test if two {@code byte}s are equal.
240     * </p>
241     * 
242     * @param fieldName
243     *            the field name
244     * @param lhs
245     *            the left hand {@code byte}
246     * @param rhs
247     *            the right hand {@code byte}
248     * @return this
249     * @throws IllegalArgumentException
250     *             if field name is {@code null}
251     */
252    public DiffBuilder append(final String fieldName, final byte lhs,
253            final byte rhs) {
254        if (fieldName == null) {
255            throw new IllegalArgumentException("Field name cannot be null");
256        }
257        if (objectsTriviallyEqual) {
258            return this;
259        }
260        if (lhs != rhs) {
261            diffs.add(new Diff<Byte>(fieldName) {
262                private static final long serialVersionUID = 1L;
263
264                @Override
265                public Byte getLeft() {
266                    return Byte.valueOf(lhs);
267                }
268
269                @Override
270                public Byte getRight() {
271                    return Byte.valueOf(rhs);
272                }
273            });
274        }
275        return this;
276    }
277
278    /**
279     * <p>
280     * Test if two {@code byte[]}s are equal.
281     * </p>
282     * 
283     * @param fieldName
284     *            the field name
285     * @param lhs
286     *            the left hand {@code byte[]}
287     * @param rhs
288     *            the right hand {@code byte[]}
289     * @return this
290     * @throws IllegalArgumentException
291     *             if field name is {@code null}
292     */
293    public DiffBuilder append(final String fieldName, final byte[] lhs,
294            final byte[] rhs) {
295        if (fieldName == null) {
296            throw new IllegalArgumentException("Field name cannot be null");
297        }
298
299        if (objectsTriviallyEqual) {
300            return this;
301        }
302        if (!Arrays.equals(lhs, rhs)) {
303            diffs.add(new Diff<Byte[]>(fieldName) {
304                private static final long serialVersionUID = 1L;
305
306                @Override
307                public Byte[] getLeft() {
308                    return ArrayUtils.toObject(lhs);
309                }
310
311                @Override
312                public Byte[] getRight() {
313                    return ArrayUtils.toObject(rhs);
314                }
315            });
316        }
317        return this;
318    }
319
320    /**
321     * <p>
322     * Test if two {@code char}s are equal.
323     * </p>
324     * 
325     * @param fieldName
326     *            the field name
327     * @param lhs
328     *            the left hand {@code char}
329     * @param rhs
330     *            the right hand {@code char}
331     * @return this
332     * @throws IllegalArgumentException
333     *             if field name is {@code null}
334     */
335    public DiffBuilder append(final String fieldName, final char lhs,
336            final char rhs) {
337        if (fieldName == null) {
338            throw new IllegalArgumentException("Field name cannot be null");
339        }
340
341        if (objectsTriviallyEqual) {
342            return this;
343        }
344        if (lhs != rhs) {
345            diffs.add(new Diff<Character>(fieldName) {
346                private static final long serialVersionUID = 1L;
347
348                @Override
349                public Character getLeft() {
350                    return Character.valueOf(lhs);
351                }
352
353                @Override
354                public Character getRight() {
355                    return Character.valueOf(rhs);
356                }
357            });
358        }
359        return this;
360    }
361
362    /**
363     * <p>
364     * Test if two {@code char[]}s are equal.
365     * </p>
366     * 
367     * @param fieldName
368     *            the field name
369     * @param lhs
370     *            the left hand {@code char[]}
371     * @param rhs
372     *            the right hand {@code char[]}
373     * @return this
374     * @throws IllegalArgumentException
375     *             if field name is {@code null}
376     */
377    public DiffBuilder append(final String fieldName, final char[] lhs,
378            final char[] rhs) {
379        if (fieldName == null) {
380            throw new IllegalArgumentException("Field name cannot be null");
381        }
382
383        if (objectsTriviallyEqual) {
384            return this;
385        }
386        if (!Arrays.equals(lhs, rhs)) {
387            diffs.add(new Diff<Character[]>(fieldName) {
388                private static final long serialVersionUID = 1L;
389
390                @Override
391                public Character[] getLeft() {
392                    return ArrayUtils.toObject(lhs);
393                }
394
395                @Override
396                public Character[] getRight() {
397                    return ArrayUtils.toObject(rhs);
398                }
399            });
400        }
401        return this;
402    }
403
404    /**
405     * <p>
406     * Test if two {@code double}s are equal.
407     * </p>
408     * 
409     * @param fieldName
410     *            the field name
411     * @param lhs
412     *            the left hand {@code double}
413     * @param rhs
414     *            the right hand {@code double}
415     * @return this
416     * @throws IllegalArgumentException
417     *             if field name is {@code null}
418     */
419    public DiffBuilder append(final String fieldName, final double lhs,
420            final double rhs) {
421        if (fieldName == null) {
422            throw new IllegalArgumentException("Field name cannot be null");
423        }
424
425        if (objectsTriviallyEqual) {
426            return this;
427        }
428        if (Double.doubleToLongBits(lhs) != Double.doubleToLongBits(rhs)) {
429            diffs.add(new Diff<Double>(fieldName) {
430                private static final long serialVersionUID = 1L;
431
432                @Override
433                public Double getLeft() {
434                    return Double.valueOf(lhs);
435                }
436
437                @Override
438                public Double getRight() {
439                    return Double.valueOf(rhs);
440                }
441            });
442        }
443        return this;
444    }
445
446    /**
447     * <p>
448     * Test if two {@code double[]}s are equal.
449     * </p>
450     * 
451     * @param fieldName
452     *            the field name
453     * @param lhs
454     *            the left hand {@code double[]}
455     * @param rhs
456     *            the right hand {@code double[]}
457     * @return this
458     * @throws IllegalArgumentException
459     *             if field name is {@code null}
460     */
461    public DiffBuilder append(final String fieldName, final double[] lhs,
462            final double[] rhs) {
463        if (fieldName == null) {
464            throw new IllegalArgumentException("Field name cannot be null");
465        }
466
467        if (objectsTriviallyEqual) {
468            return this;
469        }
470        if (!Arrays.equals(lhs, rhs)) {
471            diffs.add(new Diff<Double[]>(fieldName) {
472                private static final long serialVersionUID = 1L;
473
474                @Override
475                public Double[] getLeft() {
476                    return ArrayUtils.toObject(lhs);
477                }
478
479                @Override
480                public Double[] getRight() {
481                    return ArrayUtils.toObject(rhs);
482                }
483            });
484        }
485        return this;
486    }
487
488    /**
489     * <p>
490     * Test if two {@code float}s are equal.
491     * </p>
492     * 
493     * @param fieldName
494     *            the field name
495     * @param lhs
496     *            the left hand {@code float}
497     * @param rhs
498     *            the right hand {@code float}
499     * @return this
500     * @throws IllegalArgumentException
501     *             if field name is {@code null}
502     */
503    public DiffBuilder append(final String fieldName, final float lhs,
504            final float rhs) {
505        if (fieldName == null) {
506            throw new IllegalArgumentException("Field name cannot be null");
507        }
508
509        if (objectsTriviallyEqual) {
510            return this;
511        }
512        if (Float.floatToIntBits(lhs) != Float.floatToIntBits(rhs)) {
513            diffs.add(new Diff<Float>(fieldName) {
514                private static final long serialVersionUID = 1L;
515
516                @Override
517                public Float getLeft() {
518                    return Float.valueOf(lhs);
519                }
520
521                @Override
522                public Float getRight() {
523                    return Float.valueOf(rhs);
524                }
525            });
526        }
527        return this;
528    }
529
530    /**
531     * <p>
532     * Test if two {@code float[]}s are equal.
533     * </p>
534     * 
535     * @param fieldName
536     *            the field name
537     * @param lhs
538     *            the left hand {@code float[]}
539     * @param rhs
540     *            the right hand {@code float[]}
541     * @return this
542     * @throws IllegalArgumentException
543     *             if field name is {@code null}
544     */
545    public DiffBuilder append(final String fieldName, final float[] lhs,
546            final float[] rhs) {
547        if (fieldName == null) {
548            throw new IllegalArgumentException("Field name cannot be null");
549        }
550
551        if (objectsTriviallyEqual) {
552            return this;
553        }
554        if (!Arrays.equals(lhs, rhs)) {
555            diffs.add(new Diff<Float[]>(fieldName) {
556                private static final long serialVersionUID = 1L;
557
558                @Override
559                public Float[] getLeft() {
560                    return ArrayUtils.toObject(lhs);
561                }
562
563                @Override
564                public Float[] getRight() {
565                    return ArrayUtils.toObject(rhs);
566                }
567            });
568        }
569        return this;
570    }
571
572    /**
573     * <p>
574     * Test if two {@code int}s are equal.
575     * </p>
576     * 
577     * @param fieldName
578     *            the field name
579     * @param lhs
580     *            the left hand {@code int}
581     * @param rhs
582     *            the right hand {@code int}
583     * @return this
584     * @throws IllegalArgumentException
585     *             if field name is {@code null}
586     */
587    public DiffBuilder append(final String fieldName, final int lhs,
588            final int rhs) {
589        if (fieldName == null) {
590            throw new IllegalArgumentException("Field name cannot be null");
591        }
592
593        if (objectsTriviallyEqual) {
594            return this;
595        }
596        if (lhs != rhs) {
597            diffs.add(new Diff<Integer>(fieldName) {
598                private static final long serialVersionUID = 1L;
599
600                @Override
601                public Integer getLeft() {
602                    return Integer.valueOf(lhs);
603                }
604
605                @Override
606                public Integer getRight() {
607                    return Integer.valueOf(rhs);
608                }
609            });
610        }
611        return this;
612    }
613
614    /**
615     * <p>
616     * Test if two {@code int[]}s are equal.
617     * </p>
618     * 
619     * @param fieldName
620     *            the field name
621     * @param lhs
622     *            the left hand {@code int[]}
623     * @param rhs
624     *            the right hand {@code int[]}
625     * @return this
626     * @throws IllegalArgumentException
627     *             if field name is {@code null}
628     */
629    public DiffBuilder append(final String fieldName, final int[] lhs,
630            final int[] rhs) {
631        if (fieldName == null) {
632            throw new IllegalArgumentException("Field name cannot be null");
633        }
634
635        if (objectsTriviallyEqual) {
636            return this;
637        }
638        if (!Arrays.equals(lhs, rhs)) {
639            diffs.add(new Diff<Integer[]>(fieldName) {
640                private static final long serialVersionUID = 1L;
641
642                @Override
643                public Integer[] getLeft() {
644                    return ArrayUtils.toObject(lhs);
645                }
646
647                @Override
648                public Integer[] getRight() {
649                    return ArrayUtils.toObject(rhs);
650                }
651            });
652        }
653        return this;
654    }
655
656    /**
657     * <p>
658     * Test if two {@code long}s are equal.
659     * </p>
660     * 
661     * @param fieldName
662     *            the field name
663     * @param lhs
664     *            the left hand {@code long}
665     * @param rhs
666     *            the right hand {@code long}
667     * @return this
668     * @throws IllegalArgumentException
669     *             if field name is {@code null}
670     */
671    public DiffBuilder append(final String fieldName, final long lhs,
672            final long rhs) {
673        if (fieldName == null) {
674            throw new IllegalArgumentException("Field name cannot be null");
675        }
676
677        if (objectsTriviallyEqual) {
678            return this;
679        }
680        if (lhs != rhs) {
681            diffs.add(new Diff<Long>(fieldName) {
682                private static final long serialVersionUID = 1L;
683
684                @Override
685                public Long getLeft() {
686                    return Long.valueOf(lhs);
687                }
688
689                @Override
690                public Long getRight() {
691                    return Long.valueOf(rhs);
692                }
693            });
694        }
695        return this;
696    }
697
698    /**
699     * <p>
700     * Test if two {@code long[]}s are equal.
701     * </p>
702     * 
703     * @param fieldName
704     *            the field name
705     * @param lhs
706     *            the left hand {@code long[]}
707     * @param rhs
708     *            the right hand {@code long[]}
709     * @return this
710     * @throws IllegalArgumentException
711     *             if field name is {@code null}
712     */
713    public DiffBuilder append(final String fieldName, final long[] lhs,
714            final long[] rhs) {
715        if (fieldName == null) {
716            throw new IllegalArgumentException("Field name cannot be null");
717        }
718
719        if (objectsTriviallyEqual) {
720            return this;
721        }
722        if (!Arrays.equals(lhs, rhs)) {
723            diffs.add(new Diff<Long[]>(fieldName) {
724                private static final long serialVersionUID = 1L;
725
726                @Override
727                public Long[] getLeft() {
728                    return ArrayUtils.toObject(lhs);
729                }
730
731                @Override
732                public Long[] getRight() {
733                    return ArrayUtils.toObject(rhs);
734                }
735            });
736        }
737        return this;
738    }
739
740    /**
741     * <p>
742     * Test if two {@code short}s are equal.
743     * </p>
744     * 
745     * @param fieldName
746     *            the field name
747     * @param lhs
748     *            the left hand {@code short}
749     * @param rhs
750     *            the right hand {@code short}
751     * @return this
752     * @throws IllegalArgumentException
753     *             if field name is {@code null}
754     */
755    public DiffBuilder append(final String fieldName, final short lhs,
756            final short rhs) {
757        if (fieldName == null) {
758            throw new IllegalArgumentException("Field name cannot be null");
759        }
760
761        if (objectsTriviallyEqual) {
762            return this;
763        }
764        if (lhs != rhs) {
765            diffs.add(new Diff<Short>(fieldName) {
766                private static final long serialVersionUID = 1L;
767
768                @Override
769                public Short getLeft() {
770                    return Short.valueOf(lhs);
771                }
772
773                @Override
774                public Short getRight() {
775                    return Short.valueOf(rhs);
776                }
777            });
778        }
779        return this;
780    }
781
782    /**
783     * <p>
784     * Test if two {@code short[]}s are equal.
785     * </p>
786     * 
787     * @param fieldName
788     *            the field name
789     * @param lhs
790     *            the left hand {@code short[]}
791     * @param rhs
792     *            the right hand {@code short[]}
793     * @return this
794     * @throws IllegalArgumentException
795     *             if field name is {@code null}
796     */
797    public DiffBuilder append(final String fieldName, final short[] lhs,
798            final short[] rhs) {
799        if (fieldName == null) {
800            throw new IllegalArgumentException("Field name cannot be null");
801        }
802
803        if (objectsTriviallyEqual) {
804            return this;
805        }
806        if (!Arrays.equals(lhs, rhs)) {
807            diffs.add(new Diff<Short[]>(fieldName) {
808                private static final long serialVersionUID = 1L;
809
810                @Override
811                public Short[] getLeft() {
812                    return ArrayUtils.toObject(lhs);
813                }
814
815                @Override
816                public Short[] getRight() {
817                    return ArrayUtils.toObject(rhs);
818                }
819            });
820        }
821        return this;
822    }
823
824    /**
825     * <p>
826     * Test if two {@code Objects}s are equal.
827     * </p>
828     * 
829     * @param fieldName
830     *            the field name
831     * @param lhs
832     *            the left hand {@code Object}
833     * @param rhs
834     *            the right hand {@code Object}
835     * @return this
836     */
837    public DiffBuilder append(final String fieldName, final Object lhs,
838            final Object rhs) {
839
840        if (objectsTriviallyEqual) {
841            return this;
842        }
843        if (lhs == rhs) {
844            return this;
845        }
846
847        Object objectToTest;
848        if (lhs != null) {
849            objectToTest = lhs;
850        } else {
851            // rhs cannot be null, as lhs != rhs
852            objectToTest = rhs;
853        }
854
855        if (objectToTest.getClass().isArray()) {
856            if (objectToTest instanceof boolean[]) {
857                return append(fieldName, (boolean[]) lhs, (boolean[]) rhs);
858            }
859            if (objectToTest instanceof byte[]) {
860                return append(fieldName, (byte[]) lhs, (byte[]) rhs);
861            }
862            if (objectToTest instanceof char[]) {
863                return append(fieldName, (char[]) lhs, (char[]) rhs);
864            }
865            if (objectToTest instanceof double[]) {
866                return append(fieldName, (double[]) lhs, (double[]) rhs);
867            }
868            if (objectToTest instanceof float[]) {
869                return append(fieldName, (float[]) lhs, (float[]) rhs);
870            }
871            if (objectToTest instanceof int[]) {
872                return append(fieldName, (int[]) lhs, (int[]) rhs);
873            }
874            if (objectToTest instanceof long[]) {
875                return append(fieldName, (long[]) lhs, (long[]) rhs);
876            }
877            if (objectToTest instanceof short[]) {
878                return append(fieldName, (short[]) lhs, (short[]) rhs);
879            }
880
881            return append(fieldName, (Object[]) lhs, (Object[]) rhs);
882        }
883
884        // Not array type
885        if (lhs != null && lhs.equals(rhs)) {
886            return this;
887        }
888
889        diffs.add(new Diff<Object>(fieldName) {
890            private static final long serialVersionUID = 1L;
891
892            @Override
893            public Object getLeft() {
894                return lhs;
895            }
896
897            @Override
898            public Object getRight() {
899                return rhs;
900            }
901        });
902
903        return this;
904    }
905
906    /**
907     * <p>
908     * Test if two {@code Object[]}s are equal.
909     * </p>
910     * 
911     * @param fieldName
912     *            the field name
913     * @param lhs
914     *            the left hand {@code Object[]}
915     * @param rhs
916     *            the right hand {@code Object[]}
917     * @return this
918     */
919    public DiffBuilder append(final String fieldName, final Object[] lhs,
920            final Object[] rhs) {
921        if (objectsTriviallyEqual) {
922            return this;
923        }
924
925        if (!Arrays.equals(lhs, rhs)) {
926            diffs.add(new Diff<Object[]>(fieldName) {
927                private static final long serialVersionUID = 1L;
928
929                @Override
930                public Object[] getLeft() {
931                    return lhs;
932                }
933
934                @Override
935                public Object[] getRight() {
936                    return rhs;
937                }
938            });
939        }
940
941        return this;
942    }
943
944    /**
945     * <p>
946     * Builds a {@link DiffResult} based on the differences appended to this
947     * builder.
948     * </p>
949     * 
950     * @return a {@code DiffResult} containing the differences between the two
951     *         objects.
952     */
953    @Override
954    public DiffResult build() {
955        return new DiffResult(left, right, diffs, style);
956    }
957
958}