    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.GwtCompatible;
    022
    023    import java.util.Arrays;
    024
    025    import javax.annotation.Nullable;
    026
    027    /**
    028     * Helper functions that can operate on any {@code Object}.
    029     *
    030     * @author Laurence Gonsalves
    031     * @since 2.0 (imported from Google Collections Library)
    032     */
    033    @GwtCompatible
    034    public final class Objects {
    035      private Objects() {}
    036
    037      /**
    038       * Determines whether two possibly-null objects are equal. Returns:
    039       *
    040       * <ul>
    041       * <li>{@code true} if {@code a} and {@code b} are both null.
    042       * <li>{@code true} if {@code a} and {@code b} are both non-null and they are
    043       *     equal according to {@link Object#equals(Object)}.
    044       * <li>{@code false} in all other situations.
    045       * </ul>
    046       *
    047       * <p>This assumes that any non-null objects passed to this function conform
    048       * to the {@code equals()} contract.
    049       */
    050      public static boolean equal(@Nullable Object a, @Nullable Object b) {
    051        return a == b || (a != null && a.equals(b));
    052      }
    053
    054      /**
    055       * Generates a hash code for multiple values. The hash code is generated by
    056       * calling {@link Arrays#hashCode(Object[])}.
    057       *
    058       * <p>This is useful for implementing {@link Object#hashCode()}. For example,
    059       * in an object that has three properties, {@code x}, {@code y}, and
    060       * {@code z}, one could write:
    061       * <pre>
    062       * public int hashCode() {
    063       *   return Objects.hashCode(getX(), getY(), getZ());
    064       * }</pre>
    065       *
    066       * <b>Warning</b>: When a single object is supplied, the returned hash code
    067       * does not equal the hash code of that object.
    068       */
    069      public static int hashCode(@Nullable Object... objects) {
    070        return Arrays.hashCode(objects);
    071      }
    072
    073      /**
    074       * Creates an instance of {@link ToStringHelper}.
    075       *
    076       * <p>This is helpful for implementing {@link Object#toString()}.
    077       * Specification by example: <pre>   {@code
    078       *   // Returns "ClassName{}"
    079       *   Objects.toStringHelper(this)
    080       *       .toString();
    081       *
    082       *   // Returns "ClassName{x=1}"
    083       *   Objects.toStringHelper(this)
    084       *       .add("x", 1)
    085       *       .toString();
    086       *
    087       *   // Returns "MyObject{x=1}"
    088       *   Objects.toStringHelper("MyObject")
    089       *       .add("x", 1)
    090       *       .toString();
    091       *
    092       *   // Returns "ClassName{x=1, y=foo}"
    093       *   Objects.toStringHelper(this)
    094       *       .add("x", 1)
    095       *       .add("y", "foo")
    096       *       .toString();
    097       *   }}</pre>
    098       *
    099       * <p>Note that in GWT, class names are often obfuscated.
    100       *
    101       * @param self the object to generate the string for (typically {@code this}),
    102       *        used only for its class name
    103       * @since 2.0
    104       */
    105      public static ToStringHelper toStringHelper(Object self) {
    106        return new ToStringHelper(simpleName(self.getClass()));
    107      }
    108
    109      /**
    110       * Creates an instance of {@link ToStringHelper} in the same manner as
    111       * {@link Objects#toStringHelper(Object)}, but using the name of {@code clazz}
    112       * instead of using an instance's {@link Object#getClass()}.
    113       *
    114       * <p>Note that in GWT, class names are often obfuscated.
    115       *
    116       * @param clazz the {@link Class} of the instance
    117       * @since 7.0 (source-compatible since 2.0)
    118       */
    119      public static ToStringHelper toStringHelper(Class<?> clazz) {
    120        return new ToStringHelper(simpleName(clazz));
    121      }
    122
    123      /**
    124       * Creates an instance of {@link ToStringHelper} in the same manner as
    125       * {@link Objects#toStringHelper(Object)}, but using {@code className} instead
    126       * of using an instance's {@link Object#getClass()}.
    127       *
    128       * @param className the name of the instance type
    129       * @since 7.0 (source-compatible since 2.0)
    130       */
    131      public static ToStringHelper toStringHelper(String className) {
    132        return new ToStringHelper(className);
    133      }
    134
    135      /**
    136       * {@link Class#getSimpleName()} is not GWT compatible yet, so we
    137       * provide our own implementation.
    138       */
    139      private static String simpleName(Class<?> clazz) {
    140        String name = clazz.getName();
    141
    142        // the nth anonymous class has a class name ending in "Outer$n"
    143        // and local inner classes have names ending in "Outer.$1Inner"
    144        name = name.replaceAll("\\$[0-9]+", "\\$");
    145
    146        // we want the name of the inner class all by its lonesome
    147        int start = name.lastIndexOf('$');
    148
    149        // if this isn't an inner class, just find the start of the
    150        // top level class name.
    151        if (start == -1) {
    152          start = name.lastIndexOf('.');
    153        }
    154        return name.substring(start + 1);
    155      }
    156
    157      /**
    158       * Returns the first of two given parameters that is not {@code null}, if
    159       * either is, or otherwise throws a {@link NullPointerException}.
    160       *
    161       * <p><b>Note:</b> if {@code first} is represented as an {@code Optional<T>},
    162       * this can be accomplished with {@code first.or(second)}. That approach also
    163       * allows for lazy evaluation of the fallback instance, using
    164       * {@code first.or(Supplier)}.
    165       *
    166       * @return {@code first} if {@code first} is not {@code null}, or
    167       *     {@code second} if {@code first} is {@code null} and {@code second} is
    168       *     not {@code null}
    169       * @throws NullPointerException if both {@code first} and {@code second} were
    170       *     {@code null}
    171       * @since 3.0
    172       */
    173      public static <T> T firstNonNull(@Nullable T first, @Nullable T second) {
    174        return first != null ? first : checkNotNull(second);
    175      }
    176
    177      /**
    178       * Support class for {@link Objects#toStringHelper}.
    179       *
    180       * @author Jason Lee
    181       * @since 2.0
    182       */
    183      public static final class ToStringHelper {
    184        private final StringBuilder builder;
    185        private boolean needsSeparator = false;
    186
    187        /**
    188         * Use {@link Objects#toStringHelper(Object)} to create an instance.
    189         */
    190        private ToStringHelper(String className) {
    191          checkNotNull(className);
    192          this.builder = new StringBuilder(32).append(className).append('{');
    193        }
    194
    195        /**
    196         * Adds a name/value pair to the formatted output in {@code name=value}
    197         * format. If {@code value} is {@code null}, the string {@code "null"}
    198         * is used.
    199         */
    200        public ToStringHelper add(String name, @Nullable Object value) {
    201          checkNotNull(name);
    202          maybeAppendSeparator().append(name).append('=').append(value);
    203          return this;
    204        }
    205
    206        /**
    207         * Adds a value to the formatted output in {@code value} format.
    208         *
    209         * <p>It is strongly encouraged to use {@link #add(String, Object)} instead
    210         * and give value a readable name.
    211         */
    212        public ToStringHelper addValue(@Nullable Object value) {
    213          maybeAppendSeparator().append(value);
    214          return this;
    215        }
    216
    217        /**
    218         * Returns a string in the format specified by {@link
    219         * Objects#toStringHelper(Object)}.
    220         */
    221        @Override public String toString() {
    222          try {
    223            return builder.append('}').toString();
    224          } finally {
    225            // Slice off the closing brace in case there are additional calls to
    226            // #add or #addValue.
    227            builder.setLength(builder.length() - 1);
    228          }
    229        }
    230
    231        private StringBuilder maybeAppendSeparator() {
    232          if (needsSeparator) {
    233            return builder.append(", ");
    234          } else {
    235            needsSeparator = true;
    236            return builder;
    237          }
    238        }
    239      }
    240    }