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