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
017package com.google.common.base;
018
019import static com.google.common.base.Preconditions.checkNotNull;
020
021import com.google.common.annotations.Beta;
022import com.google.common.annotations.GwtCompatible;
023
024import java.util.Arrays;
025import java.util.LinkedList;
026import java.util.List;
027
028import 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
041public 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}