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