    001    /*
    002     * Copyright (C) 2007 The Guava Authors
    003     *
    004     * Licensed under the Apache License, Version 2.0 (the "License");
    005     * you may not use this file except in compliance with the License.
    006     * You may obtain a copy of the License at
    007     *
    008     * http://www.apache.org/licenses/LICENSE-2.0
    009     *
    010     * Unless required by applicable law or agreed to in writing, software
    011     * distributed under the License is distributed on an "AS IS" BASIS,
    012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    013     * See the License for the specific language governing permissions and
    014     * limitations under the License.
    015     */
    016
    017    package com.google.common.base;
    018
    019    import static com.google.common.base.Preconditions.checkNotNull;
    020
    021    import com.google.common.annotations.Beta;
    022    import com.google.common.annotations.GwtCompatible;
    023
    024    import java.util.Arrays;
    025    import java.util.LinkedList;
    026    import java.util.List;
    027
    028    import javax.annotation.Nullable;
    029
    030    /**
    031     * Helper functions that can operate on any {@code Object}.
    032     *
    033     * <p>See the Guava User Guide on <a
    034     * href="http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained">writing
    035     * {@code Object} methods with {@code Objects}</a>.
    036     *
    037     * @author Laurence Gonsalves
    038     * @since 2.0 (imported from Google Collections Library)
    039     */
    040    @GwtCompatible
    041    public final class Objects {
    042      private Objects() {}
    043
    044      /**
    045       * Determines whether two possibly-null objects are equal. Returns:
    046       *
    047       * <ul>
    048       * <li>{@code true} if {@code a} and {@code b} are both null.
    049       * <li>{@code true} if {@code a} and {@code b} are both non-null and they are
    050       *     equal according to {@link Object#equals(Object)}.
    051       * <li>{@code false} in all other situations.
    052       * </ul>
    053       *
    054       * <p>This assumes that any non-null objects passed to this function conform
    055       * to the {@code equals()} contract.
    056       */
    057      public static boolean equal(@Nullable Object a, @Nullable Object b) {
    058        return a == b || (a != null && a.equals(b));
    059      }
    060
    061      /**
    062       * Generates a hash code for multiple values. The hash code is generated by
    063       * calling {@link Arrays#hashCode(Object[])}.
    064       *
    065       * <p>This is useful for implementing {@link Object#hashCode()}. For example,
    066       * in an object that has three properties, {@code x}, {@code y}, and
    067       * {@code z}, one could write:
    068       * <pre>
    069       * public int hashCode() {
    070       *   return Objects.hashCode(getX(), getY(), getZ());
    071       * }</pre>
    072       *
    073       * <b>Warning</b>: When a single object is supplied, the returned hash code
    074       * does not equal the hash code of that object.
    075       */
    076      public static int hashCode(@Nullable Object... objects) {
    077        return Arrays.hashCode(objects);
    078      }
    079
    080      /**
    081       * Creates an instance of {@link ToStringHelper}.
    082       *
    083       * <p>This is helpful for implementing {@link Object#toString()}.
    084       * Specification by example: <pre>   {@code
    085       *   // Returns "ClassName{}"
    086       *   Objects.toStringHelper(this)
    087       *       .toString();
    088       *
    089       *   // Returns "ClassName{x=1}"
    090       *   Objects.toStringHelper(this)
    091       *       .add("x", 1)
    092       *       .toString();
    093       *
    094       *   // Returns "MyObject{x=1}"
    095       *   Objects.toStringHelper("MyObject")
    096       *       .add("x", 1)
    097       *       .toString();
    098       *
    099       *   // Returns "ClassName{x=1, y=foo}"
    100       *   Objects.toStringHelper(this)
    101       *       .add("x", 1)
    102       *       .add("y", "foo")
    103       *       .toString();
    104       *   }}
    105       *
    106       *   // Returns "ClassName{x=1}"
    107       *   Objects.toStringHelper(this)
    108       *       .omitNullValues()
    109       *       .add("x", 1)
    110       *       .add("y", null)
    111       *       .toString();
    112       *   }}</pre>
    113       *
    114       * <p>Note that in GWT, class names are often obfuscated.
    115       *
    116       * @param self the object to generate the string for (typically {@code this}),
    117       *        used only for its class name
    118       * @since 2.0
    119       */
    120      public static ToStringHelper toStringHelper(Object self) {
    121        return new ToStringHelper(simpleName(self.getClass()));
    122      }
    123
    124      /**
    125       * Creates an instance of {@link ToStringHelper} in the same manner as
    126       * {@link Objects#toStringHelper(Object)}, but using the name of {@code clazz}
    127       * instead of using an instance's {@link Object#getClass()}.
    128       *
    129       * <p>Note that in GWT, class names are often obfuscated.
    130       *
    131       * @param clazz the {@link Class} of the instance
    132       * @since 7.0 (source-compatible since 2.0)
    133       */
    134      public static ToStringHelper toStringHelper(Class<?> clazz) {
    135        return new ToStringHelper(simpleName(clazz));
    136      }
    137
    138      /**
    139       * Creates an instance of {@link ToStringHelper} in the same manner as
    140       * {@link Objects#toStringHelper(Object)}, but using {@code className} instead
    141       * of using an instance's {@link Object#getClass()}.
    142       *
    143       * @param className the name of the instance type
    144       * @since 7.0 (source-compatible since 2.0)
    145       */
    146      public static ToStringHelper toStringHelper(String className) {
    147        return new ToStringHelper(className);
    148      }
    149
    150      /**
    151       * {@link Class#getSimpleName()} is not GWT compatible yet, so we
    152       * provide our own implementation.
    153       */
    154      private static String simpleName(Class<?> clazz) {
    155        String name = clazz.getName();
    156
    157        // the nth anonymous class has a class name ending in "Outer$n"
    158        // and local inner classes have names ending in "Outer.$1Inner"
    159        name = name.replaceAll("\\$[0-9]+", "\\$");
    160
    161        // we want the name of the inner class all by its lonesome
    162        int start = name.lastIndexOf('$');
    163
    164        // if this isn't an inner class, just find the start of the
    165        // top level class name.
    166        if (start == -1) {
    167          start = name.lastIndexOf('.');
    168        }
    169        return name.substring(start + 1);
    170      }
    171
    172      /**
    173       * Returns the first of two given parameters that is not {@code null}, if
    174       * either is, or otherwise throws a {@link NullPointerException}.
    175       *
    176       * <p><b>Note:</b> if {@code first} is represented as an {@code Optional<T>},
    177       * this can be accomplished with {@code first.or(second)}. That approach also
    178       * allows for lazy evaluation of the fallback instance, using
    179       * {@code first.or(Supplier)}.
    180       *
    181       * @return {@code first} if {@code first} is not {@code null}, or
    182       *     {@code second} if {@code first} is {@code null} and {@code second} is
    183       *     not {@code null}
    184       * @throws NullPointerException if both {@code first} and {@code second} were
    185       *     {@code null}
    186       * @since 3.0
    187       */
    188      public static <T> T firstNonNull(@Nullable T first, @Nullable T second) {
    189        return first != null ? first : checkNotNull(second);
    190      }
    191
    192      /**
    193       * Support class for {@link Objects#toStringHelper}.
    194       *
    195       * @author Jason Lee
    196       * @since 2.0
    197       */
    198      public static final class ToStringHelper {
    199        private final String className;
    200        private final List<ValueHolder> valueHolders =
    201            new LinkedList<ValueHolder>();
    202        private boolean omitNullValues = false;
    203
    204        /**
    205         * Use {@link Objects#toStringHelper(Object)} to create an instance.
    206         */
    207        private ToStringHelper(String className) {
    208          this.className = checkNotNull(className);
    209        }
    210
    211        /**
    212         * When called, the formatted output returned by {@link #toString()} will
    213         * ignore {@code null} values.
    214         *
    215         * @since 12.0
    216         */
    217        @Beta
    218        public ToStringHelper omitNullValues() {
    219          omitNullValues = true;
    220          return this;
    221        }
    222
    223        /**
    224         * Adds a name/value pair to the formatted output in {@code name=value}
    225         * format. If {@code value} is {@code null}, the string {@code "null"}
    226         * is used, unless {@link #omitNullValues()} is called, in which case this
    227         * name/value pair will not be added.
    228         */
    229        public ToStringHelper add(String name, @Nullable Object value) {
    230          checkNotNull(name);
    231          addHolder(value).builder.append(name).append('=').append(value);
    232          return this;
    233        }
    234
    235        /**
    236         * Adds a name/value pair to the formatted output in {@code name=value}
    237         * format.
    238         *
    239         * @since 11.0 (source-compatible since 2.0)
    240         */
    241        public ToStringHelper add(String name, boolean value) {
    242          checkNameAndAppend(name).append(value);
    243          return this;
    244        }
    245
    246        /**
    247         * Adds a name/value pair to the formatted output in {@code name=value}
    248         * format.
    249         *
    250         * @since 11.0 (source-compatible since 2.0)
    251         */
    252        public ToStringHelper add(String name, char value) {
    253          checkNameAndAppend(name).append(value);
    254          return this;
    255        }
    256
    257        /**
    258         * Adds a name/value pair to the formatted output in {@code name=value}
    259         * format.
    260         *
    261         * @since 11.0 (source-compatible since 2.0)
    262         */
    263        public ToStringHelper add(String name, double value) {
    264          checkNameAndAppend(name).append(value);
    265          return this;
    266        }
    267
    268        /**
    269         * Adds a name/value pair to the formatted output in {@code name=value}
    270         * format.
    271         *
    272         * @since 11.0 (source-compatible since 2.0)
    273         */
    274        public ToStringHelper add(String name, float value) {
    275          checkNameAndAppend(name).append(value);
    276          return this;
    277        }
    278
    279        /**
    280         * Adds a name/value pair to the formatted output in {@code name=value}
    281         * format.
    282         *
    283         * @since 11.0 (source-compatible since 2.0)
    284         */
    285        public ToStringHelper add(String name, int value) {
    286          checkNameAndAppend(name).append(value);
    287          return this;
    288        }
    289
    290        /**
    291         * Adds a name/value pair to the formatted output in {@code name=value}
    292         * format.
    293         *
    294         * @since 11.0 (source-compatible since 2.0)
    295         */
    296        public ToStringHelper add(String name, long value) {
    297          checkNameAndAppend(name).append(value);
    298          return this;
    299        }
    300
    301        private StringBuilder checkNameAndAppend(String name) {
    302          checkNotNull(name);
    303          return addHolder().builder.append(name).append('=');
    304        }
    305
    306        /**
    307         * Adds an unnamed value to the formatted output.
    308         *
    309         * <p>It is strongly encouraged to use {@link #add(String, Object)} instead
    310         * and give value a readable name.
    311         */
    312        public ToStringHelper addValue(@Nullable Object value) {
    313          addHolder(value).builder.append(value);
    314          return this;
    315        }
    316
    317        /**
    318         * Adds an unnamed value to the formatted output.
    319         *
    320         * <p>It is strongly encouraged to use {@link #add(String, boolean)} instead
    321         * and give value a readable name.
    322         *
    323         * @since 11.0 (source-compatible since 2.0)
    324         */
    325        public ToStringHelper addValue(boolean value) {
    326          addHolder().builder.append(value);
    327          return this;
    328        }
    329
    330        /**
    331         * Adds an unnamed value to the formatted output.
    332         *
    333         * <p>It is strongly encouraged to use {@link #add(String, char)} instead
    334         * and give value a readable name.
    335         *
    336         * @since 11.0 (source-compatible since 2.0)
    337         */
    338        public ToStringHelper addValue(char value) {
    339          addHolder().builder.append(value);
    340          return this;
    341        }
    342
    343        /**
    344         * Adds an unnamed value to the formatted output.
    345         *
    346         * <p>It is strongly encouraged to use {@link #add(String, double)} instead
    347         * and give value a readable name.
    348         *
    349         * @since 11.0 (source-compatible since 2.0)
    350         */
    351        public ToStringHelper addValue(double value) {
    352          addHolder().builder.append(value);
    353          return this;
    354        }
    355
    356        /**
    357         * Adds an unnamed value to the formatted output.
    358         *
    359         * <p>It is strongly encouraged to use {@link #add(String, float)} instead
    360         * and give value a readable name.
    361         *
    362         * @since 11.0 (source-compatible since 2.0)
    363         */
    364        public ToStringHelper addValue(float value) {
    365          addHolder().builder.append(value);
    366          return this;
    367        }
    368
    369        /**
    370         * Adds an unnamed value to the formatted output.
    371         *
    372         * <p>It is strongly encouraged to use {@link #add(String, int)} instead
    373         * and give value a readable name.
    374         *
    375         * @since 11.0 (source-compatible since 2.0)
    376         */
    377        public ToStringHelper addValue(int value) {
    378          addHolder().builder.append(value);
    379          return this;
    380        }
    381
    382        /**
    383         * Adds an unnamed value to the formatted output.
    384         *
    385         * <p>It is strongly encouraged to use {@link #add(String, long)} instead
    386         * and give value a readable name.
    387         *
    388         * @since 11.0 (source-compatible since 2.0)
    389         */
    390        public ToStringHelper addValue(long value) {
    391          addHolder().builder.append(value);
    392          return this;
    393        }
    394
    395        /**
    396         * Returns a string in the format specified by {@link
    397         * Objects#toStringHelper(Object)}.
    398         */
    399        @Override public String toString() {
    400          // create a copy to keep it consistent in case value changes
    401          boolean omitNullValuesSnapshot = omitNullValues;
    402          boolean needsSeparator = false;
    403          StringBuilder builder = new StringBuilder(32).append(className)
    404              .append('{');
    405          for (ValueHolder valueHolder : valueHolders) {
    406            if (!omitNullValuesSnapshot || !valueHolder.isNull) {
    407              if (needsSeparator) {
    408                builder.append(", ");
    409              } else {
    410                needsSeparator = true;
    411              }
    412              // must explicitly cast it, otherwise GWT tests might fail because
    413              // it tries to access StringBuilder.append(StringBuilder), which is
    414              // a private method
    415              // TODO(user): change once 5904010 is fixed
    416              CharSequence sequence = valueHolder.builder;
    417              builder.append(sequence);
    418            }
    419          }
    420          return builder.append('}').toString();
    421        }
    422
    423        private ValueHolder addHolder() {
    424          ValueHolder valueHolder = new ValueHolder();
    425          valueHolders.add(valueHolder);
    426          return valueHolder;
    427        }
    428
    429        private ValueHolder addHolder(@Nullable Object value) {
    430          ValueHolder valueHolder = addHolder();
    431          valueHolder.isNull = (value == null);
    432          return valueHolder;
    433        }
    434
    435        private static final class ValueHolder {
    436          final StringBuilder builder = new StringBuilder();
    437          boolean isNull;
    438        }
    439      }
    440    }