View Javadoc
1   /*
2    * Copyright (C) 2012 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package com.google.common.reflect;
16  
17  import static com.google.common.base.Preconditions.checkNotNull;
18  
19  import com.google.common.annotations.Beta;
20  import com.google.common.base.Function;
21  import com.google.common.collect.ForwardingMap;
22  import com.google.common.collect.ForwardingMapEntry;
23  import com.google.common.collect.ForwardingSet;
24  import com.google.common.collect.Iterators;
25  import com.google.common.collect.Maps;
26  import com.google.errorprone.annotations.CanIgnoreReturnValue;
27  import java.util.Iterator;
28  import java.util.Map;
29  import java.util.Set;
30  import javax.annotation.Nullable;
31  
32  /**
33   * A mutable type-to-instance map. See also {@link ImmutableTypeToInstanceMap}.
34   *
35   * @author Ben Yu
36   * @since 13.0
37   */
38  @Beta
39  public final class MutableTypeToInstanceMap<B> extends ForwardingMap<TypeToken<? extends B>, B>
40      implements TypeToInstanceMap<B> {
41  
42    private final Map<TypeToken<? extends B>, B> backingMap = Maps.newHashMap();
43  
44    @Nullable
45    @Override
46    public <T extends B> T getInstance(Class<T> type) {
47      return trustedGet(TypeToken.of(type));
48    }
49  
50    @Nullable
51    @Override
52    @CanIgnoreReturnValue
53    public <T extends B> T putInstance(Class<T> type, @Nullable T value) {
54      return trustedPut(TypeToken.of(type), value);
55    }
56  
57    @Nullable
58    @Override
59    public <T extends B> T getInstance(TypeToken<T> type) {
60      return trustedGet(type.rejectTypeVariables());
61    }
62  
63    @Nullable
64    @Override
65    @CanIgnoreReturnValue
66    public <T extends B> T putInstance(TypeToken<T> type, @Nullable T value) {
67      return trustedPut(type.rejectTypeVariables(), value);
68    }
69  
70    /**
71     * Not supported. Use {@link #putInstance} instead.
72     *
73     * @deprecated unsupported operation
74     * @throws UnsupportedOperationException always
75     */
76    @CanIgnoreReturnValue
77    @Deprecated
78    @Override
79    public B put(TypeToken<? extends B> key, B value) {
80      throw new UnsupportedOperationException("Please use putInstance() instead.");
81    }
82  
83    /**
84     * Not supported. Use {@link #putInstance} instead.
85     *
86     * @deprecated unsupported operation
87     * @throws UnsupportedOperationException always
88     */
89    @Deprecated
90    @Override
91    public void putAll(Map<? extends TypeToken<? extends B>, ? extends B> map) {
92      throw new UnsupportedOperationException("Please use putInstance() instead.");
93    }
94  
95    @Override
96    public Set<Entry<TypeToken<? extends B>, B>> entrySet() {
97      return UnmodifiableEntry.transformEntries(super.entrySet());
98    }
99  
100   @Override
101   protected Map<TypeToken<? extends B>, B> delegate() {
102     return backingMap;
103   }
104 
105   @SuppressWarnings("unchecked") // value could not get in if not a T
106   @Nullable
107   private <T extends B> T trustedPut(TypeToken<T> type, @Nullable T value) {
108     return (T) backingMap.put(type, value);
109   }
110 
111   @SuppressWarnings("unchecked") // value could not get in if not a T
112   @Nullable
113   private <T extends B> T trustedGet(TypeToken<T> type) {
114     return (T) backingMap.get(type);
115   }
116 
117   private static final class UnmodifiableEntry<K, V> extends ForwardingMapEntry<K, V> {
118 
119     private final Entry<K, V> delegate;
120 
121     static <K, V> Set<Entry<K, V>> transformEntries(final Set<Entry<K, V>> entries) {
122       return new ForwardingSet<Map.Entry<K, V>>() {
123         @Override
124         protected Set<Entry<K, V>> delegate() {
125           return entries;
126         }
127 
128         @Override
129         public Iterator<Entry<K, V>> iterator() {
130           return UnmodifiableEntry.transformEntries(super.iterator());
131         }
132 
133         @Override
134         public Object[] toArray() {
135           return standardToArray();
136         }
137 
138         @Override
139         public <T> T[] toArray(T[] array) {
140           return standardToArray(array);
141         }
142       };
143     }
144 
145     private static <K, V> Iterator<Entry<K, V>> transformEntries(Iterator<Entry<K, V>> entries) {
146       return Iterators.transform(
147           entries,
148           new Function<Entry<K, V>, Entry<K, V>>() {
149             @Override
150             public Entry<K, V> apply(Entry<K, V> entry) {
151               return new UnmodifiableEntry<>(entry);
152             }
153           });
154     }
155 
156     private UnmodifiableEntry(java.util.Map.Entry<K, V> delegate) {
157       this.delegate = checkNotNull(delegate);
158     }
159 
160     @Override
161     protected Entry<K, V> delegate() {
162       return delegate;
163     }
164 
165     @Override
166     public V setValue(V value) {
167       throw new UnsupportedOperationException();
168     }
169   }
170 }