guava

Форк
0
/
ArbitraryInstances.java 
527 строк · 21.0 Кб
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
import static java.util.Objects.requireNonNull;
21

22
import com.google.common.annotations.GwtIncompatible;
23
import com.google.common.annotations.J2ktIncompatible;
24
import com.google.common.base.CharMatcher;
25
import com.google.common.base.Charsets;
26
import com.google.common.base.Defaults;
27
import com.google.common.base.Equivalence;
28
import com.google.common.base.Joiner;
29
import com.google.common.base.Predicate;
30
import com.google.common.base.Predicates;
31
import com.google.common.base.Splitter;
32
import com.google.common.base.Stopwatch;
33
import com.google.common.base.Ticker;
34
import com.google.common.collect.BiMap;
35
import com.google.common.collect.ClassToInstanceMap;
36
import com.google.common.collect.ImmutableBiMap;
37
import com.google.common.collect.ImmutableClassToInstanceMap;
38
import com.google.common.collect.ImmutableCollection;
39
import com.google.common.collect.ImmutableList;
40
import com.google.common.collect.ImmutableListMultimap;
41
import com.google.common.collect.ImmutableMap;
42
import com.google.common.collect.ImmutableMultimap;
43
import com.google.common.collect.ImmutableMultiset;
44
import com.google.common.collect.ImmutableSet;
45
import com.google.common.collect.ImmutableSetMultimap;
46
import com.google.common.collect.ImmutableSortedMap;
47
import com.google.common.collect.ImmutableSortedMultiset;
48
import com.google.common.collect.ImmutableSortedSet;
49
import com.google.common.collect.ImmutableTable;
50
import com.google.common.collect.Iterators;
51
import com.google.common.collect.ListMultimap;
52
import com.google.common.collect.MapDifference;
53
import com.google.common.collect.Maps;
54
import com.google.common.collect.Multimap;
55
import com.google.common.collect.Multimaps;
56
import com.google.common.collect.Multiset;
57
import com.google.common.collect.Ordering;
58
import com.google.common.collect.PeekingIterator;
59
import com.google.common.collect.Range;
60
import com.google.common.collect.RowSortedTable;
61
import com.google.common.collect.SetMultimap;
62
import com.google.common.collect.Sets;
63
import com.google.common.collect.SortedMapDifference;
64
import com.google.common.collect.SortedMultiset;
65
import com.google.common.collect.SortedSetMultimap;
66
import com.google.common.collect.Table;
67
import com.google.common.collect.Tables;
68
import com.google.common.collect.TreeBasedTable;
69
import com.google.common.collect.TreeMultimap;
70
import com.google.common.io.ByteSink;
71
import com.google.common.io.ByteSource;
72
import com.google.common.io.ByteStreams;
73
import com.google.common.io.CharSink;
74
import com.google.common.io.CharSource;
75
import com.google.common.primitives.Primitives;
76
import com.google.common.primitives.UnsignedInteger;
77
import com.google.common.primitives.UnsignedLong;
78
import com.google.errorprone.annotations.Keep;
79
import java.io.ByteArrayInputStream;
80
import java.io.ByteArrayOutputStream;
81
import java.io.File;
82
import java.io.InputStream;
83
import java.io.OutputStream;
84
import java.io.PrintStream;
85
import java.io.PrintWriter;
86
import java.io.Reader;
87
import java.io.Serializable;
88
import java.io.StringReader;
89
import java.io.StringWriter;
90
import java.io.Writer;
91
import java.lang.reflect.AnnotatedElement;
92
import java.lang.reflect.Array;
93
import java.lang.reflect.Constructor;
94
import java.lang.reflect.Field;
95
import java.lang.reflect.GenericDeclaration;
96
import java.lang.reflect.InvocationTargetException;
97
import java.lang.reflect.Modifier;
98
import java.lang.reflect.Type;
99
import java.math.BigDecimal;
100
import java.math.BigInteger;
101
import java.nio.Buffer;
102
import java.nio.ByteBuffer;
103
import java.nio.CharBuffer;
104
import java.nio.DoubleBuffer;
105
import java.nio.FloatBuffer;
106
import java.nio.IntBuffer;
107
import java.nio.LongBuffer;
108
import java.nio.ShortBuffer;
109
import java.nio.charset.Charset;
110
import java.util.ArrayDeque;
111
import java.util.Arrays;
112
import java.util.Collection;
113
import java.util.Comparator;
114
import java.util.Currency;
115
import java.util.Deque;
116
import java.util.Iterator;
117
import java.util.List;
118
import java.util.ListIterator;
119
import java.util.Locale;
120
import java.util.Map;
121
import java.util.NavigableMap;
122
import java.util.NavigableSet;
123
import java.util.Optional;
124
import java.util.OptionalDouble;
125
import java.util.OptionalInt;
126
import java.util.OptionalLong;
127
import java.util.Queue;
128
import java.util.Random;
129
import java.util.Set;
130
import java.util.SortedMap;
131
import java.util.SortedSet;
132
import java.util.UUID;
133
import java.util.concurrent.BlockingDeque;
134
import java.util.concurrent.BlockingQueue;
135
import java.util.concurrent.ConcurrentHashMap;
136
import java.util.concurrent.ConcurrentMap;
137
import java.util.concurrent.ConcurrentNavigableMap;
138
import java.util.concurrent.ConcurrentSkipListMap;
139
import java.util.concurrent.CountDownLatch;
140
import java.util.concurrent.Executor;
141
import java.util.concurrent.LinkedBlockingDeque;
142
import java.util.concurrent.ScheduledThreadPoolExecutor;
143
import java.util.concurrent.ThreadFactory;
144
import java.util.concurrent.ThreadPoolExecutor;
145
import java.util.concurrent.TimeUnit;
146
import java.util.logging.Level;
147
import java.util.logging.Logger;
148
import java.util.regex.MatchResult;
149
import java.util.regex.Matcher;
150
import java.util.regex.Pattern;
151
import java.util.stream.Stream;
152
import org.checkerframework.checker.nullness.qual.Nullable;
153

