001package ball.util; 002/*- 003 * ########################################################################## 004 * Utilities 005 * %% 006 * Copyright (C) 2008 - 2022 Allen D. Ball 007 * %% 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 * ########################################################################## 020 */ 021import java.io.Serializable; 022import java.util.AbstractMap; 023import java.util.ArrayList; 024import java.util.Iterator; 025import java.util.LinkedHashSet; 026import java.util.Map; 027import java.util.Set; 028 029/** 030 * {@link Map} implementation base class to provide a view of a wrapped 031 * {@link Map}. Subclass designers should override {@link #entrySet()} 032 * first. All implemented methods simply pass the call to the wrapped 033 * {@link Map} (all other methods are implemented by {@link AbstractMap}). 034 * 035 * @param <K> The key type. 036 * @param <V> The value type. 037 * 038 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 039 */ 040public class MapView<K,V> extends AbstractMap<K,V> implements Serializable { 041 private static final long serialVersionUID = -1914866590078121842L; 042 043 /** @serial */ private final Map<K,V> map; 044 /** @serial */ protected final EntrySet entrySet = new EntrySet(); 045 046 /** 047 * Sole constructor. 048 * 049 * @param map The {@link Map}. 050 */ 051 public MapView(Map<K,V> map) { 052 super(); 053 054 this.map = map; 055 } 056 057 /** 058 * @return The "wrapped" {@link Map}. 059 */ 060 protected Map<K,V> map() { return map; } 061 062 @Override 063 public V get(Object key) { return map().get(key); } 064 065 @Override 066 public V put(K key, V value) { return map().put(key, value); } 067 068 @Override 069 public V remove(Object key) { return map().remove(key); } 070 071 @Override 072 public void clear() { map().clear(); } 073 074 /** 075 * Method returns a single {@link Set} backed by {@link #map()}. 076 * Subclass implementations should update {@link #entrySet}. 077 * 078 * @return {@link #entrySet} 079 */ 080 @Override 081 public Set<Entry<K,V>> entrySet() { 082 entrySet.clear(); 083 entrySet.addAll(map().entrySet()); 084 085 return entrySet; 086 } 087 088 /** 089 * {@link #entrySet} implementation class. 090 */ 091 protected class EntrySet extends LinkedHashSet<Entry<K,V>> { 092 private static final long serialVersionUID = 5015923978722180032L; 093 094 /** 095 * Sole constructor. 096 */ 097 public EntrySet() { super(); } 098 099 @Override 100 public boolean remove(Object object) { 101 boolean changed = super.remove(object); 102 103 if (changed) { 104 MapView.this.remove(((Entry<?,?>) object).getKey()); 105 } 106 107 return changed; 108 } 109 110 @Override 111 public Iterator<Entry<K,V>> iterator() { 112 ArrayList<Entry<K,V>> list = new ArrayList<>(); 113 Iterator<Entry<K,V>> iterator = super.iterator(); 114 115 while (iterator.hasNext()) { 116 list.add(iterator.next()); 117 } 118 119 return new EntryIterator(list.iterator()); 120 } 121 } 122 123 private class EntryIterator implements Iterator<Entry<K,V>> { 124 private final Iterator<Entry<K,V>> iterator; 125 private Entry<K,V> current = null; 126 127 public EntryIterator(Iterator<Entry<K,V>> iterator) { 128 this.iterator = iterator; 129 } 130 131 @Override 132 public boolean hasNext() { return iterator.hasNext(); } 133 134 @Override 135 public Entry<K,V> next() { 136 current = iterator.next(); 137 138 return current; 139 } 140 141 @Override 142 public void remove() { 143 iterator.remove(); 144 MapView.this.remove(current.getKey()); 145 } 146 147 @Override 148 public String toString() { return iterator.toString(); } 149 } 150}