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 }