Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2011 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 com.google.common.annotations.GwtCompatible;
     20 
     21 import java.util.Iterator;
     22 import java.util.Map;
     23 import java.util.Set;
     24 
     25 /**
     26  * Workaround for
     27  * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6312706">
     28  * EnumMap bug</a>. If you want to pass an {@code EnumMap}, with the
     29  * intention of using its {@code entrySet()} method, you should
     30  * wrap the {@code EnumMap} in this class instead.
     31  *
     32  * <p>This class is not thread-safe even if the underlying map is.
     33  *
     34  * @author Dimitris Andreou
     35  */
     36 @GwtCompatible
     37 final class WellBehavedMap<K, V> extends ForwardingMap<K, V> {
     38   private final Map<K, V> delegate;
     39   private Set<Entry<K, V>> entrySet;
     40 
     41   private WellBehavedMap(Map<K, V> delegate) {
     42     this.delegate = delegate;
     43   }
     44 
     45   /**
     46    * Wraps the given map into a {@code WellBehavedEntriesMap}, which
     47    * intercepts its {@code entrySet()} method by taking the
     48    * {@code Set<K> keySet()} and transforming it to
     49    * {@code Set<Entry<K, V>>}. All other invocations are delegated as-is.
     50    */
     51   static <K, V> WellBehavedMap<K, V> wrap(Map<K, V> delegate) {
     52     return new WellBehavedMap<K, V>(delegate);
     53   }
     54 
     55   @Override protected Map<K, V> delegate() {
     56     return delegate;
     57   }
     58 
     59   @Override public Set<Entry<K, V>> entrySet() {
     60     Set<Entry<K, V>> es = entrySet;
     61     if (es != null) {
     62       return es;
     63     }
     64     return entrySet = new EntrySet();
     65   }
     66 
     67   private final class EntrySet extends Maps.EntrySet<K, V> {
     68     @Override
     69     Map<K, V> map() {
     70       return WellBehavedMap.this;
     71     }
     72 
     73     @Override
     74     public Iterator<Entry<K, V>> iterator() {
     75       return new TransformedIterator<K, Entry<K, V>>(keySet().iterator()) {
     76         @Override
     77         Entry<K, V> transform(final K key) {
     78           return new AbstractMapEntry<K, V>() {
     79             @Override
     80             public K getKey() {
     81               return key;
     82             }
     83 
     84             @Override
     85             public V getValue() {
     86               return get(key);
     87             }
     88 
     89             @Override
     90             public V setValue(V value) {
     91               return put(key, value);
     92             }
     93           };
     94         }
     95       };
     96     }
     97   }
     98 }
     99