    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 *      https://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.io.Serializable;
    020import java.util.ArrayList;
    021import java.util.Arrays;
    022import java.util.List;
    023import java.util.Objects;
    024import java.util.function.Supplier;
    025
    026import org.apache.commons.lang3.ArrayUtils;
    027import org.apache.commons.lang3.ObjectUtils;
    028
    029/**
    030 * Assists in implementing {@link Diffable#diff(Object)} methods.
    031 *
    032 * <p>
    033 * To use this class, write code as follows:
    034 * </p>
    035 *
    036 * <pre>{@code
    037 * public class Person implements Diffable<Person> {
    038 *   String name;
    039 *   int age;
    040 *   boolean smoker;
    041 *
    042 *   ...
    043 *
    044 *   public DiffResult<Person> diff(Person obj) {
    045 *     // No need for null check, as NullPointerException correct if obj is null
    046 *     return DiffBuilder.<Person>builder()
    047 *         .setLeft(this)
    048 *         .setRight(obj)
    049 *         .setStyle(ToStringStyle.SHORT_PREFIX_STYLE)
    050 *         .build()
    051 *       .append("name", this.name, obj.name)
    052 *       .append("age", this.age, obj.age)
    053 *       .append("smoker", this.smoker, obj.smoker)
    054 *       .build();
    055 *   }
    056 * }
    057 * }</pre>
    058 *
    059 * <p>
    060 * The {@link ToStringStyle} passed to the constructor is embedded in the returned {@link DiffResult} and influences the style of the
    061 * {@code DiffResult.toString()} method. This style choice can be overridden by calling {@link DiffResult#toString(ToStringStyle)}.
    062 * </p>
    063 * <p>
    064 * See {@link ReflectionDiffBuilder} for a reflection based version of this class.
    065 * </p>
    066 *
    067 * @param <T> type of the left and right object.
    068 * @see Diffable
    069 * @see Diff
    070 * @see DiffResult
    071 * @see ToStringStyle
    072 * @see ReflectionDiffBuilder
    073 * @since 3.3
    074 */
    075public class DiffBuilder<T> implements Builder<DiffResult<T>> {
    076
    077    /**
    078     * Constructs a new instance.
    079     *
    080     * @param <T> type of the left and right object.
    081     * @since 3.15.0
    082     */
    083    public static final class Builder<T> {
    084
    085        private T left;
    086        private T right;
    087        private ToStringStyle style;
    088        private boolean testObjectsEquals = true;
    089        private String toStringFormat = TO_STRING_FORMAT;
    090
    091        /**
    092         * Constructs a new instance.
    093         */
    094        public Builder() {
    095            // empty
    096        }
    097
    098        /**
    099         * Builds a new configured {@link DiffBuilder}.
    100         *
    101         * @return a new configured {@link DiffBuilder}.
    102         */
    103        public DiffBuilder<T> build() {
    104            return new DiffBuilder<>(left, right, style, testObjectsEquals, toStringFormat);
    105        }
    106
    107        /**
    108         * Sets the left object.
    109         *
    110         * @param left the left object.
    111         * @return {@code this} instance.
    112         */
    113        public Builder<T> setLeft(final T left) {
    114            this.left = left;
    115            return this;
    116        }
    117
    118        /**
    119         * Sets the right object.
    120         *
    121         * @param right the left object.
    122         * @return {@code this} instance.
    123         */
    124        public Builder<T> setRight(final T right) {
    125            this.right = right;
    126            return this;
    127        }
    128
    129        /**
    130         * Sets the style will to use when outputting the objects, {@code null} uses the default.
    131         *
    132         * @param style the style to use when outputting the objects, {@code null} uses the default.
    133         * @return {@code this} instance.
    134         */
    135        public Builder<T> setStyle(final ToStringStyle style) {
    136            this.style = style != null ? style : ToStringStyle.DEFAULT_STYLE;
    137            return this;
    138        }
    139
    140        /**
    141         * Sets whether to test if left and right are the same or equal. All of the append(fieldName, left, right) methods will abort without creating a field
    142         * {@link Diff} if the trivially equal test is enabled and returns true. The result of this test is never changed throughout the life of this
    143         * {@link DiffBuilder}.
    144         *
    145         * @param testObjectsEquals If true, this will test if lhs and rhs are the same or equal. All of the append(fieldName, left, right) methods will abort
    146         *                          without creating a field {@link Diff} if the trivially equal test is enabled and returns true. The result of this test is
    147         *                          never changed throughout the life of this {@link DiffBuilder}.
    148         * @return {@code this} instance.
    149         */
    150        public Builder<T> setTestObjectsEquals(final boolean testObjectsEquals) {
    151            this.testObjectsEquals = testObjectsEquals;
    152            return this;
    153        }
    154
    155        /**
    156         * Sets the two-argument format string for {@link String#format(String, Object...)}, for example {@code "%s differs from %s"}.
    157         *
    158         * @param toStringFormat {@code null} uses the default.
    159         * @return {@code this} instance.
    160         */
    161        public Builder<T> setToStringFormat(final String toStringFormat) {
    162            this.toStringFormat = toStringFormat != null ? toStringFormat : TO_STRING_FORMAT;
    163            return this;
    164        }
    165    }
    166
    167    private static final class SDiff<T> extends Diff<T> {
    168
    169        private static final long serialVersionUID = 1L;
    170        private final SerializableSupplier<T> leftSupplier;
    171        private final SerializableSupplier<T> rightSupplier;
    172
    173        private SDiff(final String fieldName, final SerializableSupplier<T> leftSupplier, final SerializableSupplier<T> rightSupplier, final Class<T> type) {
    174            super(fieldName, type);
    175            this.leftSupplier = Objects.requireNonNull(leftSupplier);
    176            this.rightSupplier = Objects.requireNonNull(rightSupplier);
    177        }
    178
    179        @Override
    180        public T getLeft() {
    181            return leftSupplier.get();
    182        }
    183
    184        @Override
    185        public T getRight() {
    186            return rightSupplier.get();
    187        }
    188
    189    }
    190
    191    /**
    192     * Private interface while we still have to support serialization.
    193     *
    194     * @param <T> the type of results supplied by this supplier.
    195     */
    196    private interface SerializableSupplier<T> extends Supplier<T>, Serializable {
    197        // empty
    198    }
    199
    200    static final String TO_STRING_FORMAT = "%s differs from %s";
    201
    202    /**
    203     * Constructs a new {@link Builder}.
    204     *
    205     * @param <T> type of the left and right object.
    206     * @return a new {@link Builder}.
    207     * @since 3.15.0
    208     */
    209    public static <T> Builder<T> builder() {
    210        return new Builder<>();
    211    }
    212
    213    private final List<Diff<?>> diffs;
    214    private final boolean equals;
    215    private final T left;
    216    private final T right;
    217    private final ToStringStyle style;
    218    private final String toStringFormat;
    219
    220    /**
    221     * Constructs a builder for the specified objects with the specified style.
    222     *
    223     * <p>
    224     * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will not evaluate any calls to {@code append(...)} and will return an empty
    225     * {@link DiffResult} when {@link #build()} is executed.
    226     * </p>
    227     *
    228     * <p>
    229     * This delegates to {@link #DiffBuilder(Object, Object, ToStringStyle, boolean)} with the testTriviallyEqual flag enabled.
    230     * </p>
    231     *
    232     * @param left  {@code this} object
    233     * @param right the object to diff against
    234     * @param style the style to use when outputting the objects, {@code null} uses the default
    235     * @throws NullPointerException if {@code lhs} or {@code rhs} is {@code null}
    236     * @deprecated Use {@link Builder}.
    237     */
    238    @Deprecated
    239    public DiffBuilder(final T left, final T right, final ToStringStyle style) {
    240        this(left, right, style, true);
    241    }
    242
    243    /**
    244     * Constructs a builder for the specified objects with the specified style.
    245     *
    246     * <p>
    247     * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will not evaluate any calls to {@code append(...)} and will return an empty
    248     * {@link DiffResult} when {@link #build()} is executed.
    249     * </p>
    250     *
    251     * @param left              {@code this} object
    252     * @param right             the object to diff against
    253     * @param style             the style to use when outputting the objects, {@code null} uses the default
    254     * @param testObjectsEquals If true, this will test if lhs and rhs are the same or equal. All of the append(fieldName, lhs, rhs) methods will abort without
    255     *                          creating a field {@link Diff} if the trivially equal test is enabled and returns true. The result of this test is never changed
    256     *                          throughout the life of this {@link DiffBuilder}.
    257     * @throws NullPointerException if {@code lhs} or {@code rhs} is {@code null}
    258     * @since 3.4
    259     * @deprecated Use {@link Builder}.
    260     */
    261    @Deprecated
    262    public DiffBuilder(final T left, final T right, final ToStringStyle style, final boolean testObjectsEquals) {
    263        this(left, right, style, testObjectsEquals, TO_STRING_FORMAT);
    264    }
    265
    266    private DiffBuilder(final T left, final T right, final ToStringStyle style, final boolean testObjectsEquals, final String toStringFormat) {
    267        this.left = Objects.requireNonNull(left, "left");
    268        this.right = Objects.requireNonNull(right, "right");
    269        this.diffs = new ArrayList<>();
    270        this.toStringFormat = toStringFormat;
    271        this.style = style != null ? style : ToStringStyle.DEFAULT_STYLE;
    272        // Don't compare any fields if objects equal
    273        this.equals = testObjectsEquals && Objects.equals(left, right);
    274    }
    275
    276    private <F> DiffBuilder<T> add(final String fieldName, final SerializableSupplier<F> left, final SerializableSupplier<F> right, final Class<F> type) {
    277        diffs.add(new SDiff<>(fieldName, left, right, type));
    278        return this;
    279    }
    280
    281    /**
    282     * Tests if two {@code boolean}s are equal.
    283     *
    284     * @param fieldName the field name
    285     * @param lhs       the left-hand side {@code boolean}
    286     * @param rhs       the right-hand side {@code boolean}
    287     * @return {@code this} instance.
    288     * @throws NullPointerException if field name is {@code null}
    289     */
    290    public DiffBuilder<T> append(final String fieldName, final boolean lhs, final boolean rhs) {
    291        return equals || lhs == rhs ? this : add(fieldName, () -> Boolean.valueOf(lhs), () -> Boolean.valueOf(rhs), Boolean.class);
    292    }
    293
    294    /**
    295     * Tests if two {@code boolean[]}s are equal.
    296     *
    297     * @param fieldName the field name
    298     * @param lhs       the left-hand side {@code boolean[]}
    299     * @param rhs       the right-hand side {@code boolean[]}
    300     * @return {@code this} instance.
    301     * @throws NullPointerException if field name is {@code null}
    302     */
    303    public DiffBuilder<T> append(final String fieldName, final boolean[] lhs, final boolean[] rhs) {
    304        return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Boolean[].class);
    305    }
    306
    307    /**
    308     * Tests if two {@code byte}s are equal.
    309     *
    310     * @param fieldName the field name
    311     * @param lhs       the left-hand side {@code byte}
    312     * @param rhs       the right-hand side {@code byte}
    313     * @return {@code this} instance.
    314     * @throws NullPointerException if field name is {@code null}
    315     */
    316    public DiffBuilder<T> append(final String fieldName, final byte lhs, final byte rhs) {
    317        return equals || lhs == rhs ? this : add(fieldName, () -> Byte.valueOf(lhs), () -> Byte.valueOf(rhs), Byte.class);
    318    }
    319
    320    /**
    321     * Tests if two {@code byte[]}s are equal.
    322     *
    323     * @param fieldName the field name
    324     * @param lhs       the left-hand side {@code byte[]}
    325     * @param rhs       the right-hand side {@code byte[]}
    326     * @return {@code this} instance.
    327     * @throws NullPointerException if field name is {@code null}
    328     */
    329    public DiffBuilder<T> append(final String fieldName, final byte[] lhs, final byte[] rhs) {
    330        return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Byte[].class);
    331    }
    332
    333    /**
    334     * Tests if two {@code char}s are equal.
    335     *
    336     * @param fieldName the field name
    337     * @param lhs       the left-hand side {@code char}
    338     * @param rhs       the right-hand side {@code char}
    339     * @return {@code this} instance.
    340     * @throws NullPointerException if field name is {@code null}
    341     */
    342    public DiffBuilder<T> append(final String fieldName, final char lhs, final char rhs) {
    343        return equals || lhs == rhs ? this : add(fieldName, () -> Character.valueOf(lhs), () -> Character.valueOf(rhs), Character.class);
    344    }
    345
    346    /**
    347     * Tests if two {@code char[]}s are equal.
    348     *
    349     * @param fieldName the field name
    350     * @param lhs       the left-hand side {@code char[]}
    351     * @param rhs       the right-hand side {@code char[]}
    352     * @return {@code this} instance.
    353     * @throws NullPointerException if field name is {@code null}
    354     */
    355    public DiffBuilder<T> append(final String fieldName, final char[] lhs, final char[] rhs) {
    356        return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Character[].class);
    357    }
    358
    359    /**
    360     * Appends diffs from another {@link DiffResult}.
    361     *
    362     * <p>
    363     * Useful this method to compare properties which are themselves Diffable and would like to know which specific part of it is different.
    364     * </p>
    365     *
    366     * <pre>{@code
    367     * public class Person implements Diffable<Person> {
    368     *   String name;
    369     *   Address address; // implements Diffable<Address>
    370     *
    371     *   ...
    372     *
    373     *   public DiffResult diff(Person obj) {
    374     *     return new DiffBuilder(this, obj, ToStringStyle.SHORT_PREFIX_STYLE)
    375     *       .append("name", this.name, obj.name)
    376     *       .append("address", this.address.diff(obj.address))
    377     *       .build();
    378     *   }
    379     * }
    380     * }
    381     * </pre>
    382     *
    383     * @param fieldName  the field name
    384     * @param diffResult the {@link DiffResult} to append
    385     * @return {@code this} instance.
    386     * @throws NullPointerException if field name is {@code null} or diffResult is {@code null}
    387     * @since 3.5
    388     */
    389    public DiffBuilder<T> append(final String fieldName, final DiffResult<?> diffResult) {
    390        Objects.requireNonNull(diffResult, "diffResult");
    391        if (equals) {
    392            return this;
    393        }
    394        diffResult.getDiffs().forEach(diff -> append(fieldName + "." + diff.getFieldName(), diff.getLeft(), diff.getRight()));
    395        return this;
    396    }
    397
    398    /**
    399     * Tests if two {@code double}s are equal.
    400     *
    401     * @param fieldName the field name
    402     * @param lhs       the left-hand side {@code double}
    403     * @param rhs       the right-hand side {@code double}
    404     * @return {@code this} instance.
    405     * @throws NullPointerException if field name is {@code null}
    406     */
    407    public DiffBuilder<T> append(final String fieldName, final double lhs, final double rhs) {
    408        return equals || Double.doubleToLongBits(lhs) == Double.doubleToLongBits(rhs) ? this
    409                : add(fieldName, () -> Double.valueOf(lhs), () -> Double.valueOf(rhs), Double.class);
    410    }
    411
    412    /**
    413     * Tests if two {@code double[]}s are equal.
    414     *
    415     * @param fieldName the field name
    416     * @param lhs       the left-hand side {@code double[]}
    417     * @param rhs       the right-hand side {@code double[]}
    418     * @return {@code this} instance.
    419     * @throws NullPointerException if field name is {@code null}
    420     */
    421    public DiffBuilder<T> append(final String fieldName, final double[] lhs, final double[] rhs) {
    422        return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Double[].class);
    423    }
    424
    425    /**
    426     * Test if two {@code float}s are equal.
    427     *
    428     * @param fieldName the field name
    429     * @param lhs       the left-hand side {@code float}
    430     * @param rhs       the right-hand side {@code float}
    431     * @return {@code this} instance.
    432     * @throws NullPointerException if field name is {@code null}
    433     */
    434    public DiffBuilder<T> append(final String fieldName, final float lhs, final float rhs) {
    435        return equals || Float.floatToIntBits(lhs) == Float.floatToIntBits(rhs) ? this
    436                : add(fieldName, () -> Float.valueOf(lhs), () -> Float.valueOf(rhs), Float.class);
    437    }
    438
    439    /**
    440     * Tests if two {@code float[]}s are equal.
    441     *
    442     * @param fieldName the field name
    443     * @param lhs       the left-hand side {@code float[]}
    444     * @param rhs       the right-hand side {@code float[]}
    445     * @return {@code this} instance.
    446     * @throws NullPointerException if field name is {@code null}
    447     */
    448    public DiffBuilder<T> append(final String fieldName, final float[] lhs, final float[] rhs) {
    449        return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Float[].class);
    450    }
    451
    452    /**
    453     * Tests if two {@code int}s are equal.
    454     *
    455     * @param fieldName the field name
    456     * @param lhs       the left-hand side {@code int}
    457     * @param rhs       the right-hand side {@code int}
    458     * @return {@code this} instance.
    459     * @throws NullPointerException if field name is {@code null}
    460     */
    461    public DiffBuilder<T> append(final String fieldName, final int lhs, final int rhs) {
    462        return equals || lhs == rhs ? this : add(fieldName, () -> Integer.valueOf(lhs), () -> Integer.valueOf(rhs), Integer.class);
    463    }
    464
    465    /**
    466     * Tests if two {@code int[]}s are equal.
    467     *
    468     * @param fieldName the field name
    469     * @param lhs       the left-hand side {@code int[]}
    470     * @param rhs       the right-hand side {@code int[]}
    471     * @return {@code this} instance.
    472     * @throws NullPointerException if field name is {@code null}
    473     */
    474    public DiffBuilder<T> append(final String fieldName, final int[] lhs, final int[] rhs) {
    475        return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Integer[].class);
    476    }
    477
    478    /**
    479     * Tests if two {@code long}s are equal.
    480     *
    481     * @param fieldName the field name
    482     * @param lhs       the left-hand side {@code long}
    483     * @param rhs       the right-hand side {@code long}
    484     * @return {@code this} instance.
    485     * @throws NullPointerException if field name is {@code null}
    486     */
    487    public DiffBuilder<T> append(final String fieldName, final long lhs, final long rhs) {
    488        return equals || lhs == rhs ? this : add(fieldName, () -> Long.valueOf(lhs), () -> Long.valueOf(rhs), Long.class);
    489    }
    490
    491    /**
    492     * Tests if two {@code long[]}s are equal.
    493     *
    494     * @param fieldName the field name
    495     * @param lhs       the left-hand side {@code long[]}
    496     * @param rhs       the right-hand side {@code long[]}
    497     * @return {@code this} instance.
    498     * @throws NullPointerException if field name is {@code null}
    499     */
    500    public DiffBuilder<T> append(final String fieldName, final long[] lhs, final long[] rhs) {
    501        return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Long[].class);
    502    }
    503
    504    /**
    505     * Tests if two {@link Objects}s are equal.
    506     *
    507     * @param fieldName the field name
    508     * @param lhs       the left-hand side {@link Object}
    509     * @param rhs       the right-hand side {@link Object}
    510     * @return {@code this} instance.
    511     * @throws NullPointerException if field name is {@code null}
    512     */
    513    public DiffBuilder<T> append(final String fieldName, final Object lhs, final Object rhs) {
    514        if (equals || lhs == rhs) {
    515            return this;
    516        }
    517        // rhs cannot be null, as lhs != rhs
    518        final Object test = lhs != null ? lhs : rhs;
    519        if (ObjectUtils.isArray(test)) {
    520            if (test instanceof boolean[]) {
    521                return append(fieldName, (boolean[]) lhs, (boolean[]) rhs);
    522            }
    523            if (test instanceof byte[]) {
    524                return append(fieldName, (byte[]) lhs, (byte[]) rhs);
    525            }
    526            if (test instanceof char[]) {
    527                return append(fieldName, (char[]) lhs, (char[]) rhs);
    528            }
    529            if (test instanceof double[]) {
    530                return append(fieldName, (double[]) lhs, (double[]) rhs);
    531            }
    532            if (test instanceof float[]) {
    533                return append(fieldName, (float[]) lhs, (float[]) rhs);
    534            }
    535            if (test instanceof int[]) {
    536                return append(fieldName, (int[]) lhs, (int[]) rhs);
    537            }
    538            if (test instanceof long[]) {
    539                return append(fieldName, (long[]) lhs, (long[]) rhs);
    540            }
    541            if (test instanceof short[]) {
    542                return append(fieldName, (short[]) lhs, (short[]) rhs);
    543            }
    544            return append(fieldName, (Object[]) lhs, (Object[]) rhs);
    545        }
    546        // Not array type
    547        return Objects.equals(lhs, rhs) ? this : add(fieldName, () -> lhs, () -> rhs, Object.class);
    548    }
    549
    550    /**
    551     * Tests if two {@code Object[]}s are equal.
    552     *
    553     * @param fieldName the field name
    554     * @param lhs       the left-hand side {@code Object[]}
    555     * @param rhs       the right-hand side {@code Object[]}
    556     * @return {@code this} instance.
    557     * @throws NullPointerException if field name is {@code null}
    558     */
    559    public DiffBuilder<T> append(final String fieldName, final Object[] lhs, final Object[] rhs) {
    560        return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> lhs, () -> rhs, Object[].class);
    561    }
    562
    563    /**
    564     * Tests if two {@code short}s are equal.
    565     *
    566     * @param fieldName the field name
    567     * @param lhs       the left-hand side {@code short}
    568     * @param rhs       the right-hand side {@code short}
    569     * @return {@code this} instance.
    570     * @throws NullPointerException if field name is {@code null}
    571     */
    572    public DiffBuilder<T> append(final String fieldName, final short lhs, final short rhs) {
    573        return equals || lhs == rhs ? this : add(fieldName, () -> Short.valueOf(lhs), () -> Short.valueOf(rhs), Short.class);
    574    }
    575
    576    /**
    577     * Tests if two {@code short[]}s are equal.
    578     *
    579     * @param fieldName the field name
    580     * @param lhs       the left-hand side {@code short[]}
    581     * @param rhs       the right-hand side {@code short[]}
    582     * @return {@code this} instance.
    583     * @throws NullPointerException if field name is {@code null}
    584     */
    585    public DiffBuilder<T> append(final String fieldName, final short[] lhs, final short[] rhs) {
    586        return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Short[].class);
    587    }
    588
    589    /**
    590     * Builds a {@link DiffResult} based on the differences appended to this builder.
    591     *
    592     * @return a {@link DiffResult} containing the differences between the two objects.
    593     */
    594    @Override
    595    public DiffResult<T> build() {
    596        return new DiffResult<>(left, right, diffs, style, toStringFormat);
    597    }
    598
    599    /**
    600     * Gets the left object.
    601     *
    602     * @return the left object.
    603     */
    604    T getLeft() {
    605        return left;
    606    }
    607
    608    /**
    609     * Gets the right object.
    610     *
    611     * @return the right object.
    612     */
    613    T getRight() {
    614        return right;
    615    }
    616
    617}