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