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    }