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