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