1 /* 2 * Copyright (C) 2012 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.testing; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static java.util.Objects.requireNonNull; 21 22 import com.google.common.annotations.GwtIncompatible; 23 import com.google.common.annotations.J2ktIncompatible; 24 import com.google.common.base.CharMatcher; 25 import com.google.common.base.Charsets; 26 import com.google.common.base.Defaults; 27 import com.google.common.base.Equivalence; 28 import com.google.common.base.Joiner; 29 import com.google.common.base.Predicate; 30 import com.google.common.base.Predicates; 31 import com.google.common.base.Splitter; 32 import com.google.common.base.Stopwatch; 33 import com.google.common.base.Ticker; 34 import com.google.common.collect.BiMap; 35 import com.google.common.collect.ClassToInstanceMap; 36 import com.google.common.collect.ImmutableBiMap; 37 import com.google.common.collect.ImmutableClassToInstanceMap; 38 import com.google.common.collect.ImmutableCollection; 39 import com.google.common.collect.ImmutableList; 40 import com.google.common.collect.ImmutableListMultimap; 41 import com.google.common.collect.ImmutableMap; 42 import com.google.common.collect.ImmutableMultimap; 43 import com.google.common.collect.ImmutableMultiset; 44 import com.google.common.collect.ImmutableSet; 45 import com.google.common.collect.ImmutableSetMultimap; 46 import com.google.common.collect.ImmutableSortedMap; 47 import com.google.common.collect.ImmutableSortedMultiset; 48 import com.google.common.collect.ImmutableSortedSet; 49 import com.google.common.collect.ImmutableTable; 50 import com.google.common.collect.Iterators; 51 import com.google.common.collect.ListMultimap; 52 import com.google.common.collect.MapDifference; 53 import com.google.common.collect.Maps; 54 import com.google.common.collect.Multimap; 55 import com.google.common.collect.Multimaps; 56 import com.google.common.collect.Multiset; 57 import com.google.common.collect.Ordering; 58 import com.google.common.collect.PeekingIterator; 59 import com.google.common.collect.Range; 60 import com.google.common.collect.RowSortedTable; 61 import com.google.common.collect.SetMultimap; 62 import com.google.common.collect.Sets; 63 import com.google.common.collect.SortedMapDifference; 64 import com.google.common.collect.SortedMultiset; 65 import com.google.common.collect.SortedSetMultimap; 66 import com.google.common.collect.Table; 67 import com.google.common.collect.Tables; 68 import com.google.common.collect.TreeBasedTable; 69 import com.google.common.collect.TreeMultimap; 70 import com.google.common.io.ByteSink; 71 import com.google.common.io.ByteSource; 72 import com.google.common.io.ByteStreams; 73 import com.google.common.io.CharSink; 74 import com.google.common.io.CharSource; 75 import com.google.common.primitives.Primitives; 76 import com.google.common.primitives.UnsignedInteger; 77 import com.google.common.primitives.UnsignedLong; 78 import com.google.errorprone.annotations.Keep; 79 import java.io.ByteArrayInputStream; 80 import java.io.ByteArrayOutputStream; 81 import java.io.File; 82 import java.io.InputStream; 83 import java.io.OutputStream; 84 import java.io.PrintStream; 85 import java.io.PrintWriter; 86 import java.io.Reader; 87 import java.io.Serializable; 88 import java.io.StringReader; 89 import java.io.StringWriter; 90 import java.io.Writer; 91 import java.lang.reflect.AnnotatedElement; 92 import java.lang.reflect.Array; 93 import java.lang.reflect.Constructor; 94 import java.lang.reflect.Field; 95 import java.lang.reflect.GenericDeclaration; 96 import java.lang.reflect.InvocationTargetException; 97 import java.lang.reflect.Modifier; 98 import java.lang.reflect.Type; 99 import java.math.BigDecimal; 100 import java.math.BigInteger; 101 import java.nio.Buffer; 102 import java.nio.ByteBuffer; 103 import java.nio.CharBuffer; 104 import java.nio.DoubleBuffer; 105 import java.nio.FloatBuffer; 106 import java.nio.IntBuffer; 107 import java.nio.LongBuffer; 108 import java.nio.ShortBuffer; 109 import java.nio.charset.Charset; 110 import java.util.ArrayDeque; 111 import java.util.Arrays; 112 import java.util.Collection; 113 import java.util.Comparator; 114 import java.util.Currency; 115 import java.util.Deque; 116 import java.util.Iterator; 117 import java.util.List; 118 import java.util.ListIterator; 119 import java.util.Locale; 120 import java.util.Map; 121 import java.util.NavigableMap; 122 import java.util.NavigableSet; 123 import java.util.Optional; 124 import java.util.OptionalDouble; 125 import java.util.OptionalInt; 126 import java.util.OptionalLong; 127 import java.util.Queue; 128 import java.util.Random; 129 import java.util.Set; 130 import java.util.SortedMap; 131 import java.util.SortedSet; 132 import java.util.UUID; 133 import java.util.concurrent.BlockingDeque; 134 import java.util.concurrent.BlockingQueue; 135 import java.util.concurrent.ConcurrentHashMap; 136 import java.util.concurrent.ConcurrentMap; 137 import java.util.concurrent.ConcurrentNavigableMap; 138 import java.util.concurrent.ConcurrentSkipListMap; 139 import java.util.concurrent.CountDownLatch; 140 import java.util.concurrent.Executor; 141 import java.util.concurrent.LinkedBlockingDeque; 142 import java.util.concurrent.ScheduledThreadPoolExecutor; 143 import java.util.concurrent.ThreadFactory; 144 import java.util.concurrent.ThreadPoolExecutor; 145 import java.util.concurrent.TimeUnit; 146 import java.util.logging.Level; 147 import java.util.logging.Logger; 148 import java.util.regex.MatchResult; 149 import java.util.regex.Matcher; 150 import java.util.regex.Pattern; 151 import java.util.stream.Stream; 152 import org.checkerframework.checker.nullness.qual.Nullable; 153 154 /** 155 * Supplies an arbitrary "default" instance for a wide range of types, often useful in testing 156 * utilities. 157 * 158 * <p>Covers arrays, enums and common types defined in {@code java.lang}, {@code java.lang.reflect}, 159 * {@code java.io}, {@code java.nio}, {@code java.math}, {@code java.util}, {@code 160 * java.util.concurrent}, {@code java.util.regex}, {@code com.google.common.base}, {@code 161 * com.google.common.collect} and {@code com.google.common.primitives}. In addition, if the type 162 * exposes at least one public static final constant of the same type, one of the constants will be 163 * used; or if the class exposes a public parameter-less constructor then it will be "new"d and 164 * returned. 165 * 166 * <p>All default instances returned by {@link #get} are generics-safe. Clients won't get type 167 * errors for using {@code get(Comparator.class)} as a {@code Comparator<Foo>}, for example. 168 * Immutable empty instances are returned for collection types; {@code ""} for string; {@code 0} for 169 * number types; reasonable default instance for other stateless types. For mutable types, a fresh 170 * instance is created each time {@code get()} is called. 171 * 172 * @author Kevin Bourrillion 173 * @author Ben Yu 174 * @since 12.0 175 */ 176 @GwtIncompatible 177 @J2ktIncompatible 178 @ElementTypesAreNonnullByDefault 179 public final class ArbitraryInstances { 180 181 private static final Ordering<Field> BY_FIELD_NAME = 182 new Ordering<Field>() { 183 @Override 184 public int compare(Field left, Field right) { 185 return left.getName().compareTo(right.getName()); 186 } 187 }; 188 189 /** 190 * Returns a new {@code MatchResult} that corresponds to a successful match. Apache Harmony (used 191 * in Android) requires a successful match in order to generate a {@code MatchResult}: 192 * http://goo.gl/5VQFmC 193 */ newMatchResult()194 private static MatchResult newMatchResult() { 195 Matcher matcher = Pattern.compile(".").matcher("X"); 196 matcher.find(); 197 return matcher.toMatchResult(); 198 } 199 200 private static final ClassToInstanceMap<Object> DEFAULTS = 201 ImmutableClassToInstanceMap.builder() 202 // primitives 203 .put(Object.class, "") 204 .put(Number.class, 0) 205 .put(UnsignedInteger.class, UnsignedInteger.ZERO) 206 .put(UnsignedLong.class, UnsignedLong.ZERO) 207 .put(BigInteger.class, BigInteger.ZERO) 208 .put(BigDecimal.class, BigDecimal.ZERO) 209 .put(CharSequence.class, "") 210 .put(String.class, "") 211 .put(Pattern.class, Pattern.compile("")) 212 .put(MatchResult.class, newMatchResult()) 213 .put(TimeUnit.class, TimeUnit.SECONDS) 214 .put(Charset.class, Charsets.UTF_8) 215 .put(Currency.class, Currency.getInstance(Locale.US)) 216 .put(Locale.class, Locale.US) 217 .put(Optional.class, Optional.empty()) 218 .put(OptionalInt.class, OptionalInt.empty()) 219 .put(OptionalLong.class, OptionalLong.empty()) 220 .put(OptionalDouble.class, OptionalDouble.empty()) 221 .put(UUID.class, UUID.randomUUID()) 222 // common.base 223 .put(CharMatcher.class, CharMatcher.none()) 224 .put(Joiner.class, Joiner.on(',')) 225 .put(Splitter.class, Splitter.on(',')) 226 .put(com.google.common.base.Optional.class, com.google.common.base.Optional.absent()) 227 .put(Predicate.class, Predicates.alwaysTrue()) 228 .put(Equivalence.class, Equivalence.equals()) 229 .put(Ticker.class, Ticker.systemTicker()) 230 .put(Stopwatch.class, Stopwatch.createUnstarted()) 231 // io types 232 .put(InputStream.class, new ByteArrayInputStream(new byte[0])) 233 .put(ByteArrayInputStream.class, new ByteArrayInputStream(new byte[0])) 234 .put(Readable.class, new StringReader("")) 235 .put(Reader.class, new StringReader("")) 236 .put(StringReader.class, new StringReader("")) 237 .put(Buffer.class, ByteBuffer.allocate(0)) 238 .put(CharBuffer.class, CharBuffer.allocate(0)) 239 .put(ByteBuffer.class, ByteBuffer.allocate(0)) 240 .put(ShortBuffer.class, ShortBuffer.allocate(0)) 241 .put(IntBuffer.class, IntBuffer.allocate(0)) 242 .put(LongBuffer.class, LongBuffer.allocate(0)) 243 .put(FloatBuffer.class, FloatBuffer.allocate(0)) 244 .put(DoubleBuffer.class, DoubleBuffer.allocate(0)) 245 .put(File.class, new File("")) 246 .put(ByteSource.class, ByteSource.empty()) 247 .put(CharSource.class, CharSource.empty()) 248 .put(ByteSink.class, NullByteSink.INSTANCE) 249 .put(CharSink.class, NullByteSink.INSTANCE.asCharSink(Charsets.UTF_8)) 250 // All collections are immutable empty. So safe for any type parameter. 251 .put(Iterator.class, ImmutableSet.of().iterator()) 252 .put(PeekingIterator.class, Iterators.peekingIterator(ImmutableSet.of().iterator())) 253 .put(ListIterator.class, ImmutableList.of().listIterator()) 254 .put(Iterable.class, ImmutableSet.of()) 255 .put(Collection.class, ImmutableList.of()) 256 .put(ImmutableCollection.class, ImmutableList.of()) 257 .put(List.class, ImmutableList.of()) 258 .put(ImmutableList.class, ImmutableList.of()) 259 .put(Set.class, ImmutableSet.of()) 260 .put(ImmutableSet.class, ImmutableSet.of()) 261 .put(SortedSet.class, ImmutableSortedSet.of()) 262 .put(ImmutableSortedSet.class, ImmutableSortedSet.of()) 263 .put(NavigableSet.class, Sets.unmodifiableNavigableSet(Sets.newTreeSet())) 264 .put(Map.class, ImmutableMap.of()) 265 .put(ImmutableMap.class, ImmutableMap.of()) 266 .put(SortedMap.class, ImmutableSortedMap.of()) 267 .put(ImmutableSortedMap.class, ImmutableSortedMap.of()) 268 .put(NavigableMap.class, Maps.unmodifiableNavigableMap(Maps.newTreeMap())) 269 .put(Multimap.class, ImmutableMultimap.of()) 270 .put(ImmutableMultimap.class, ImmutableMultimap.of()) 271 .put(ListMultimap.class, ImmutableListMultimap.of()) 272 .put(ImmutableListMultimap.class, ImmutableListMultimap.of()) 273 .put(SetMultimap.class, ImmutableSetMultimap.of()) 274 .put(ImmutableSetMultimap.class, ImmutableSetMultimap.of()) 275 .put( 276 SortedSetMultimap.class, 277 Multimaps.unmodifiableSortedSetMultimap(TreeMultimap.create())) 278 .put(Multiset.class, ImmutableMultiset.of()) 279 .put(ImmutableMultiset.class, ImmutableMultiset.of()) 280 .put(SortedMultiset.class, ImmutableSortedMultiset.of()) 281 .put(ImmutableSortedMultiset.class, ImmutableSortedMultiset.of()) 282 .put(BiMap.class, ImmutableBiMap.of()) 283 .put(ImmutableBiMap.class, ImmutableBiMap.of()) 284 .put(Table.class, ImmutableTable.of()) 285 .put(ImmutableTable.class, ImmutableTable.of()) 286 .put(RowSortedTable.class, Tables.unmodifiableRowSortedTable(TreeBasedTable.create())) 287 .put(ClassToInstanceMap.class, ImmutableClassToInstanceMap.builder().build()) 288 .put(ImmutableClassToInstanceMap.class, ImmutableClassToInstanceMap.builder().build()) 289 .put(Comparable.class, ByToString.INSTANCE) 290 .put(Comparator.class, AlwaysEqual.INSTANCE) 291 .put(Ordering.class, AlwaysEqual.INSTANCE) 292 .put(Range.class, Range.all()) 293 .put(MapDifference.class, Maps.difference(ImmutableMap.of(), ImmutableMap.of())) 294 .put( 295 SortedMapDifference.class, 296 Maps.difference(ImmutableSortedMap.of(), ImmutableSortedMap.of())) 297 // reflect 298 .put(AnnotatedElement.class, Object.class) 299 .put(GenericDeclaration.class, Object.class) 300 .put(Type.class, Object.class) 301 .build(); 302 303 /** 304 * type → implementation. Inherently mutable interfaces and abstract classes are mapped to their 305 * default implementations and are "new"d upon get(). 306 */ 307 private static final ConcurrentMap<Class<?>, Class<?>> implementations = Maps.newConcurrentMap(); 308 setImplementation(Class<T> type, Class<? extends T> implementation)309 private static <T> void setImplementation(Class<T> type, Class<? extends T> implementation) { 310 checkArgument(type != implementation, "Don't register %s to itself!", type); 311 checkArgument( 312 !DEFAULTS.containsKey(type), "A default value was already registered for %s", type); 313 checkArgument( 314 implementations.put(type, implementation) == null, 315 "Implementation for %s was already registered", 316 type); 317 } 318 319 static { setImplementation(Appendable.class, StringBuilder.class)320 setImplementation(Appendable.class, StringBuilder.class); setImplementation(BlockingQueue.class, LinkedBlockingDeque.class)321 setImplementation(BlockingQueue.class, LinkedBlockingDeque.class); setImplementation(BlockingDeque.class, LinkedBlockingDeque.class)322 setImplementation(BlockingDeque.class, LinkedBlockingDeque.class); setImplementation(ConcurrentMap.class, ConcurrentHashMap.class)323 setImplementation(ConcurrentMap.class, ConcurrentHashMap.class); setImplementation(ConcurrentNavigableMap.class, ConcurrentSkipListMap.class)324 setImplementation(ConcurrentNavigableMap.class, ConcurrentSkipListMap.class); setImplementation(CountDownLatch.class, Dummies.DummyCountDownLatch.class)325 setImplementation(CountDownLatch.class, Dummies.DummyCountDownLatch.class); setImplementation(Deque.class, ArrayDeque.class)326 setImplementation(Deque.class, ArrayDeque.class); setImplementation(OutputStream.class, ByteArrayOutputStream.class)327 setImplementation(OutputStream.class, ByteArrayOutputStream.class); setImplementation(PrintStream.class, Dummies.InMemoryPrintStream.class)328 setImplementation(PrintStream.class, Dummies.InMemoryPrintStream.class); setImplementation(PrintWriter.class, Dummies.InMemoryPrintWriter.class)329 setImplementation(PrintWriter.class, Dummies.InMemoryPrintWriter.class); setImplementation(Queue.class, ArrayDeque.class)330 setImplementation(Queue.class, ArrayDeque.class); setImplementation(Random.class, Dummies.DeterministicRandom.class)331 setImplementation(Random.class, Dummies.DeterministicRandom.class); setImplementation( ScheduledThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class)332 setImplementation( 333 ScheduledThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class); setImplementation(ThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class)334 setImplementation(ThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class); setImplementation(Writer.class, StringWriter.class)335 setImplementation(Writer.class, StringWriter.class); setImplementation(Runnable.class, Dummies.DummyRunnable.class)336 setImplementation(Runnable.class, Dummies.DummyRunnable.class); setImplementation(ThreadFactory.class, Dummies.DummyThreadFactory.class)337 setImplementation(ThreadFactory.class, Dummies.DummyThreadFactory.class); setImplementation(Executor.class, Dummies.DummyExecutor.class)338 setImplementation(Executor.class, Dummies.DummyExecutor.class); 339 } 340 341 @SuppressWarnings("unchecked") // it's a subtype map getImplementation(Class<T> type)342 private static <T> @Nullable Class<? extends T> getImplementation(Class<T> type) { 343 return (Class<? extends T>) implementations.get(type); 344 } 345 346 private static final Logger logger = Logger.getLogger(ArbitraryInstances.class.getName()); 347 348 /** 349 * Returns an arbitrary instance for {@code type}, or {@code null} if no arbitrary instance can be 350 * determined. 351 */ get(Class<T> type)352 public static <T> @Nullable T get(Class<T> type) { 353 T defaultValue = DEFAULTS.getInstance(type); 354 if (defaultValue != null) { 355 return defaultValue; 356 } 357 Class<? extends T> implementation = getImplementation(type); 358 if (implementation != null) { 359 return get(implementation); 360 } 361 if (type == Stream.class) { 362 return type.cast(Stream.empty()); 363 } 364 if (type.isEnum()) { 365 T[] enumConstants = type.getEnumConstants(); 366 return (enumConstants == null || enumConstants.length == 0) ? null : enumConstants[0]; 367 } 368 if (type.isArray()) { 369 return createEmptyArray(type); 370 } 371 T jvmDefault = Defaults.defaultValue(Primitives.unwrap(type)); 372 if (jvmDefault != null) { 373 return jvmDefault; 374 } 375 if (Modifier.isAbstract(type.getModifiers()) || !Modifier.isPublic(type.getModifiers())) { 376 return arbitraryConstantInstanceOrNull(type); 377 } 378 final Constructor<T> constructor; 379 try { 380 constructor = type.getConstructor(); 381 } catch (NoSuchMethodException e) { 382 return arbitraryConstantInstanceOrNull(type); 383 } 384 constructor.setAccessible(true); // accessibility check is too slow 385 try { 386 return constructor.newInstance(); 387 /* 388 * Do not merge the 2 catch blocks below. javac would infer a type of 389 * ReflectiveOperationException, which Animal Sniffer would reject. (Old versions of 390 * Android don't *seem* to mind, but there might be edge cases of which we're unaware.) 391 */ 392 } catch (InstantiationException impossible) { 393 throw new AssertionError(impossible); 394 } catch (IllegalAccessException impossible) { 395 throw new AssertionError(impossible); 396 } catch (InvocationTargetException e) { 397 logger.log(Level.WARNING, "Exception while invoking default constructor.", e.getCause()); 398 return arbitraryConstantInstanceOrNull(type); 399 } 400 } 401 arbitraryConstantInstanceOrNull(Class<T> type)402 private static <T> @Nullable T arbitraryConstantInstanceOrNull(Class<T> type) { 403 Field[] fields = type.getDeclaredFields(); 404 Arrays.sort(fields, BY_FIELD_NAME); 405 for (Field field : fields) { 406 if (Modifier.isPublic(field.getModifiers()) 407 && Modifier.isStatic(field.getModifiers()) 408 && Modifier.isFinal(field.getModifiers())) { 409 if (field.getGenericType() == field.getType() && type.isAssignableFrom(field.getType())) { 410 field.setAccessible(true); 411 try { 412 T constant = type.cast(field.get(null)); 413 if (constant != null) { 414 return constant; 415 } 416 } catch (IllegalAccessException impossible) { 417 throw new AssertionError(impossible); 418 } 419 } 420 } 421 } 422 return null; 423 } 424 createEmptyArray(Class<T> arrayType)425 private static <T> T createEmptyArray(Class<T> arrayType) { 426 // getComponentType() is non-null because we call createEmptyArray only with an array type. 427 return arrayType.cast(Array.newInstance(requireNonNull(arrayType.getComponentType()), 0)); 428 } 429 430 // Internal implementations of some classes, with public default constructor that get() needs. 431 private static final class Dummies { 432 433 public static final class InMemoryPrintStream extends PrintStream { InMemoryPrintStream()434 public InMemoryPrintStream() { 435 super(new ByteArrayOutputStream()); 436 } 437 } 438 439 public static final class InMemoryPrintWriter extends PrintWriter { InMemoryPrintWriter()440 public InMemoryPrintWriter() { 441 super(new StringWriter()); 442 } 443 } 444 445 public static final class DeterministicRandom extends Random { 446 @Keep DeterministicRandom()447 public DeterministicRandom() { 448 super(0); 449 } 450 } 451 452 public static final class DummyScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor { DummyScheduledThreadPoolExecutor()453 public DummyScheduledThreadPoolExecutor() { 454 super(1); 455 } 456 } 457 458 public static final class DummyCountDownLatch extends CountDownLatch { DummyCountDownLatch()459 public DummyCountDownLatch() { 460 super(0); 461 } 462 } 463 464 public static final class DummyRunnable implements Runnable, Serializable { 465 @Override run()466 public void run() {} 467 } 468 469 public static final class DummyThreadFactory implements ThreadFactory, Serializable { 470 @Override newThread(Runnable r)471 public Thread newThread(Runnable r) { 472 return new Thread(r); 473 } 474 } 475 476 public static final class DummyExecutor implements Executor, Serializable { 477 @Override execute(Runnable command)478 public void execute(Runnable command) {} 479 } 480 } 481 482 private static final class NullByteSink extends ByteSink implements Serializable { 483 private static final NullByteSink INSTANCE = new NullByteSink(); 484 485 @Override openStream()486 public OutputStream openStream() { 487 return ByteStreams.nullOutputStream(); 488 } 489 } 490 491 // Compare by toString() to satisfy 2 properties: 492 // 1. compareTo(null) should throw NullPointerException 493 // 2. the order is deterministic and easy to understand, for debugging purpose. 494 @SuppressWarnings("ComparableType") 495 private static final class ByToString implements Comparable<Object>, Serializable { 496 private static final ByToString INSTANCE = new ByToString(); 497 498 @Override compareTo(Object o)499 public int compareTo(Object o) { 500 return toString().compareTo(o.toString()); 501 } 502 503 @Override toString()504 public String toString() { 505 return "BY_TO_STRING"; 506 } 507 readResolve()508 private Object readResolve() { 509 return INSTANCE; 510 } 511 } 512 513 // Always equal is a valid total ordering. And it works for any Object. 514 private static final class AlwaysEqual extends Ordering<@Nullable Object> 515 implements Serializable { 516 private static final AlwaysEqual INSTANCE = new AlwaysEqual(); 517 518 @Override compare(@ullable Object o1, @Nullable Object o2)519 public int compare(@Nullable Object o1, @Nullable Object o2) { 520 return 0; 521 } 522 523 @Override toString()524 public String toString() { 525 return "ALWAYS_EQUAL"; 526 } 527 readResolve()528 private Object readResolve() { 529 return INSTANCE; 530 } 531 } 532 ArbitraryInstances()533 private ArbitraryInstances() {} 534 } 535