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          checkNameAndAppend(name).append(value);
202          return this;
203        }
204    
205        /**
206         * Adds a name/value pair to the formatted output in {@code name=value}
207         * format.
208         *
209         * @since 11.0 (source-compatible since 2.0)
210         */
211        public ToStringHelper add(String name, boolean value) {
212          checkNameAndAppend(name).append(value);
213          return this;
214        }
215    
216        /**
217         * Adds a name/value pair to the formatted output in {@code name=value}
218         * format.
219         *
220         * @since 11.0 (source-compatible since 2.0)
221         */
222        public ToStringHelper add(String name, char value) {
223          checkNameAndAppend(name).append(value);
224          return this;
225        }
226    
227        /**
228         * Adds a name/value pair to the formatted output in {@code name=value}
229         * format.
230         *
231         * @since 11.0 (source-compatible since 2.0)
232         */
233        public ToStringHelper add(String name, double value) {
234          checkNameAndAppend(name).append(value);
235          return this;
236        }
237    
238        /**
239         * Adds a name/value pair to the formatted output in {@code name=value}
240         * format.
241         *
242         * @since 11.0 (source-compatible since 2.0)
243         */
244        public ToStringHelper add(String name, float value) {
245          checkNameAndAppend(name).append(value);
246          return this;
247        }
248    
249        /**
250         * Adds a name/value pair to the formatted output in {@code name=value}
251         * format.
252         *
253         * @since 11.0 (source-compatible since 2.0)
254         */
255        public ToStringHelper add(String name, int value) {
256          checkNameAndAppend(name).append(value);
257          return this;
258        }
259    
260        /**
261         * Adds a name/value pair to the formatted output in {@code name=value}
262         * format.
263         *
264         * @since 11.0 (source-compatible since 2.0)
265         */
266        public ToStringHelper add(String name, long value) {
267          checkNameAndAppend(name).append(value);
268          return this;
269        }
270    
271        private StringBuilder checkNameAndAppend(String name) {
272          checkNotNull(name);
273          return maybeAppendSeparator().append(name).append('=');
274        }
275    
276        /**
277         * Adds an unnamed value to the formatted output.
278         *
279         * <p>It is strongly encouraged to use {@link #add(String, Object)} instead
280         * and give value a readable name.
281         */
282        public ToStringHelper addValue(@Nullable Object value) {
283          maybeAppendSeparator().append(value);
284          return this;
285        }
286    
287        /**
288         * Adds an unnamed value to the formatted output.
289         *
290         * <p>It is strongly encouraged to use {@link #add(String, boolean)} instead
291         * and give value a readable name.
292         *
293         * @since 11.0 (source-compatible since 2.0)
294         */
295        public ToStringHelper addValue(boolean value) {
296          maybeAppendSeparator().append(value);
297          return this;
298        }
299    
300        /**
301         * Adds an unnamed value to the formatted output.
302         *
303         * <p>It is strongly encouraged to use {@link #add(String, char)} instead
304         * and give value a readable name.
305         *
306         * @since 11.0 (source-compatible since 2.0)
307         */
308        public ToStringHelper addValue(char value) {
309          maybeAppendSeparator().append(value);
310          return this;
311        }
312    
313        /**
314         * Adds an unnamed value to the formatted output.
315         *
316         * <p>It is strongly encouraged to use {@link #add(String, double)} instead
317         * and give value a readable name.
318         *
319         * @since 11.0 (source-compatible since 2.0)
320         */
321        public ToStringHelper addValue(double value) {
322          maybeAppendSeparator().append(value);
323          return this;
324        }
325    
326        /**
327         * Adds an unnamed value to the formatted output.
328         *
329         * <p>It is strongly encouraged to use {@link #add(String, float)} instead
330         * and give value a readable name.
331         *
332         * @since 11.0 (source-compatible since 2.0)
333         */
334        public ToStringHelper addValue(float value) {
335          maybeAppendSeparator().append(value);
336          return this;
337        }
338    
339        /**
340         * Adds an unnamed value to the formatted output.
341         *
342         * <p>It is strongly encouraged to use {@link #add(String, int)} instead
343         * and give value a readable name.
344         *
345         * @since 11.0 (source-compatible since 2.0)
346         */
347        public ToStringHelper addValue(int value) {
348          maybeAppendSeparator().append(value);
349          return this;
350        }
351    
352        /**
353         * Adds an unnamed value to the formatted output.
354         *
355         * <p>It is strongly encouraged to use {@link #add(String, long)} instead
356         * and give value a readable name.
357         *
358         * @since 11.0 (source-compatible since 2.0)
359         */
360        public ToStringHelper addValue(long value) {
361          maybeAppendSeparator().append(value);
362          return this;
363        }
364    
365        /**
366         * Returns a string in the format specified by {@link
367         * Objects#toStringHelper(Object)}.
368         */
369        @Override public String toString() {
370          try {
371            return builder.append('}').toString();
372          } finally {
373            // Slice off the closing brace in case there are additional calls to
374            // #add or #addValue.
375            builder.setLength(builder.length() - 1);
376          }
377        }
378    
379        private StringBuilder maybeAppendSeparator() {
380          if (needsSeparator) {
381            return builder.append(", ");
382          } else {
383            needsSeparator = true;
384            return builder;
385          }
386        }
387      }
388    }