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