001/* 002 * Copyright (C) 2012 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 017package com.google.common.testing; 018 019import static com.google.common.base.Preconditions.checkArgument; 020import static java.nio.charset.StandardCharsets.UTF_8; 021import static java.util.Objects.requireNonNull; 022import static java.util.concurrent.TimeUnit.SECONDS; 023 024import com.google.common.annotations.GwtIncompatible; 025import com.google.common.annotations.J2ktIncompatible; 026import com.google.common.base.CharMatcher; 027import com.google.common.base.Defaults; 028import com.google.common.base.Equivalence; 029import com.google.common.base.Joiner; 030import com.google.common.base.Predicate; 031import com.google.common.base.Predicates; 032import com.google.common.base.Splitter; 033import com.google.common.base.Stopwatch; 034import com.google.common.base.Ticker; 035import com.google.common.collect.BiMap; 036import com.google.common.collect.ClassToInstanceMap; 037import com.google.common.collect.ImmutableBiMap; 038import com.google.common.collect.ImmutableClassToInstanceMap; 039import com.google.common.collect.ImmutableCollection; 040import com.google.common.collect.ImmutableList; 041import com.google.common.collect.ImmutableListMultimap; 042import com.google.common.collect.ImmutableMap; 043import com.google.common.collect.ImmutableMultimap; 044import com.google.common.collect.ImmutableMultiset; 045import com.google.common.collect.ImmutableSet; 046import com.google.common.collect.ImmutableSetMultimap; 047import com.google.common.collect.ImmutableSortedMap; 048import com.google.common.collect.ImmutableSortedMultiset; 049import com.google.common.collect.ImmutableSortedSet; 050import com.google.common.collect.ImmutableTable; 051import com.google.common.collect.Iterators; 052import com.google.common.collect.ListMultimap; 053import com.google.common.collect.MapDifference; 054import com.google.common.collect.Maps; 055import com.google.common.collect.Multimap; 056import com.google.common.collect.Multimaps; 057import com.google.common.collect.Multiset; 058import com.google.common.collect.Ordering; 059import com.google.common.collect.PeekingIterator; 060import com.google.common.collect.Range; 061import com.google.common.collect.RowSortedTable; 062import com.google.common.collect.SetMultimap; 063import com.google.common.collect.Sets; 064import com.google.common.collect.SortedMapDifference; 065import com.google.common.collect.SortedMultiset; 066import com.google.common.collect.SortedSetMultimap; 067import com.google.common.collect.Table; 068import com.google.common.collect.Tables; 069import com.google.common.collect.TreeBasedTable; 070import com.google.common.collect.TreeMultimap; 071import com.google.common.io.ByteSink; 072import com.google.common.io.ByteSource; 073import com.google.common.io.ByteStreams; 074import com.google.common.io.CharSink; 075import com.google.common.io.CharSource; 076import com.google.common.primitives.Primitives; 077import com.google.common.primitives.UnsignedInteger; 078import com.google.common.primitives.UnsignedLong; 079import com.google.errorprone.annotations.Keep; 080import java.io.ByteArrayInputStream; 081import java.io.ByteArrayOutputStream; 082import java.io.File; 083import java.io.InputStream; 084import java.io.OutputStream; 085import java.io.PrintStream; 086import java.io.PrintWriter; 087import java.io.Reader; 088import java.io.Serializable; 089import java.io.StringReader; 090import java.io.StringWriter; 091import java.io.Writer; 092import java.lang.reflect.AnnotatedElement; 093import java.lang.reflect.Array; 094import java.lang.reflect.Constructor; 095import java.lang.reflect.Field; 096import java.lang.reflect.GenericDeclaration; 097import java.lang.reflect.InvocationTargetException; 098import java.lang.reflect.Modifier; 099import java.lang.reflect.Type; 100import java.math.BigDecimal; 101import java.math.BigInteger; 102import java.nio.Buffer; 103import java.nio.ByteBuffer; 104import java.nio.CharBuffer; 105import java.nio.DoubleBuffer; 106import java.nio.FloatBuffer; 107import java.nio.IntBuffer; 108import java.nio.LongBuffer; 109import java.nio.ShortBuffer; 110import java.nio.charset.Charset; 111import java.util.ArrayDeque; 112import java.util.Arrays; 113import java.util.Collection; 114import java.util.Comparator; 115import java.util.Currency; 116import java.util.Deque; 117import java.util.Iterator; 118import java.util.List; 119import java.util.ListIterator; 120import java.util.Locale; 121import java.util.Map; 122import java.util.NavigableMap; 123import java.util.NavigableSet; 124import java.util.Queue; 125import java.util.Random; 126import java.util.Set; 127import java.util.SortedMap; 128import java.util.SortedSet; 129import java.util.UUID; 130import java.util.concurrent.BlockingDeque; 131import java.util.concurrent.BlockingQueue; 132import java.util.concurrent.ConcurrentHashMap; 133import java.util.concurrent.ConcurrentMap; 134import java.util.concurrent.ConcurrentNavigableMap; 135import java.util.concurrent.ConcurrentSkipListMap; 136import java.util.concurrent.CountDownLatch; 137import java.util.concurrent.Executor; 138import java.util.concurrent.LinkedBlockingDeque; 139import java.util.concurrent.ScheduledThreadPoolExecutor; 140import java.util.concurrent.ThreadFactory; 141import java.util.concurrent.ThreadPoolExecutor; 142import java.util.concurrent.TimeUnit; 143import java.util.logging.Level; 144import java.util.logging.Logger; 145import java.util.regex.MatchResult; 146import java.util.regex.Matcher; 147import java.util.regex.Pattern; 148import org.jspecify.annotations.NullMarked; 149import org.checkerframework.checker.nullness.qual.Nullable; 150 151/** 152 * Supplies an arbitrary "default" instance for a wide range of types, often useful in testing 153 * utilities. 154 * 155 * <p>Covers arrays, enums and common types defined in {@code java.lang}, {@code java.lang.reflect}, 156 * {@code java.io}, {@code java.nio}, {@code java.math}, {@code java.util}, {@code 157 * java.util.concurrent}, {@code java.util.regex}, {@code com.google.common.base}, {@code 158 * com.google.common.collect} and {@code com.google.common.primitives}. In addition, if the type 159 * exposes at least one public static final constant of the same type, one of the constants will be 160 * used; or if the class exposes a public parameter-less constructor then it will be "new"d and 161 * returned. 162 * 163 * <p>All default instances returned by {@link #get} are generics-safe. Clients won't get type 164 * errors for using {@code get(Comparator.class)} as a {@code Comparator<Foo>}, for example. 165 * Immutable empty instances are returned for collection types; {@code ""} for string; {@code 0} for 166 * number types; reasonable default instance for other stateless types. For mutable types, a fresh 167 * instance is created each time {@code get()} is called. 168 * 169 * @author Kevin Bourrillion 170 * @author Ben Yu 171 * @since 12.0 172 */ 173@GwtIncompatible 174@J2ktIncompatible 175@NullMarked 176public final class ArbitraryInstances { 177 178 private static final Ordering<Field> BY_FIELD_NAME = 179 new Ordering<Field>() { 180 @Override 181 public int compare(Field left, Field right) { 182 return left.getName().compareTo(right.getName()); 183 } 184 }; 185 186 /** 187 * Returns a new {@code MatchResult} that corresponds to a successful match. Apache Harmony (used 188 * in Android) requires a successful match in order to generate a {@code MatchResult}: 189 * https://cs.android.com/android/platform/superproject/+/android-2.3.7_r1:libcore/luni/src/main/java/java/util/regex/Matcher.java;l=550;drc=5850271b4ab93ebc27c1d49169a348c6be3c7f04 190 */ 191 private static MatchResult createMatchResult() { 192 Matcher matcher = Pattern.compile(".").matcher("X"); 193 matcher.find(); 194 return matcher.toMatchResult(); 195 } 196 197 private static final ClassToInstanceMap<Object> DEFAULTS = 198 ImmutableClassToInstanceMap.builder() 199 // primitives 200 .put(Object.class, "") 201 .put(Number.class, 0) 202 .put(UnsignedInteger.class, UnsignedInteger.ZERO) 203 .put(UnsignedLong.class, UnsignedLong.ZERO) 204 .put(BigInteger.class, BigInteger.ZERO) 205 .put(BigDecimal.class, BigDecimal.ZERO) 206 .put(CharSequence.class, "") 207 .put(String.class, "") 208 .put(Pattern.class, Pattern.compile("")) 209 .put(MatchResult.class, createMatchResult()) 210 .put(TimeUnit.class, SECONDS) 211 .put(Charset.class, UTF_8) 212 .put(Currency.class, Currency.getInstance(Locale.US)) 213 .put(Locale.class, Locale.US) 214 .put(UUID.class, UUID.randomUUID()) 215 // common.base 216 .put(CharMatcher.class, CharMatcher.none()) 217 .put(Joiner.class, Joiner.on(',')) 218 .put(Splitter.class, Splitter.on(',')) 219 .put(com.google.common.base.Optional.class, com.google.common.base.Optional.absent()) 220 .put(Predicate.class, Predicates.alwaysTrue()) 221 .put(Equivalence.class, Equivalence.equals()) 222 .put(Ticker.class, Ticker.systemTicker()) 223 .put(Stopwatch.class, Stopwatch.createUnstarted()) 224 // io types 225 .put(InputStream.class, new ByteArrayInputStream(new byte[0])) 226 .put(ByteArrayInputStream.class, new ByteArrayInputStream(new byte[0])) 227 .put(Readable.class, new StringReader("")) 228 .put(Reader.class, new StringReader("")) 229 .put(StringReader.class, new StringReader("")) 230 .put(Buffer.class, ByteBuffer.allocate(0)) 231 .put(CharBuffer.class, CharBuffer.allocate(0)) 232 .put(ByteBuffer.class, ByteBuffer.allocate(0)) 233 .put(ShortBuffer.class, ShortBuffer.allocate(0)) 234 .put(IntBuffer.class, IntBuffer.allocate(0)) 235 .put(LongBuffer.class, LongBuffer.allocate(0)) 236 .put(FloatBuffer.class, FloatBuffer.allocate(0)) 237 .put(DoubleBuffer.class, DoubleBuffer.allocate(0)) 238 .put(File.class, new File("")) 239 .put(ByteSource.class, ByteSource.empty()) 240 .put(CharSource.class, CharSource.empty()) 241 .put(ByteSink.class, NullByteSink.INSTANCE) 242 .put(CharSink.class, NullByteSink.INSTANCE.asCharSink(UTF_8)) 243 // All collections are immutable empty. So safe for any type parameter. 244 .put(Iterator.class, ImmutableSet.of().iterator()) 245 .put(PeekingIterator.class, Iterators.peekingIterator(ImmutableSet.of().iterator())) 246 .put(ListIterator.class, ImmutableList.of().listIterator()) 247 .put(Iterable.class, ImmutableSet.of()) 248 .put(Collection.class, ImmutableList.of()) 249 .put(ImmutableCollection.class, ImmutableList.of()) 250 .put(List.class, ImmutableList.of()) 251 .put(ImmutableList.class, ImmutableList.of()) 252 .put(Set.class, ImmutableSet.of()) 253 .put(ImmutableSet.class, ImmutableSet.of()) 254 .put(SortedSet.class, ImmutableSortedSet.of()) 255 .put(ImmutableSortedSet.class, ImmutableSortedSet.of()) 256 .put(NavigableSet.class, Sets.unmodifiableNavigableSet(Sets.newTreeSet())) 257 .put(Map.class, ImmutableMap.of()) 258 .put(ImmutableMap.class, ImmutableMap.of()) 259 .put(SortedMap.class, ImmutableSortedMap.of()) 260 .put(ImmutableSortedMap.class, ImmutableSortedMap.of()) 261 .put(NavigableMap.class, Maps.unmodifiableNavigableMap(Maps.newTreeMap())) 262 .put(Multimap.class, ImmutableMultimap.of()) 263 .put(ImmutableMultimap.class, ImmutableMultimap.of()) 264 .put(ListMultimap.class, ImmutableListMultimap.of()) 265 .put(ImmutableListMultimap.class, ImmutableListMultimap.of()) 266 .put(SetMultimap.class, ImmutableSetMultimap.of()) 267 .put(ImmutableSetMultimap.class, ImmutableSetMultimap.of()) 268 .put( 269 SortedSetMultimap.class, 270 Multimaps.unmodifiableSortedSetMultimap(TreeMultimap.create())) 271 .put(Multiset.class, ImmutableMultiset.of()) 272 .put(ImmutableMultiset.class, ImmutableMultiset.of()) 273 .put(SortedMultiset.class, ImmutableSortedMultiset.of()) 274 .put(ImmutableSortedMultiset.class, ImmutableSortedMultiset.of()) 275 .put(BiMap.class, ImmutableBiMap.of()) 276 .put(ImmutableBiMap.class, ImmutableBiMap.of()) 277 .put(Table.class, ImmutableTable.of()) 278 .put(ImmutableTable.class, ImmutableTable.of()) 279 .put(RowSortedTable.class, Tables.unmodifiableRowSortedTable(TreeBasedTable.create())) 280 .put(ClassToInstanceMap.class, ImmutableClassToInstanceMap.builder().build()) 281 .put(ImmutableClassToInstanceMap.class, ImmutableClassToInstanceMap.builder().build()) 282 .put(Comparable.class, ByToString.INSTANCE) 283 .put(Comparator.class, AlwaysEqual.INSTANCE) 284 .put(Ordering.class, AlwaysEqual.INSTANCE) 285 .put(Range.class, Range.all()) 286 .put(MapDifference.class, Maps.difference(ImmutableMap.of(), ImmutableMap.of())) 287 .put( 288 SortedMapDifference.class, 289 Maps.difference(ImmutableSortedMap.of(), ImmutableSortedMap.of())) 290 // reflect 291 .put(AnnotatedElement.class, Object.class) 292 .put(GenericDeclaration.class, Object.class) 293 .put(Type.class, Object.class) 294 .build(); 295 296 /** 297 * type → implementation. Inherently mutable interfaces and abstract classes are mapped to their 298 * default implementations and are "new"d upon get(). 299 */ 300 private static final ConcurrentMap<Class<?>, Class<?>> implementations = Maps.newConcurrentMap(); 301 302 private static <T> void setImplementation(Class<T> type, Class<? extends T> implementation) { 303 checkArgument(type != implementation, "Don't register %s to itself!", type); 304 checkArgument( 305 !DEFAULTS.containsKey(type), "A default value was already registered for %s", type); 306 checkArgument( 307 implementations.put(type, implementation) == null, 308 "Implementation for %s was already registered", 309 type); 310 } 311 312 static { 313 setImplementation(Appendable.class, StringBuilder.class); 314 setImplementation(BlockingQueue.class, LinkedBlockingDeque.class); 315 setImplementation(BlockingDeque.class, LinkedBlockingDeque.class); 316 setImplementation(ConcurrentMap.class, ConcurrentHashMap.class); 317 setImplementation(ConcurrentNavigableMap.class, ConcurrentSkipListMap.class); 318 setImplementation(CountDownLatch.class, Dummies.DummyCountDownLatch.class); 319 setImplementation(Deque.class, ArrayDeque.class); 320 setImplementation(OutputStream.class, ByteArrayOutputStream.class); 321 setImplementation(PrintStream.class, Dummies.InMemoryPrintStream.class); 322 setImplementation(PrintWriter.class, Dummies.InMemoryPrintWriter.class); 323 setImplementation(Queue.class, ArrayDeque.class); 324 setImplementation(Random.class, Dummies.DeterministicRandom.class); 325 setImplementation( 326 ScheduledThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class); 327 setImplementation(ThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class); 328 setImplementation(Writer.class, StringWriter.class); 329 setImplementation(Runnable.class, Dummies.DummyRunnable.class); 330 setImplementation(ThreadFactory.class, Dummies.DummyThreadFactory.class); 331 setImplementation(Executor.class, Dummies.DummyExecutor.class); 332 } 333 334 @SuppressWarnings("unchecked") // it's a subtype map 335 private static <T> @Nullable Class<? extends T> getImplementation(Class<T> type) { 336 return (Class<? extends T>) implementations.get(type); 337 } 338 339 private static final Logger logger = Logger.getLogger(ArbitraryInstances.class.getName()); 340 341 /** 342 * Returns an arbitrary instance for {@code type}, or {@code null} if no arbitrary instance can be 343 * determined. 344 */ 345 public static <T> @Nullable T get(Class<T> type) { 346 T defaultValue = DEFAULTS.getInstance(type); 347 if (defaultValue != null) { 348 return defaultValue; 349 } 350 Class<? extends T> implementation = getImplementation(type); 351 if (implementation != null) { 352 return get(implementation); 353 } 354 if (type.isEnum()) { 355 T[] enumConstants = type.getEnumConstants(); 356 return (enumConstants == null || enumConstants.length == 0) ? null : enumConstants[0]; 357 } 358 if (type.isArray()) { 359 return createEmptyArray(type); 360 } 361 T jvmDefault = Defaults.defaultValue(Primitives.unwrap(type)); 362 if (jvmDefault != null) { 363 return jvmDefault; 364 } 365 if (Modifier.isAbstract(type.getModifiers()) || !Modifier.isPublic(type.getModifiers())) { 366 return arbitraryConstantInstanceOrNull(type); 367 } 368 final Constructor<T> constructor; 369 try { 370 constructor = type.getConstructor(); 371 } catch (NoSuchMethodException e) { 372 return arbitraryConstantInstanceOrNull(type); 373 } 374 constructor.setAccessible(true); // accessibility check is too slow 375 try { 376 return constructor.newInstance(); 377 } catch (InstantiationException | IllegalAccessException impossible) { 378 throw new AssertionError(impossible); 379 } catch (InvocationTargetException e) { 380 logger.log(Level.WARNING, "Exception while invoking default constructor.", e.getCause()); 381 return arbitraryConstantInstanceOrNull(type); 382 } 383 } 384 385 private static <T> @Nullable T arbitraryConstantInstanceOrNull(Class<T> type) { 386 Field[] fields = type.getDeclaredFields(); 387 Arrays.sort(fields, BY_FIELD_NAME); 388 for (Field field : fields) { 389 if (Modifier.isPublic(field.getModifiers()) 390 && Modifier.isStatic(field.getModifiers()) 391 && Modifier.isFinal(field.getModifiers())) { 392 if (field.getGenericType() == field.getType() && type.isAssignableFrom(field.getType())) { 393 field.setAccessible(true); 394 try { 395 T constant = type.cast(field.get(null)); 396 if (constant != null) { 397 return constant; 398 } 399 } catch (IllegalAccessException impossible) { 400 throw new AssertionError(impossible); 401 } 402 } 403 } 404 } 405 return null; 406 } 407 408 private static <T> T createEmptyArray(Class<T> arrayType) { 409 // getComponentType() is non-null because we call createEmptyArray only with an array type. 410 return arrayType.cast(Array.newInstance(requireNonNull(arrayType.getComponentType()), 0)); 411 } 412 413 // Internal implementations of some classes, with public default constructor that get() needs. 414 private static final class Dummies { 415 416 public static final class InMemoryPrintStream extends PrintStream { 417 public InMemoryPrintStream() { 418 super(new ByteArrayOutputStream()); 419 } 420 } 421 422 public static final class InMemoryPrintWriter extends PrintWriter { 423 public InMemoryPrintWriter() { 424 super(new StringWriter()); 425 } 426 } 427 428 public static final class DeterministicRandom extends Random { 429 @Keep 430 public DeterministicRandom() { 431 super(0); 432 } 433 } 434 435 public static final class DummyScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor { 436 public DummyScheduledThreadPoolExecutor() { 437 super(1); 438 } 439 } 440 441 public static final class DummyCountDownLatch extends CountDownLatch { 442 public DummyCountDownLatch() { 443 super(0); 444 } 445 } 446 447 public static final class DummyRunnable implements Runnable, Serializable { 448 @Override 449 public void run() {} 450 } 451 452 public static final class DummyThreadFactory implements ThreadFactory, Serializable { 453 @Override 454 public Thread newThread(Runnable r) { 455 return new Thread(r); 456 } 457 } 458 459 public static final class DummyExecutor implements Executor, Serializable { 460 @Override 461 public void execute(Runnable command) {} 462 } 463 } 464 465 private static final class NullByteSink extends ByteSink implements Serializable { 466 private static final NullByteSink INSTANCE = new NullByteSink(); 467 468 @Override 469 public OutputStream openStream() { 470 return ByteStreams.nullOutputStream(); 471 } 472 } 473 474 // Compare by toString() to satisfy 2 properties: 475 // 1. compareTo(null) should throw NullPointerException 476 // 2. the order is deterministic and easy to understand, for debugging purpose. 477 @SuppressWarnings("ComparableType") 478 private static final class ByToString implements Comparable<Object>, Serializable { 479 private static final ByToString INSTANCE = new ByToString(); 480 481 @Override 482 public int compareTo(Object o) { 483 return toString().compareTo(o.toString()); 484 } 485 486 @Override 487 public String toString() { 488 return "BY_TO_STRING"; 489 } 490 491 private Object readResolve() { 492 return INSTANCE; 493 } 494 } 495 496 // Always equal is a valid total ordering. And it works for any Object. 497 private static final class AlwaysEqual extends Ordering<@Nullable Object> 498 implements Serializable { 499 private static final AlwaysEqual INSTANCE = new AlwaysEqual(); 500 501 @Override 502 @SuppressWarnings("UnusedVariable") // intentionally weird Comparator 503 public int compare(@Nullable Object o1, @Nullable Object o2) { 504 return 0; 505 } 506 507 @Override 508 public String toString() { 509 return "ALWAYS_EQUAL"; 510 } 511 512 private Object readResolve() { 513 return INSTANCE; 514 } 515 } 516 517 private ArbitraryInstances() {} 518}