154
/**
155
 * Supplies an arbitrary "default" instance for a wide range of types, often useful in testing
156
 * utilities.
157
 *
158
 * <p>Covers arrays, enums and common types defined in {@code java.lang}, {@code java.lang.reflect},
159
 * {@code java.io}, {@code java.nio}, {@code java.math}, {@code java.util}, {@code
160
 * java.util.concurrent}, {@code java.util.regex}, {@code com.google.common.base}, {@code
161
 * com.google.common.collect} and {@code com.google.common.primitives}. In addition, if the type
162
 * exposes at least one public static final constant of the same type, one of the constants will be
163
 * used; or if the class exposes a public parameter-less constructor then it will be "new"d and
164
 * returned.
165
 *
166
 * <p>All default instances returned by {@link #get} are generics-safe. Clients won't get type
167
 * errors for using {@code get(Comparator.class)} as a {@code Comparator<Foo>}, for example.
168
 * Immutable empty instances are returned for collection types; {@code ""} for string; {@code 0} for
169
 * number types; reasonable default instance for other stateless types. For mutable types, a fresh
170
 * instance is created each time {@code get()} is called.
171
 *
172
 * @author Kevin Bourrillion
173
 * @author Ben Yu
174
 * @since 12.0
175
 */
176
@GwtIncompatible
177
@J2ktIncompatible
178
@ElementTypesAreNonnullByDefault
179
public final class ArbitraryInstances {
180

181
  private static final Ordering<Field> BY_FIELD_NAME =
182
      new Ordering<Field>() {
183
        @Override
184
        public int compare(Field left, Field right) {
185
          return left.getName().compareTo(right.getName());
186
        }
187
      };
188

189
  /**
190
   * Returns a new {@code MatchResult} that corresponds to a successful match. Apache Harmony (used
191
   * in Android) requires a successful match in order to generate a {@code MatchResult}:
192
   * http://goo.gl/5VQFmC
193
   */
194
  private static MatchResult createMatchResult() {
195
    Matcher matcher = Pattern.compile(".").matcher("X");
196
    matcher.find();
197
    return matcher.toMatchResult();
198
  }
199

200
  private static final ClassToInstanceMap<Object> DEFAULTS =
201
      ImmutableClassToInstanceMap.builder()
202
          // primitives
203
          .put(Object.class, "")
204
          .put(Number.class, 0)
205
          .put(UnsignedInteger.class, UnsignedInteger.ZERO)
206
          .put(UnsignedLong.class, UnsignedLong.ZERO)
207
          .put(BigInteger.class, BigInteger.ZERO)
208
          .put(BigDecimal.class, BigDecimal.ZERO)
209
          .put(CharSequence.class, "")
210
          .put(String.class, "")
211
          .put(Pattern.class, Pattern.compile(""))
212
          .put(MatchResult.class, createMatchResult())
213
          .put(TimeUnit.class, TimeUnit.SECONDS)
214
          .put(Charset.class, Charsets.UTF_8)
215
          .put(Currency.class, Currency.getInstance(Locale.US))
216
          .put(Locale.class, Locale.US)
217
          .put(Optional.class, Optional.empty())
218
          .put(OptionalInt.class, OptionalInt.empty())
219
          .put(OptionalLong.class, OptionalLong.empty())
220
          .put(OptionalDouble.class, OptionalDouble.empty())
221
          .put(UUID.class, UUID.randomUUID())
222
          // common.base
223
          .put(CharMatcher.class, CharMatcher.none())
224
          .put(Joiner.class, Joiner.on(','))
225
          .put(Splitter.class, Splitter.on(','))
226
          .put(com.google.common.base.Optional.class, com.google.common.base.Optional.absent())
227
          .put(Predicate.class, Predicates.alwaysTrue())
228
          .put(Equivalence.class, Equivalence.equals())
229
          .put(Ticker.class, Ticker.systemTicker())
230
          .put(Stopwatch.class, Stopwatch.createUnstarted())
231
          // io types
232
          .put(InputStream.class, new ByteArrayInputStream(new byte[0]))
233
          .put(ByteArrayInputStream.class, new ByteArrayInputStream(new byte[0]))
234
          .put(Readable.class, new StringReader(""))
235
          .put(Reader.class, new StringReader(""))
236
          .put(StringReader.class, new StringReader(""))
237
          .put(Buffer.class, ByteBuffer.allocate(0))
238
          .put(CharBuffer.class, CharBuffer.allocate(0))
239
          .put(ByteBuffer.class, ByteBuffer.allocate(0))
240
          .put(ShortBuffer.class, ShortBuffer.allocate(0))
241
          .put(IntBuffer.class, IntBuffer.allocate(0))
242
          .put(LongBuffer.class, LongBuffer.allocate(0))
243
          .put(FloatBuffer.class, FloatBuffer.allocate(0))
244
          .put(DoubleBuffer.class, DoubleBuffer.allocate(0))
245
          .put(File.class, new File(""))
246
          .put(ByteSource.class, ByteSource.empty())
247
          .put(CharSource.class, CharSource.empty())
248
          .put(ByteSink.class, NullByteSink.INSTANCE)
249
          .put(CharSink.class, NullByteSink.INSTANCE.asCharSink(Charsets.UTF_8))
250
          // All collections are immutable empty. So safe for any type parameter.
251
          .put(Iterator.class, ImmutableSet.of().iterator())
252
          .put(PeekingIterator.class, Iterators.peekingIterator(ImmutableSet.of().iterator()))
253
          .put(ListIterator.class, ImmutableList.of().listIterator())
254
          .put(Iterable.class, ImmutableSet.of())
255
          .put(Collection.class, ImmutableList.of())
256
          .put(ImmutableCollection.class, ImmutableList.of())
257
          .put(List.class, ImmutableList.of())
258
          .put(ImmutableList.class, ImmutableList.of())
259
          .put(Set.class, ImmutableSet.of())
260
          .put(ImmutableSet.class, ImmutableSet.of())
261
          .put(SortedSet.class, ImmutableSortedSet.of())
262
          .put(ImmutableSortedSet.class, ImmutableSortedSet.of())
263
          .put(NavigableSet.class, Sets.unmodifiableNavigableSet(Sets.newTreeSet()))
264
          .put(Map.class, ImmutableMap.of())
265
          .put(ImmutableMap.class, ImmutableMap.of())
266
          .put(SortedMap.class, ImmutableSortedMap.of())
267
          .put(ImmutableSortedMap.class, ImmutableSortedMap.of())
268
          .put(NavigableMap.class, Maps.unmodifiableNavigableMap(Maps.newTreeMap()))
269
          .put(Multimap.class, ImmutableMultimap.of())
270
          .put(ImmutableMultimap.class, ImmutableMultimap.of())
271
          .put(ListMultimap.class, ImmutableListMultimap.of())
272
          .put(ImmutableListMultimap.class, ImmutableListMultimap.of())
273
          .put(SetMultimap.class, ImmutableSetMultimap.of())
274
          .put(ImmutableSetMultimap.class, ImmutableSetMultimap.of())
275
          .put(
276
              SortedSetMultimap.class,
277
              Multimaps.unmodifiableSortedSetMultimap(TreeMultimap.create()))
278
          .put(Multiset.class, ImmutableMultiset.of())
279
          .put(ImmutableMultiset.class, ImmutableMultiset.of())
280
          .put(SortedMultiset.class, ImmutableSortedMultiset.of())
281
          .put(ImmutableSortedMultiset.class, ImmutableSortedMultiset.of())
282
          .put(BiMap.class, ImmutableBiMap.of())
283
          .put(ImmutableBiMap.class, ImmutableBiMap.of())
284
          .put(Table.class, ImmutableTable.of())
285
          .put(ImmutableTable.class, ImmutableTable.of())
286
          .put(RowSortedTable.class, Tables.unmodifiableRowSortedTable(TreeBasedTable.create()))
287
          .put(ClassToInstanceMap.class, ImmutableClassToInstanceMap.builder().build())
288
          .put(ImmutableClassToInstanceMap.class, ImmutableClassToInstanceMap.builder().build())
289
          .put(Comparable.class, ByToString.INSTANCE)
290
          .put(Comparator.class, AlwaysEqual.INSTANCE)
291
          .put(Ordering.class, AlwaysEqual.INSTANCE)
292
          .put(Range.class, Range.all())
293
          .put(MapDifference.class, Maps.difference(ImmutableMap.of(), ImmutableMap.of()))
294
          .put(
295
              SortedMapDifference.class,
296
              Maps.difference(ImmutableSortedMap.of(), ImmutableSortedMap.of()))
297
          // reflect
298
          .put(AnnotatedElement.class, Object.class)
299
          .put(GenericDeclaration.class, Object.class)
300
          .put(Type.class, Object.class)
301
          .build();
302

303
  /**
304
   * type → implementation. Inherently mutable interfaces and abstract classes are mapped to their
305
   * default implementations and are "new"d upon get().
306
   */
307
  private static final ConcurrentMap<Class<?>, Class<?>> implementations = Maps.newConcurrentMap();
308

309
  private static <T> void setImplementation(Class<T> type, Class<? extends T> implementation) {
310
    checkArgument(type != implementation, "Don't register %s to itself!", type);
311
    checkArgument(
312
        !DEFAULTS.containsKey(type), "A default value was already registered for %s", type);
313
    checkArgument(
314
        implementations.put(type, implementation) == null,
315
        "Implementation for %s was already registered",
316
        type);
317
  }
318

319
  static {
320
    setImplementation(Appendable.class, StringBuilder.class);
321
    setImplementation(BlockingQueue.class, LinkedBlockingDeque.class);
322
    setImplementation(BlockingDeque.class, LinkedBlockingDeque.class);
323
    setImplementation(ConcurrentMap.class, ConcurrentHashMap.class);
324
    setImplementation(ConcurrentNavigableMap.class, ConcurrentSkipListMap.class);
325
    setImplementation(CountDownLatch.class, Dummies.DummyCountDownLatch.class);
326
    setImplementation(Deque.class, ArrayDeque.class);
327
    setImplementation(OutputStream.class, ByteArrayOutputStream.class);
328
    setImplementation(PrintStream.class, Dummies.InMemoryPrintStream.class);
329
    setImplementation(PrintWriter.class, Dummies.InMemoryPrintWriter.class);
330
    setImplementation(Queue.class, ArrayDeque.class);
331
    setImplementation(Random.class, Dummies.DeterministicRandom.class);
332
    setImplementation(
333
        ScheduledThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class);
334
    setImplementation(ThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class);
335
    setImplementation(Writer.class, StringWriter.class);
336
    setImplementation(Runnable.class, Dummies.DummyRunnable.class);
337
    setImplementation(ThreadFactory.class, Dummies.DummyThreadFactory.class);
338
    setImplementation(Executor.class, Dummies.DummyExecutor.class);
339
  }
340

341
  @SuppressWarnings("unchecked") // it's a subtype map
342
  private static <T> @Nullable Class<? extends T> getImplementation(Class<T> type) {
343
    return (Class<? extends T>) implementations.get(type);
344
  }
345

346
  private static final Logger logger = Logger.getLogger(ArbitraryInstances.class.getName());
347

348
  /**
349
   * Returns an arbitrary instance for {@code type}, or {@code null} if no arbitrary instance can be
350
   * determined.
351
   */
352
  public static <T> @Nullable T get(Class<T> type) {
353
    T defaultValue = DEFAULTS.getInstance(type);
354
    if (defaultValue != null) {
355
      return defaultValue;
356
    }
357
    Class<? extends T> implementation = getImplementation(type);
358
    if (implementation != null) {
359
      return get(implementation);
360
    }
361
    if (type == Stream.class) {
362
      return type.cast(Stream.empty());
363
    }
364
    if (type.isEnum()) {
365
      T[] enumConstants = type.getEnumConstants();
366
      return (enumConstants == null || enumConstants.length == 0) ? null : enumConstants[0];
367
    }
368
    if (type.isArray()) {
369
      return createEmptyArray(type);
370
    }
371
    T jvmDefault = Defaults.defaultValue(Primitives.unwrap(type));
372
    if (jvmDefault != null) {
373
      return jvmDefault;
374
    }
375
    if (Modifier.isAbstract(type.getModifiers()) || !Modifier.isPublic(type.getModifiers())) {
376
      return arbitraryConstantInstanceOrNull(type);
377
    }
378
    final Constructor<T> constructor;
379
    try {
380
      constructor = type.getConstructor();
381
    } catch (NoSuchMethodException e) {
382
      return arbitraryConstantInstanceOrNull(type);
383
    }
384
    constructor.setAccessible(true); // accessibility check is too slow
385
    try {
386
      return constructor.newInstance();
387
    } catch (InstantiationException | IllegalAccessException impossible) {
388
      throw new AssertionError(impossible);
389
    } catch (InvocationTargetException e) {
390
      logger.log(Level.WARNING, "Exception while invoking default constructor.", e.getCause());
391
      return arbitraryConstantInstanceOrNull(type);
392
    }
393
  }
394

395
  private static <T> @Nullable T arbitraryConstantInstanceOrNull(Class<T> type) {
396
    Field[] fields = type.getDeclaredFields();
397
    Arrays.sort(fields, BY_FIELD_NAME);
398
    for (Field field : fields) {
399
      if (Modifier.isPublic(field.getModifiers())
400
          && Modifier.isStatic(field.getModifiers())
401
          && Modifier.isFinal(field.getModifiers())) {
402
        if (field.getGenericType() == field.getType() && type.isAssignableFrom(field.getType())) {
403
          field.setAccessible(true);
404
          try {
405
            T constant = type.cast(field.get(null));
406
            if (constant != null) {
407
              return constant;
408
            }
409
          } catch (IllegalAccessException impossible) {
410
            throw new AssertionError(impossible);
411
          }
412
        }
413
      }
414
    }
415
    return null;
416
  }
417

418
  private static <T> T createEmptyArray(Class<T> arrayType) {
419
    // getComponentType() is non-null because we call createEmptyArray only with an array type.
420
    return arrayType.cast(Array.newInstance(requireNonNull(arrayType.getComponentType()), 0));
421
  }
422

423
  // Internal implementations of some classes, with public default constructor that get() needs.
424
  private static final class Dummies {
425

426
    public static final class InMemoryPrintStream extends PrintStream {
427
      public InMemoryPrintStream() {
428
        super(new ByteArrayOutputStream());
429
      }
430
    }
431

432
    public static final class InMemoryPrintWriter extends PrintWriter {
433
      public InMemoryPrintWriter() {
434
        super(new StringWriter());
435
      }
436
    }
437

438
    public static final class DeterministicRandom extends Random {
439
      @Keep
440
      public DeterministicRandom() {
441
        super(0);
442
      }
443
    }
444

445
    public static final class DummyScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
446
      public DummyScheduledThreadPoolExecutor() {
447
        super(1);
448
      }
449
    }
450

451
    public static final class DummyCountDownLatch extends CountDownLatch {
452
      public DummyCountDownLatch() {
453
        super(0);
454
      }
455
    }
456

457
    public static final class DummyRunnable implements Runnable, Serializable {
458
      @Override
459
      public void run() {}
460
    }
461

462
    public static final class DummyThreadFactory implements ThreadFactory, Serializable {
463
      @Override
464
      public Thread newThread(Runnable r) {
465
        return new Thread(r);
466
      }
467
    }
468

469
    public static final class DummyExecutor implements Executor, Serializable {
470
      @Override
471
      public void execute(Runnable command) {}
472
    }
473
  }
