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; 022import java.util.Objects; 023 024import org.apache.commons.lang3.ArrayUtils; 025import org.apache.commons.lang3.ObjectUtils; 026 027/** 028 * Assists in implementing {@link Diffable#diff(Object)} methods. 029 * 030 * <p> 031 * To use this class, write code as follows: 032 * </p> 033 * 034 * <pre> 035 * public class Person implements Diffable<Person> { 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 {@link ToStringStyle} passed to the constructor is embedded in the 055 * returned {@link 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 * <p> 060 * See {@link ReflectionDiffBuilder} for a reflection based version of this class. 061 * </p> 062 * 063 * @param <T> type of the left and right object. 064 * @see Diffable 065 * @see Diff 066 * @see DiffResult 067 * @see ToStringStyle 068 * @see ReflectionDiffBuilder 069 * @since 3.3 070 */ 071public class DiffBuilder<T> implements Builder<DiffResult<T>> { 072 073 private final List<Diff<?>> diffs; 074 private final boolean objectsTriviallyEqual; 075 private final T left; 076 private final T right; 077 private final ToStringStyle style; 078 079 /** 080 * Constructs a builder for the specified objects with the specified style. 081 * 082 * <p> 083 * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will 084 * not evaluate any calls to {@code append(...)} and will return an empty 085 * {@link DiffResult} when {@link #build()} is executed. 086 * </p> 087 * 088 * @param lhs 089 * {@code this} object 090 * @param rhs 091 * the object to diff against 092 * @param style 093 * the style will use when outputting the objects, {@code null} 094 * uses the default 095 * @param testTriviallyEqual 096 * If true, this will test if lhs and rhs are the same or equal. 097 * All of the append(fieldName, lhs, rhs) methods will abort 098 * without creating a field {@link Diff} if the trivially equal 099 * test is enabled and returns true. The result of this test 100 * is never changed throughout the life of this {@link DiffBuilder}. 101 * @throws NullPointerException 102 * if {@code lhs} or {@code rhs} is {@code null} 103 * @since 3.4 104 */ 105 public DiffBuilder(final T lhs, final T rhs, 106 final ToStringStyle style, final boolean testTriviallyEqual) { 107 108 Objects.requireNonNull(lhs, "lhs"); 109 Objects.requireNonNull(rhs, "rhs"); 110 111 this.diffs = new ArrayList<>(); 112 this.left = lhs; 113 this.right = rhs; 114 this.style = style; 115 116 // Don't compare any fields if objects equal 117 this.objectsTriviallyEqual = testTriviallyEqual && Objects.equals(lhs, rhs); 118 } 119 120 /** 121 * Constructs a builder for the specified objects with the specified style. 122 * 123 * <p> 124 * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will 125 * not evaluate any calls to {@code append(...)} and will return an empty 126 * {@link DiffResult} when {@link #build()} is executed. 127 * </p> 128 * 129 * <p> 130 * This delegates to {@link #DiffBuilder(Object, Object, ToStringStyle, boolean)} 131 * with the testTriviallyEqual flag enabled. 132 * </p> 133 * 134 * @param lhs 135 * {@code this} object 136 * @param rhs 137 * the object to diff against 138 * @param style 139 * the style will use when outputting the objects, {@code null} 140 * uses the default 141 * @throws NullPointerException 142 * if {@code lhs} or {@code rhs} is {@code null} 143 */ 144 public DiffBuilder(final T lhs, final T rhs, 145 final ToStringStyle style) { 146 147 this(lhs, rhs, style, true); 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 * Test if two {@code double}s are equal. 378 * 379 * @param fieldName 380 * the field name 381 * @param lhs 382 * the left-hand {@code double} 383 * @param rhs 384 * the right-hand {@code double} 385 * @return this 386 * @throws NullPointerException 387 * if field name is {@code null} 388 */ 389 public DiffBuilder<T> append(final String fieldName, final double lhs, 390 final double rhs) { 391 validateFieldNameNotNull(fieldName); 392 393 if (objectsTriviallyEqual) { 394 return this; 395 } 396 if (Double.doubleToLongBits(lhs) != Double.doubleToLongBits(rhs)) { 397 diffs.add(new Diff<Double>(fieldName) { 398 private static final long serialVersionUID = 1L; 399 400 @Override 401 public Double getLeft() { 402 return Double.valueOf(lhs); 403 } 404 405 @Override 406 public Double getRight() { 407 return Double.valueOf(rhs); 408 } 409 }); 410 } 411 return this; 412 } 413 414 /** 415 * Test if two {@code double[]}s are equal. 416 * 417 * @param fieldName 418 * the field name 419 * @param lhs 420 * the left-hand {@code double[]} 421 * @param rhs 422 * the right-hand {@code double[]} 423 * @return this 424 * @throws NullPointerException 425 * if field name is {@code null} 426 */ 427 public DiffBuilder<T> append(final String fieldName, final double[] lhs, 428 final double[] rhs) { 429 validateFieldNameNotNull(fieldName); 430 431 if (objectsTriviallyEqual) { 432 return this; 433 } 434 if (!Arrays.equals(lhs, rhs)) { 435 diffs.add(new Diff<Double[]>(fieldName) { 436 private static final long serialVersionUID = 1L; 437 438 @Override 439 public Double[] getLeft() { 440 return ArrayUtils.toObject(lhs); 441 } 442 443 @Override 444 public Double[] getRight() { 445 return ArrayUtils.toObject(rhs); 446 } 447 }); 448 } 449 return this; 450 } 451 452 /** 453 * Test if two {@code float}s are equal. 454 * 455 * @param fieldName 456 * the field name 457 * @param lhs 458 * the left-hand {@code float} 459 * @param rhs 460 * the right-hand {@code float} 461 * @return this 462 * @throws NullPointerException 463 * if field name is {@code null} 464 */ 465 public DiffBuilder<T> append(final String fieldName, final float lhs, 466 final float rhs) { 467 validateFieldNameNotNull(fieldName); 468 469 if (objectsTriviallyEqual) { 470 return this; 471 } 472 if (Float.floatToIntBits(lhs) != Float.floatToIntBits(rhs)) { 473 diffs.add(new Diff<Float>(fieldName) { 474 private static final long serialVersionUID = 1L; 475 476 @Override 477 public Float getLeft() { 478 return Float.valueOf(lhs); 479 } 480 481 @Override 482 public Float getRight() { 483 return Float.valueOf(rhs); 484 } 485 }); 486 } 487 return this; 488 } 489 490 /** 491 * Test if two {@code float[]}s are equal. 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 NullPointerException 501 * if field name is {@code null} 502 */ 503 public DiffBuilder<T> append(final String fieldName, final float[] lhs, 504 final float[] rhs) { 505 validateFieldNameNotNull(fieldName); 506 507 if (objectsTriviallyEqual) { 508 return this; 509 } 510 if (!Arrays.equals(lhs, rhs)) { 511 diffs.add(new Diff<Float[]>(fieldName) { 512 private static final long serialVersionUID = 1L; 513 514 @Override 515 public Float[] getLeft() { 516 return ArrayUtils.toObject(lhs); 517 } 518 519 @Override 520 public Float[] getRight() { 521 return ArrayUtils.toObject(rhs); 522 } 523 }); 524 } 525 return this; 526 } 527 528 /** 529 * Test if two {@code int}s are equal. 530 * 531 * @param fieldName 532 * the field name 533 * @param lhs 534 * the left-hand {@code int} 535 * @param rhs 536 * the right-hand {@code int} 537 * @return this 538 * @throws NullPointerException 539 * if field name is {@code null} 540 */ 541 public DiffBuilder<T> append(final String fieldName, final int lhs, 542 final int rhs) { 543 validateFieldNameNotNull(fieldName); 544 545 if (objectsTriviallyEqual) { 546 return this; 547 } 548 if (lhs != rhs) { 549 diffs.add(new Diff<Integer>(fieldName) { 550 private static final long serialVersionUID = 1L; 551 552 @Override 553 public Integer getLeft() { 554 return Integer.valueOf(lhs); 555 } 556 557 @Override 558 public Integer getRight() { 559 return Integer.valueOf(rhs); 560 } 561 }); 562 } 563 return this; 564 } 565 566 /** 567 * Test if two {@code int[]}s are equal. 568 * 569 * @param fieldName 570 * the field name 571 * @param lhs 572 * the left-hand {@code int[]} 573 * @param rhs 574 * the right-hand {@code int[]} 575 * @return this 576 * @throws NullPointerException 577 * if field name is {@code null} 578 */ 579 public DiffBuilder<T> append(final String fieldName, final int[] lhs, 580 final int[] rhs) { 581 validateFieldNameNotNull(fieldName); 582 583 if (objectsTriviallyEqual) { 584 return this; 585 } 586 if (!Arrays.equals(lhs, rhs)) { 587 diffs.add(new Diff<Integer[]>(fieldName) { 588 private static final long serialVersionUID = 1L; 589 590 @Override 591 public Integer[] getLeft() { 592 return ArrayUtils.toObject(lhs); 593 } 594 595 @Override 596 public Integer[] getRight() { 597 return ArrayUtils.toObject(rhs); 598 } 599 }); 600 } 601 return this; 602 } 603 604 /** 605 * Test if two {@code long}s are equal. 606 * 607 * @param fieldName 608 * the field name 609 * @param lhs 610 * the left-hand {@code long} 611 * @param rhs 612 * the right-hand {@code long} 613 * @return this 614 * @throws NullPointerException 615 * if field name is {@code null} 616 */ 617 public DiffBuilder<T> append(final String fieldName, final long lhs, 618 final long rhs) { 619 validateFieldNameNotNull(fieldName); 620 621 if (objectsTriviallyEqual) { 622 return this; 623 } 624 if (lhs != rhs) { 625 diffs.add(new Diff<Long>(fieldName) { 626 private static final long serialVersionUID = 1L; 627 628 @Override 629 public Long getLeft() { 630 return Long.valueOf(lhs); 631 } 632 633 @Override 634 public Long getRight() { 635 return Long.valueOf(rhs); 636 } 637 }); 638 } 639 return this; 640 } 641 642 /** 643 * Test if two {@code long[]}s are equal. 644 * 645 * @param fieldName 646 * the field name 647 * @param lhs 648 * the left-hand {@code long[]} 649 * @param rhs 650 * the right-hand {@code long[]} 651 * @return this 652 * @throws NullPointerException 653 * if field name is {@code null} 654 */ 655 public DiffBuilder<T> append(final String fieldName, final long[] lhs, 656 final long[] rhs) { 657 validateFieldNameNotNull(fieldName); 658 659 if (objectsTriviallyEqual) { 660 return this; 661 } 662 if (!Arrays.equals(lhs, rhs)) { 663 diffs.add(new Diff<Long[]>(fieldName) { 664 private static final long serialVersionUID = 1L; 665 666 @Override 667 public Long[] getLeft() { 668 return ArrayUtils.toObject(lhs); 669 } 670 671 @Override 672 public Long[] getRight() { 673 return ArrayUtils.toObject(rhs); 674 } 675 }); 676 } 677 return this; 678 } 679 680 /** 681 * Test if two {@code short}s are equal. 682 * 683 * @param fieldName 684 * the field name 685 * @param lhs 686 * the left-hand {@code short} 687 * @param rhs 688 * the right-hand {@code short} 689 * @return this 690 * @throws NullPointerException 691 * if field name is {@code null} 692 */ 693 public DiffBuilder<T> append(final String fieldName, final short lhs, 694 final short rhs) { 695 validateFieldNameNotNull(fieldName); 696 697 if (objectsTriviallyEqual) { 698 return this; 699 } 700 if (lhs != rhs) { 701 diffs.add(new Diff<Short>(fieldName) { 702 private static final long serialVersionUID = 1L; 703 704 @Override 705 public Short getLeft() { 706 return Short.valueOf(lhs); 707 } 708 709 @Override 710 public Short getRight() { 711 return Short.valueOf(rhs); 712 } 713 }); 714 } 715 return this; 716 } 717 718 /** 719 * Test if two {@code short[]}s are equal. 720 * 721 * @param fieldName 722 * the field name 723 * @param lhs 724 * the left-hand {@code short[]} 725 * @param rhs 726 * the right-hand {@code short[]} 727 * @return this 728 * @throws NullPointerException 729 * if field name is {@code null} 730 */ 731 public DiffBuilder<T> append(final String fieldName, final short[] lhs, 732 final short[] rhs) { 733 validateFieldNameNotNull(fieldName); 734 735 if (objectsTriviallyEqual) { 736 return this; 737 } 738 if (!Arrays.equals(lhs, rhs)) { 739 diffs.add(new Diff<Short[]>(fieldName) { 740 private static final long serialVersionUID = 1L; 741 742 @Override 743 public Short[] getLeft() { 744 return ArrayUtils.toObject(lhs); 745 } 746 747 @Override 748 public Short[] getRight() { 749 return ArrayUtils.toObject(rhs); 750 } 751 }); 752 } 753 return this; 754 } 755 756 /** 757 * Test if two {@link Objects}s are equal. 758 * 759 * @param fieldName 760 * the field name 761 * @param lhs 762 * the left-hand {@link Object} 763 * @param rhs 764 * the right-hand {@link Object} 765 * @return this 766 * @throws NullPointerException 767 * if field name is {@code null} 768 */ 769 public DiffBuilder<T> append(final String fieldName, final Object lhs, 770 final Object rhs) { 771 validateFieldNameNotNull(fieldName); 772 if (objectsTriviallyEqual) { 773 return this; 774 } 775 if (lhs == rhs) { 776 return this; 777 } 778 779 final Object objectToTest; 780 if (lhs != null) { 781 objectToTest = lhs; 782 } else { 783 // rhs cannot be null, as lhs != rhs 784 objectToTest = rhs; 785 } 786 787 if (ObjectUtils.isArray(objectToTest)) { 788 if (objectToTest instanceof boolean[]) { 789 return append(fieldName, (boolean[]) lhs, (boolean[]) rhs); 790 } 791 if (objectToTest instanceof byte[]) { 792 return append(fieldName, (byte[]) lhs, (byte[]) rhs); 793 } 794 if (objectToTest instanceof char[]) { 795 return append(fieldName, (char[]) lhs, (char[]) rhs); 796 } 797 if (objectToTest instanceof double[]) { 798 return append(fieldName, (double[]) lhs, (double[]) rhs); 799 } 800 if (objectToTest instanceof float[]) { 801 return append(fieldName, (float[]) lhs, (float[]) rhs); 802 } 803 if (objectToTest instanceof int[]) { 804 return append(fieldName, (int[]) lhs, (int[]) rhs); 805 } 806 if (objectToTest instanceof long[]) { 807 return append(fieldName, (long[]) lhs, (long[]) rhs); 808 } 809 if (objectToTest instanceof short[]) { 810 return append(fieldName, (short[]) lhs, (short[]) rhs); 811 } 812 813 return append(fieldName, (Object[]) lhs, (Object[]) rhs); 814 } 815 816 // Not array type 817 if (Objects.equals(lhs, rhs)) { 818 return this; 819 } 820 821 diffs.add(new Diff<Object>(fieldName) { 822 private static final long serialVersionUID = 1L; 823 824 @Override 825 public Object getLeft() { 826 return lhs; 827 } 828 829 @Override 830 public Object getRight() { 831 return rhs; 832 } 833 }); 834 835 return this; 836 } 837 838 /** 839 * Test if two {@code Object[]}s are equal. 840 * 841 * @param fieldName 842 * the field name 843 * @param lhs 844 * the left-hand {@code Object[]} 845 * @param rhs 846 * the right-hand {@code Object[]} 847 * @return this 848 * @throws NullPointerException 849 * if field name is {@code null} 850 */ 851 public DiffBuilder<T> append(final String fieldName, final Object[] lhs, 852 final Object[] rhs) { 853 validateFieldNameNotNull(fieldName); 854 if (objectsTriviallyEqual) { 855 return this; 856 } 857 858 if (!Arrays.equals(lhs, rhs)) { 859 diffs.add(new Diff<Object[]>(fieldName) { 860 private static final long serialVersionUID = 1L; 861 862 @Override 863 public Object[] getLeft() { 864 return lhs; 865 } 866 867 @Override 868 public Object[] getRight() { 869 return rhs; 870 } 871 }); 872 } 873 874 return this; 875 } 876 877 /** 878 * Append diffs from another {@link DiffResult}. 879 * 880 * <p> 881 * This method is useful if you want to compare properties which are 882 * themselves Diffable and would like to know which specific part of 883 * it is different. 884 * </p> 885 * 886 * <pre> 887 * public class Person implements Diffable<Person> { 888 * String name; 889 * Address address; // implements Diffable<Address> 890 * 891 * ... 892 * 893 * public DiffResult diff(Person obj) { 894 * return new DiffBuilder(this, obj, ToStringStyle.SHORT_PREFIX_STYLE) 895 * .append("name", this.name, obj.name) 896 * .append("address", this.address.diff(obj.address)) 897 * .build(); 898 * } 899 * } 900 * </pre> 901 * 902 * @param fieldName 903 * the field name 904 * @param diffResult 905 * the {@link DiffResult} to append 906 * @return this 907 * @throws NullPointerException if field name is {@code null} or diffResult is {@code null} 908 * @since 3.5 909 */ 910 public DiffBuilder<T> append(final String fieldName, final DiffResult<T> diffResult) { 911 validateFieldNameNotNull(fieldName); 912 Objects.requireNonNull(diffResult, "diffResult"); 913 if (objectsTriviallyEqual) { 914 return this; 915 } 916 diffResult.getDiffs().forEach(diff -> append(fieldName + "." + diff.getFieldName(), diff.getLeft(), diff.getRight())); 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}