Coverage Summary for Class: ImmutableClassToInstanceMap (com.google.common.collect)

Class Method, % Line, %
ImmutableClassToInstanceMap 63.6% (7/11) 55.6% (10/18)
ImmutableClassToInstanceMap$Builder 60% (3/5) 53.3% (8/15)
Total 62.5% (10/16) 54.5% (18/33)


1 /* 2  * Copyright (C) 2009 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.collect; 18  19 import static com.google.common.base.Preconditions.checkNotNull; 20  21 import com.google.common.annotations.GwtIncompatible; 22 import com.google.common.primitives.Primitives; 23 import com.google.errorprone.annotations.CanIgnoreReturnValue; 24 import com.google.errorprone.annotations.DoNotCall; 25 import com.google.errorprone.annotations.Immutable; 26 import java.io.Serializable; 27 import java.util.Map; 28 import org.checkerframework.checker.nullness.qual.Nullable; 29  30 /** 31  * A {@link ClassToInstanceMap} whose contents will never change, with many other important 32  * properties detailed at {@link ImmutableCollection}. 33  * 34  * @author Kevin Bourrillion 35  * @since 2.0 36  */ 37 @Immutable(containerOf = "B") 38 @GwtIncompatible 39 public final class ImmutableClassToInstanceMap<B> extends ForwardingMap<Class<? extends B>, B> 40  implements ClassToInstanceMap<B>, Serializable { 41  42  private static final ImmutableClassToInstanceMap<Object> EMPTY = 43  new ImmutableClassToInstanceMap<>(ImmutableMap.<Class<?>, Object>of()); 44  45  /** 46  * Returns an empty {@code ImmutableClassToInstanceMap}. 47  * 48  * <p><b>Performance note:</b> the instance returned is a singleton. 49  * 50  * @since 19.0 51  */ 52  @SuppressWarnings("unchecked") 53  public static <B> ImmutableClassToInstanceMap<B> of() { 54  return (ImmutableClassToInstanceMap<B>) EMPTY; 55  } 56  57  /** 58  * Returns an {@code ImmutableClassToInstanceMap} containing a single entry. 59  * 60  * @since 19.0 61  */ 62  public static <B, T extends B> ImmutableClassToInstanceMap<B> of(Class<T> type, T value) { 63  ImmutableMap<Class<? extends B>, B> map = ImmutableMap.<Class<? extends B>, B>of(type, value); 64  return new ImmutableClassToInstanceMap<B>(map); 65  } 66  67  /** 68  * Returns a new builder. The generated builder is equivalent to the builder created by the {@link 69  * Builder} constructor. 70  */ 71  public static <B> Builder<B> builder() { 72  return new Builder<B>(); 73  } 74  75  /** 76  * A builder for creating immutable class-to-instance maps. Example: 77  * 78  * <pre>{@code 79  * static final ImmutableClassToInstanceMap<Handler> HANDLERS = 80  * new ImmutableClassToInstanceMap.Builder<Handler>() 81  * .put(FooHandler.class, new FooHandler()) 82  * .put(BarHandler.class, new SubBarHandler()) 83  * .put(Handler.class, new QuuxHandler()) 84  * .build(); 85  * }</pre> 86  * 87  * <p>After invoking {@link #build()} it is still possible to add more entries and build again. 88  * Thus each map generated by this builder will be a superset of any map generated before it. 89  * 90  * @since 2.0 91  */ 92  public static final class Builder<B> { 93  private final ImmutableMap.Builder<Class<? extends B>, B> mapBuilder = ImmutableMap.builder(); 94  95  /** 96  * Associates {@code key} with {@code value} in the built map. Duplicate keys are not allowed, 97  * and will cause {@link #build} to fail. 98  */ 99  @CanIgnoreReturnValue 100  public <T extends B> Builder<B> put(Class<T> key, T value) { 101  mapBuilder.put(key, value); 102  return this; 103  } 104  105  /** 106  * Associates all of {@code map's} keys and values in the built map. Duplicate keys are not 107  * allowed, and will cause {@link #build} to fail. 108  * 109  * @throws NullPointerException if any key or value in {@code map} is null 110  * @throws ClassCastException if any value is not an instance of the type specified by its key 111  */ 112  @CanIgnoreReturnValue 113  public <T extends B> Builder<B> putAll(Map<? extends Class<? extends T>, ? extends T> map) { 114  for (Entry<? extends Class<? extends T>, ? extends T> entry : map.entrySet()) { 115  Class<? extends T> type = entry.getKey(); 116  T value = entry.getValue(); 117  mapBuilder.put(type, cast(type, value)); 118  } 119  return this; 120  } 121  122  private static <B, T extends B> T cast(Class<T> type, B value) { 123  return Primitives.wrap(type).cast(value); 124  } 125  126  /** 127  * Returns a new immutable class-to-instance map containing the entries provided to this 128  * builder. 129  * 130  * @throws IllegalArgumentException if duplicate keys were added 131  */ 132  public ImmutableClassToInstanceMap<B> build() { 133  ImmutableMap<Class<? extends B>, B> map = mapBuilder.build(); 134  if (map.isEmpty()) { 135  return of(); 136  } else { 137  return new ImmutableClassToInstanceMap<B>(map); 138  } 139  } 140  } 141  142  /** 143  * Returns an immutable map containing the same entries as {@code map}. If {@code map} somehow 144  * contains entries with duplicate keys (for example, if it is a {@code SortedMap} whose 145  * comparator is not <i>consistent with equals</i>), the results of this method are undefined. 146  * 147  * <p><b>Note:</b> Despite what the method name suggests, if {@code map} is an {@code 148  * ImmutableClassToInstanceMap}, no copy will actually be performed. 149  * 150  * @throws NullPointerException if any key or value in {@code map} is null 151  * @throws ClassCastException if any value is not an instance of the type specified by its key 152  */ 153  public static <B, S extends B> ImmutableClassToInstanceMap<B> copyOf( 154  Map<? extends Class<? extends S>, ? extends S> map) { 155  if (map instanceof ImmutableClassToInstanceMap) { 156  @SuppressWarnings("unchecked") // covariant casts safe (unmodifiable) 157  ImmutableClassToInstanceMap<B> cast = (ImmutableClassToInstanceMap<B>) map; 158  return cast; 159  } 160  return new Builder<B>().putAll(map).build(); 161  } 162  163  private final ImmutableMap<Class<? extends B>, B> delegate; 164  165  private ImmutableClassToInstanceMap(ImmutableMap<Class<? extends B>, B> delegate) { 166  this.delegate = delegate; 167  } 168  169  @Override 170  protected Map<Class<? extends B>, B> delegate() { 171  return delegate; 172  } 173  174  @Override 175  @SuppressWarnings("unchecked") // value could not get in if not a T 176  public <T extends B> @Nullable T getInstance(Class<T> type) { 177  return (T) delegate.get(checkNotNull(type)); 178  } 179  180  /** 181  * Guaranteed to throw an exception and leave the map unmodified. 182  * 183  * @throws UnsupportedOperationException always 184  * @deprecated Unsupported operation. 185  */ 186  @CanIgnoreReturnValue 187  @Deprecated 188  @Override 189  @DoNotCall("Always throws UnsupportedOperationException") 190  public <T extends B> T putInstance(Class<T> type, T value) { 191  throw new UnsupportedOperationException(); 192  } 193  194  Object readResolve() { 195  return isEmpty() ? of() : this; 196  } 197 }