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}