474

475
  private static final class NullByteSink extends ByteSink implements Serializable {
476
    private static final NullByteSink INSTANCE = new NullByteSink();
477

478
    @Override
479
    public OutputStream openStream() {
480
      return ByteStreams.nullOutputStream();
481
    }
482
  }
483

484
  // Compare by toString() to satisfy 2 properties:
485
  // 1. compareTo(null) should throw NullPointerException
486
  // 2. the order is deterministic and easy to understand, for debugging purpose.
487
  @SuppressWarnings("ComparableType")
488
  private static final class ByToString implements Comparable<Object>, Serializable {
489
    private static final ByToString INSTANCE = new ByToString();
490

491
    @Override
492
    public int compareTo(Object o) {
493
      return toString().compareTo(o.toString());
494
    }
495

496
    @Override
497
    public String toString() {
498
      return "BY_TO_STRING";
499
    }
500

501
    private Object readResolve() {
502
      return INSTANCE;
503
    }
504
  }
505

506
  // Always equal is a valid total ordering. And it works for any Object.
507
  private static final class AlwaysEqual extends Ordering<@Nullable Object>
508
      implements Serializable {
509
    private static final AlwaysEqual INSTANCE = new AlwaysEqual();
510

511
    @Override
512
    public int compare(@Nullable Object o1, @Nullable Object o2) {
513
      return 0;
514
    }
515

516
    @Override
517
    public String toString() {
518
      return "ALWAYS_EQUAL";
519
    }
520

521
    private Object readResolve() {
522
      return INSTANCE;
523
    }
524
  }
525

526
  private ArbitraryInstances() {}
527
}
528

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.