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