1090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2009 The Guava Authors 3090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 4090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * you may not use this file except in compliance with the License. 6090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * You may obtain a copy of the License at 7090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 8090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 10090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * See the License for the specific language governing permissions and 14090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * limitations under the License. 15090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 16090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 17090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonpackage com.google.common.collect; 18090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 197dd252788645e940eada959bdde927426e2531c9Paul Duffinimport static com.google.common.base.Preconditions.checkNotNull; 207dd252788645e940eada959bdde927426e2531c9Paul Duffin 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.primitives.Primitives; 22090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 230888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.io.Serializable; 24090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.Map; 25090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 267dd252788645e940eada959bdde927426e2531c9Paul Duffinimport javax.annotation.Nullable; 277dd252788645e940eada959bdde927426e2531c9Paul Duffin 28090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/** 29090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * A class-to-instance map backed by an {@link ImmutableMap}. See also {@link 30090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * MutableClassToInstanceMap}. 31090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 32090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @author Kevin Bourrillion 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 2.0 (imported from Google Collections Library) 34090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 350888a09821a98ac0680fad765217302858e70fa4Paul Duffinpublic final class ImmutableClassToInstanceMap<B> 360888a09821a98ac0680fad765217302858e70fa4Paul Duffin extends ForwardingMap<Class<? extends B>, B> 370888a09821a98ac0680fad765217302858e70fa4Paul Duffin implements ClassToInstanceMap<B>, Serializable { 380888a09821a98ac0680fad765217302858e70fa4Paul Duffin 39090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 40090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns a new builder. The generated builder is equivalent to the builder 41090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * created by the {@link Builder} constructor. 42090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 43090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <B> Builder<B> builder() { 44090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new Builder<B>(); 45090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 46090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 47090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 48090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * A builder for creating immutable class-to-instance maps. Example: 49090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * <pre> {@code 50090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 51090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * static final ImmutableClassToInstanceMap<Handler> HANDLERS = 52090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * new ImmutableClassToInstanceMap.Builder<Handler>() 53090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * .put(FooHandler.class, new FooHandler()) 54090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * .put(BarHandler.class, new SubBarHandler()) 55090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * .put(Handler.class, new QuuxHandler()) 56090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * .build();}</pre> 57090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 580888a09821a98ac0680fad765217302858e70fa4Paul Duffin * <p>After invoking {@link #build()} it is still possible to add more entries 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * and build again. Thus each map generated by this builder will be a superset 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * of any map generated before it. 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 2.0 (imported from Google Collections Library) 63090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 64090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static final class Builder<B> { 650888a09821a98ac0680fad765217302858e70fa4Paul Duffin private final ImmutableMap.Builder<Class<? extends B>, B> mapBuilder 660888a09821a98ac0680fad765217302858e70fa4Paul Duffin = ImmutableMap.builder(); 67090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 68090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 69090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Associates {@code key} with {@code value} in the built map. Duplicate 70090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * keys are not allowed, and will cause {@link #build} to fail. 71090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public <T extends B> Builder<B> put(Class<T> key, T value) { 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert mapBuilder.put(key, value); 74090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return this; 75090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 76090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 77090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 78090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Associates all of {@code map's} keys and values in the built map. 79090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Duplicate keys are not allowed, and will cause {@link #build} to fail. 80090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 81090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws NullPointerException if any key or value in {@code map} is null 82090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws ClassCastException if any value is not an instance of the type 83090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * specified by its key 84090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 850888a09821a98ac0680fad765217302858e70fa4Paul Duffin public <T extends B> Builder<B> putAll( 860888a09821a98ac0680fad765217302858e70fa4Paul Duffin Map<? extends Class<? extends T>, ? extends T> map) { 870888a09821a98ac0680fad765217302858e70fa4Paul Duffin for (Entry<? extends Class<? extends T>, ? extends T> entry 880888a09821a98ac0680fad765217302858e70fa4Paul Duffin : map.entrySet()) { 89090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Class<? extends T> type = entry.getKey(); 90090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson T value = entry.getValue(); 91090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson mapBuilder.put(type, cast(type, value)); 92090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 93090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return this; 94090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 95090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static <B, T extends B> T cast(Class<T> type, B value) { 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return Primitives.wrap(type).cast(value); 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 100090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 101090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns a new immutable class-to-instance map containing the entries 102090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * provided to this builder. 103090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 104090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws IllegalArgumentException if duplicate keys were added 105090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 106090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public ImmutableClassToInstanceMap<B> build() { 107090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new ImmutableClassToInstanceMap<B>(mapBuilder.build()); 108090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 109090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 110090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 111090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 112090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns an immutable map containing the same entries as {@code map}. If 113090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * {@code map} somehow contains entries with duplicate keys (for example, if 114090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * it is a {@code SortedMap} whose comparator is not <i>consistent with 115090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * equals</i>), the results of this method are undefined. 116090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 117090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * <p><b>Note:</b> Despite what the method name suggests, if {@code map} is 118090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * an {@code ImmutableClassToInstanceMap}, no copy will actually be performed. 119090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 120090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws NullPointerException if any key or value in {@code map} is null 121090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws ClassCastException if any value is not an instance of the type 122090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * specified by its key 123090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 124090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <B, S extends B> ImmutableClassToInstanceMap<B> copyOf( 125090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Map<? extends Class<? extends S>, ? extends S> map) { 126090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (map instanceof ImmutableClassToInstanceMap) { 1270888a09821a98ac0680fad765217302858e70fa4Paul Duffin @SuppressWarnings("unchecked") // covariant casts safe (unmodifiable) 1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Eclipse won't compile if we cast to the parameterized type. 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ImmutableClassToInstanceMap<B> cast = (ImmutableClassToInstanceMap) map; 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return cast; 131090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 132090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new Builder<B>().putAll(map).build(); 133090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 134090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 135090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private final ImmutableMap<Class<? extends B>, B> delegate; 136090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 1370888a09821a98ac0680fad765217302858e70fa4Paul Duffin private ImmutableClassToInstanceMap( 1380888a09821a98ac0680fad765217302858e70fa4Paul Duffin ImmutableMap<Class<? extends B>, B> delegate) { 139090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson this.delegate = delegate; 140090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 141090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 1420888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override protected Map<Class<? extends B>, B> delegate() { 143090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return delegate; 144090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 145090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 1460888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override 1470888a09821a98ac0680fad765217302858e70fa4Paul Duffin @SuppressWarnings("unchecked") // value could not get in if not a T 1487dd252788645e940eada959bdde927426e2531c9Paul Duffin @Nullable 149090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public <T extends B> T getInstance(Class<T> type) { 1507dd252788645e940eada959bdde927426e2531c9Paul Duffin return (T) delegate.get(checkNotNull(type)); 151090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 152090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 153090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 154090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Guaranteed to throw an exception and leave the map unmodified. 155090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 156090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws UnsupportedOperationException always 1577dd252788645e940eada959bdde927426e2531c9Paul Duffin * @deprecated Unsupported operation. 158090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 1597dd252788645e940eada959bdde927426e2531c9Paul Duffin @Deprecated 1600888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override 161090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public <T extends B> T putInstance(Class<T> type, T value) { 162090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new UnsupportedOperationException(); 163090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 164090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson} 165