001/*
002 * Copyright (C) 2014 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.base;
016
017import static com.google.common.base.Preconditions.checkNotNull;
018import static java.util.logging.Level.WARNING;
019
020import com.google.common.annotations.GwtCompatible;
021import com.google.errorprone.annotations.CanIgnoreReturnValue;
022import com.google.errorprone.annotations.concurrent.GuardedBy;
023import java.util.Arrays;
024import java.util.logging.Logger;
025import org.checkerframework.checker.nullness.qual.Nullable;
026
027/**
028 * Helper functions that operate on any {@code Object}, and are not already provided in {@link
029 * java.util.Objects}.
030 *
031 * <p>See the Guava User Guide on <a
032 * href="https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained">writing {@code Object}
033 * methods with {@code MoreObjects}</a>.
034 *
035 * @author Laurence Gonsalves
036 * @since 18.0 (since 2.0 as {@code Objects})
037 */
038@GwtCompatible
039public final class MoreObjects {
040  /**
041   * Returns the first of two given parameters that is not {@code null}, if either is, or otherwise
042   * throws a {@link NullPointerException}.
043   *
044   * <p>To find the first non-null element in an iterable, use {@code Iterables.find(iterable,
045   * Predicates.notNull())}. For varargs, use {@code Iterables.find(Arrays.asList(a, b, c, ...),
046   * Predicates.notNull())}, static importing as necessary.
047   *
048   * <p><b>Note:</b> if {@code first} is represented as an {@link Optional}, this can be
049   * accomplished with {@link Optional#or(Object) first.or(second)}. That approach also allows for
050   * lazy evaluation of the fallback instance, using {@link Optional#or(Supplier)
051   * first.or(supplier)}.
052   *
053   * <p><b>Java 9 users:</b> use {@code java.util.Objects.requireNonNullElse(first, second)}
054   * instead.
055   *
056   * @return {@code first} if it is non-null; otherwise {@code second} if it is non-null
057   * @throws NullPointerException if both {@code first} and {@code second} are null
058   * @since 18.0 (since 3.0 as {@code Objects.firstNonNull()}).
059   */
060  public static <T> T firstNonNull(@Nullable T first, @Nullable T second) {
061    if (first != null) {
062      return first;
063    }
064    if (second != null) {
065      return second;
066    }
067    throw new NullPointerException("Both parameters are null");
068  }
069
070  /**
071   * Creates an instance of {@link ToStringHelper}.
072   *
073   * <p>This is helpful for implementing {@link Object#toString()}. Specification by example:
074   *
075   * <pre>{@code
076   * // Returns "ClassName{}"
077   * MoreObjects.toStringHelper(this)
078   *     .toString();
079   *
080   * // Returns "ClassName{x=1}"
081   * MoreObjects.toStringHelper(this)
082   *     .add("x", 1)
083   *     .toString();
084   *
085   * // Returns "MyObject{x=1}"
086   * MoreObjects.toStringHelper("MyObject")
087   *     .add("x", 1)
088   *     .toString();
089   *
090   * // Returns "ClassName{x=1, y=foo}"
091   * MoreObjects.toStringHelper(this)
092   *     .add("x", 1)
093   *     .add("y", "foo")
094   *     .toString();
095   *
096   * // Returns "ClassName{x=1}"
097   * MoreObjects.toStringHelper(this)
098   *     .omitNullValues()
099   *     .add("x", 1)
100   *     .add("y", null)
101   *     .toString();
102   * }</pre>
103   *
104   * <p>Note that in GWT, class names are often obfuscated.
105   *
106   * @param self the object to generate the string for (typically {@code this}), used only for its
107   *     class name
108   * @since 18.0 (since 2.0 as {@code Objects.toStringHelper()}).
109   */
110  public static ToStringHelper toStringHelper(Object self) {
111    return new ToStringHelper(self.getClass().getSimpleName());
112  }
113
114  /**
115   * Creates an instance of {@link ToStringHelper} in the same manner as {@link
116   * #toStringHelper(Object)}, but using the simple name of {@code clazz} instead of using an
117   * instance's {@link Object#getClass()}.
118   *
119   * <p>Note that in GWT, class names are often obfuscated.
120   *
121   * @param clazz the {@link Class} of the instance
122   * @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}).
123   */
124  public static ToStringHelper toStringHelper(Class<?> clazz) {
125    return new ToStringHelper(clazz.getSimpleName());
126  }
127
128  /**
129   * Creates an instance of {@link ToStringHelper} in the same manner as {@link
130   * #toStringHelper(Object)}, but using {@code className} instead of using an instance's {@link
131   * Object#getClass()}.
132   *
133   * @param className the name of the instance type
134   * @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}).
135   */
136  public static ToStringHelper toStringHelper(String className) {
137    return new ToStringHelper(className);
138  }
139
140  /**
141   * Support class for {@link MoreObjects#toStringHelper}.
142   *
143   * @author Jason Lee
144   * @since 18.0 (since 2.0 as {@code Objects.ToStringHelper}).
145   */
146  public static final class ToStringHelper {
147    @GuardedBy("ToStringHelper.class")
148    private static boolean performedJava8CompatibilityCheck;
149
150    private static void java8CompatibilityCheck() {
151      @SuppressWarnings("GuardedBy")
152      boolean racyReadForDoubleCheckedLock = performedJava8CompatibilityCheck;
153      if (racyReadForDoubleCheckedLock) {
154        return;
155      }
156      synchronized (ToStringHelper.class) {
157        if (performedJava8CompatibilityCheck) {
158          return;
159        }
160        performedJava8CompatibilityCheck = true;
161      }
162
163      try {
164        Java8Usage.performCheck();
165      } catch (Throwable underlying) {
166        Exception toLog =
167            new Exception(
168                "Guava will drop support for Java 7 in 2021. Please let us know if this will cause"
169                    + " you problems: https://github.com/google/guava/issues/5269",
170                underlying);
171        Logger.getLogger(ToStringHelper.class.getName())
172            .log(
173                WARNING,
174                "Java 7 compatibility warning: See https://github.com/google/guava/issues/5269",
175                toLog);
176      }
177    }
178
179    private final String className;
180    private final ValueHolder holderHead = new ValueHolder();
181    private ValueHolder holderTail = holderHead;
182    private boolean omitNullValues = false;
183
184    /** Use {@link MoreObjects#toStringHelper(Object)} to create an instance. */
185    private ToStringHelper(String className) {
186      java8CompatibilityCheck();
187      this.className = checkNotNull(className);
188    }
189
190    /**
191     * Configures the {@link ToStringHelper} so {@link #toString()} will ignore properties with null
192     * value. The order of calling this method, relative to the {@code add()}/{@code addValue()}
193     * methods, is not significant.
194     *
195     * @since 18.0 (since 12.0 as {@code Objects.ToStringHelper.omitNullValues()}).
196     */
197    @CanIgnoreReturnValue
198    public ToStringHelper omitNullValues() {
199      omitNullValues = true;
200      return this;
201    }
202
203    /**
204     * Adds a name/value pair to the formatted output in {@code name=value} format. If {@code value}
205     * is {@code null}, the string {@code "null"} is used, unless {@link #omitNullValues()} is
206     * called, in which case this name/value pair will not be added.
207     */
208    @CanIgnoreReturnValue
209    public ToStringHelper add(String name, @Nullable Object value) {
210      return addHolder(name, value);
211    }
212
213    /**
214     * Adds a name/value pair to the formatted output in {@code name=value} format.
215     *
216     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
217     */
218    @CanIgnoreReturnValue
219    public ToStringHelper add(String name, boolean value) {
220      return addHolder(name, String.valueOf(value));
221    }
222
223    /**
224     * Adds a name/value pair to the formatted output in {@code name=value} format.
225     *
226     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
227     */
228    @CanIgnoreReturnValue
229    public ToStringHelper add(String name, char value) {
230      return addHolder(name, String.valueOf(value));
231    }
232
233    /**
234     * Adds a name/value pair to the formatted output in {@code name=value} format.
235     *
236     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
237     */
238    @CanIgnoreReturnValue
239    public ToStringHelper add(String name, double value) {
240      return addHolder(name, String.valueOf(value));
241    }
242
243    /**
244     * Adds a name/value pair to the formatted output in {@code name=value} format.
245     *
246     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
247     */
248    @CanIgnoreReturnValue
249    public ToStringHelper add(String name, float value) {
250      return addHolder(name, String.valueOf(value));
251    }
252
253    /**
254     * Adds a name/value pair to the formatted output in {@code name=value} format.
255     *
256     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
257     */
258    @CanIgnoreReturnValue
259    public ToStringHelper add(String name, int value) {
260      return addHolder(name, String.valueOf(value));
261    }
262
263    /**
264     * Adds a name/value pair to the formatted output in {@code name=value} format.
265     *
266     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
267     */
268    @CanIgnoreReturnValue
269    public ToStringHelper add(String name, long value) {
270      return addHolder(name, String.valueOf(value));
271    }
272
273    /**
274     * Adds an unnamed value to the formatted output.
275     *
276     * <p>It is strongly encouraged to use {@link #add(String, Object)} instead and give value a
277     * readable name.
278     */
279    @CanIgnoreReturnValue
280    public ToStringHelper addValue(@Nullable Object value) {
281      return addHolder(value);
282    }
283
284    /**
285     * Adds an unnamed value to the formatted output.
286     *
287     * <p>It is strongly encouraged to use {@link #add(String, boolean)} instead and give value a
288     * readable name.
289     *
290     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
291     */
292    @CanIgnoreReturnValue
293    public ToStringHelper addValue(boolean value) {
294      return addHolder(String.valueOf(value));
295    }
296
297    /**
298     * Adds an unnamed value to the formatted output.
299     *
300     * <p>It is strongly encouraged to use {@link #add(String, char)} instead and give value a
301     * readable name.
302     *
303     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
304     */
305    @CanIgnoreReturnValue
306    public ToStringHelper addValue(char value) {
307      return addHolder(String.valueOf(value));
308    }
309
310    /**
311     * Adds an unnamed value to the formatted output.
312     *
313     * <p>It is strongly encouraged to use {@link #add(String, double)} instead and give value a
314     * readable name.
315     *
316     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
317     */
318    @CanIgnoreReturnValue
319    public ToStringHelper addValue(double value) {
320      return addHolder(String.valueOf(value));
321    }
322
323    /**
324     * Adds an unnamed value to the formatted output.
325     *
326     * <p>It is strongly encouraged to use {@link #add(String, float)} instead and give value a
327     * readable name.
328     *
329     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
330     */
331    @CanIgnoreReturnValue
332    public ToStringHelper addValue(float value) {
333      return addHolder(String.valueOf(value));
334    }
335
336    /**
337     * Adds an unnamed value to the formatted output.
338     *
339     * <p>It is strongly encouraged to use {@link #add(String, int)} instead and give value a
340     * readable name.
341     *
342     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
343     */
344    @CanIgnoreReturnValue
345    public ToStringHelper addValue(int value) {
346      return addHolder(String.valueOf(value));
347    }
348
349    /**
350     * Adds an unnamed value to the formatted output.
351     *
352     * <p>It is strongly encouraged to use {@link #add(String, long)} instead and give value a
353     * readable name.
354     *
355     * @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
356     */
357    @CanIgnoreReturnValue
358    public ToStringHelper addValue(long value) {
359      return addHolder(String.valueOf(value));
360    }
361
362    /**
363     * Returns a string in the format specified by {@link MoreObjects#toStringHelper(Object)}.
364     *
365     * <p>After calling this method, you can keep adding more properties to later call toString()
366     * again and get a more complete representation of the same object; but properties cannot be
367     * removed, so this only allows limited reuse of the helper instance. The helper allows
368     * duplication of properties (multiple name/value pairs with the same name can be added).
369     */
370    @Override
371    public String toString() {
372      // create a copy to keep it consistent in case value changes
373      boolean omitNullValuesSnapshot = omitNullValues;
374      String nextSeparator = "";
375      StringBuilder builder = new StringBuilder(32).append(className).append('{');
376      for (ValueHolder valueHolder = holderHead.next;
377          valueHolder != null;
378          valueHolder = valueHolder.next) {
379        Object value = valueHolder.value;
380        if (!omitNullValuesSnapshot || value != null) {
381          builder.append(nextSeparator);
382          nextSeparator = ", ";
383
384          if (valueHolder.name != null) {
385            builder.append(valueHolder.name).append('=');
386          }
387          if (value != null && value.getClass().isArray()) {
388            Object[] objectArray = {value};
389            String arrayString = Arrays.deepToString(objectArray);
390            builder.append(arrayString, 1, arrayString.length() - 1);
391          } else {
392            builder.append(value);
393          }
394        }
395      }
396      return builder.append('}').toString();
397    }
398
399    private ValueHolder addHolder() {
400      ValueHolder valueHolder = new ValueHolder();
401      holderTail = holderTail.next = valueHolder;
402      return valueHolder;
403    }
404
405    private ToStringHelper addHolder(@Nullable Object value) {
406      ValueHolder valueHolder = addHolder();
407      valueHolder.value = value;
408      return this;
409    }
410
411    private ToStringHelper addHolder(String name, @Nullable Object value) {
412      ValueHolder valueHolder = addHolder();
413      valueHolder.value = value;
414      valueHolder.name = checkNotNull(name);
415      return this;
416    }
417
418    private static final class ValueHolder {
419      @Nullable String name;
420      @Nullable Object value;
421      @Nullable ValueHolder next;
422    }
423  }
424
425  private MoreObjects() {}
426}