001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4; 018 019import java.util.Collection; 020import java.util.Map; 021import java.util.Objects; 022import java.util.Set; 023 024import org.apache.commons.collections4.collection.UnmodifiableCollection; 025import org.apache.commons.collections4.iterators.UnmodifiableMapIterator; 026import org.apache.commons.collections4.map.EntrySetToMapIteratorAdapter; 027import org.apache.commons.collections4.map.UnmodifiableEntrySet; 028import org.apache.commons.collections4.set.UnmodifiableSet; 029 030/** 031 * Utilities for working with "split maps:" objects that implement {@link Put} 032 * and/or {@link Get} but not {@link Map}. 033 * 034 * @since 4.0 035 * @see Get 036 * @see Put 037 */ 038public class SplitMapUtils { 039 040 private static final class WrappedGet<K, V> implements IterableMap<K, V>, Unmodifiable { 041 private final Get<K, V> get; 042 043 private WrappedGet(final Get<K, V> get) { 044 this.get = get; 045 } 046 047 /** 048 * Always throws {@link UnsupportedOperationException}. 049 * 050 * @throws UnsupportedOperationException Always thrown. 051 */ 052 @Override 053 public void clear() { 054 throw new UnsupportedOperationException(); 055 } 056 057 @Override 058 public boolean containsKey(final Object key) { 059 return get.containsKey(key); 060 } 061 062 @Override 063 public boolean containsValue(final Object value) { 064 return get.containsValue(value); 065 } 066 067 @Override 068 public Set<Map.Entry<K, V>> entrySet() { 069 return UnmodifiableEntrySet.unmodifiableEntrySet(get.entrySet()); 070 } 071 072 @Override 073 public boolean equals(final Object arg0) { 074 if (arg0 == this) { 075 return true; 076 } 077 return arg0 instanceof WrappedGet && ((WrappedGet<?, ?>) arg0).get.equals(get); 078 } 079 080 @Override 081 public V get(final Object key) { 082 return get.get(key); 083 } 084 085 @Override 086 public int hashCode() { 087 return "WrappedGet".hashCode() << 4 | get.hashCode(); 088 } 089 090 @Override 091 public boolean isEmpty() { 092 return get.isEmpty(); 093 } 094 095 @Override 096 public Set<K> keySet() { 097 return UnmodifiableSet.unmodifiableSet(get.keySet()); 098 } 099 100 @Override 101 public MapIterator<K, V> mapIterator() { 102 final MapIterator<K, V> it; 103 if (get instanceof IterableGet) { 104 it = ((IterableGet<K, V>) get).mapIterator(); 105 } else { 106 it = new EntrySetToMapIteratorAdapter<>(get.entrySet()); 107 } 108 return UnmodifiableMapIterator.unmodifiableMapIterator(it); 109 } 110 111 /** 112 * Always throws {@link UnsupportedOperationException}. 113 * 114 * @param key Ignored. 115 * @param value Ignored. 116 * @throws UnsupportedOperationException Always thrown. 117 */ 118 @Override 119 public V put(final K key, final V value) { 120 throw new UnsupportedOperationException(); 121 } 122 123 /** 124 * Always throws {@link UnsupportedOperationException}. 125 * 126 * @param map Ignored. 127 * @throws UnsupportedOperationException Always thrown. 128 */ 129 @Override 130 public void putAll(final Map<? extends K, ? extends V> map) { 131 throw new UnsupportedOperationException(); 132 } 133 134 /** 135 * Always throws {@link UnsupportedOperationException}. 136 * 137 * @param key The key whose mapping would be removed. 138 * @throws UnsupportedOperationException Always thrown. 139 */ 140 @Override 141 public V remove(final Object key) { 142 throw new UnsupportedOperationException(); 143 } 144 145 @Override 146 public int size() { 147 return get.size(); 148 } 149 150 @Override 151 public Collection<V> values() { 152 return UnmodifiableCollection.unmodifiableCollection(get.values()); 153 } 154 } 155 156 private static final class WrappedPut<K, V> implements Map<K, V>, Put<K, V> { 157 private final Put<K, V> put; 158 159 private WrappedPut(final Put<K, V> put) { 160 this.put = put; 161 } 162 163 @Override 164 public void clear() { 165 put.clear(); 166 } 167 168 /** 169 * Always throws {@link UnsupportedOperationException}. 170 * 171 * @param key Ignored. 172 * @throws UnsupportedOperationException Always thrown. 173 */ 174 @Override 175 public boolean containsKey(final Object key) { 176 throw new UnsupportedOperationException(); 177 } 178 179 /** 180 * Always throws {@link UnsupportedOperationException}. 181 * 182 * @param value Ignored. 183 * @throws UnsupportedOperationException Always thrown. 184 */ 185 @Override 186 public boolean containsValue(final Object value) { 187 throw new UnsupportedOperationException(); 188 } 189 190 /** 191 * Always throws {@link UnsupportedOperationException}. 192 * 193 * @throws UnsupportedOperationException Always thrown. 194 */ 195 @Override 196 public Set<Map.Entry<K, V>> entrySet() { 197 throw new UnsupportedOperationException(); 198 } 199 200 @Override 201 public boolean equals(final Object obj) { 202 if (obj == this) { 203 return true; 204 } 205 return obj instanceof WrappedPut && ((WrappedPut<?, ?>) obj).put.equals(put); 206 } 207 208 /** 209 * Always throws {@link UnsupportedOperationException}. 210 * 211 * @param key Ignored. 212 * @throws UnsupportedOperationException Always thrown. 213 */ 214 @Override 215 public V get(final Object key) { 216 throw new UnsupportedOperationException(); 217 } 218 219 @Override 220 public int hashCode() { 221 return "WrappedPut".hashCode() << 4 | put.hashCode(); 222 } 223 224 /** 225 * Always throws {@link UnsupportedOperationException}. 226 * 227 * @throws UnsupportedOperationException Always thrown. 228 */ 229 @Override 230 public boolean isEmpty() { 231 throw new UnsupportedOperationException(); 232 } 233 234 /** 235 * Always throws {@link UnsupportedOperationException}. 236 * 237 * @throws UnsupportedOperationException Always thrown. 238 */ 239 @Override 240 public Set<K> keySet() { 241 throw new UnsupportedOperationException(); 242 } 243 244 @Override 245 @SuppressWarnings("unchecked") 246 public V put(final K key, final V value) { 247 return (V) put.put(key, value); 248 } 249 250 @Override 251 public void putAll(final Map<? extends K, ? extends V> t) { 252 put.putAll(t); 253 } 254 255 /** 256 * Always throws {@link UnsupportedOperationException}. 257 * 258 * @param key Ignored. 259 * @throws UnsupportedOperationException Always thrown. 260 */ 261 @Override 262 public V remove(final Object key) { 263 throw new UnsupportedOperationException(); 264 } 265 266 /** 267 * Always throws {@link UnsupportedOperationException}. 268 * 269 * @throws UnsupportedOperationException Always thrown. 270 */ 271 @Override 272 public int size() { 273 throw new UnsupportedOperationException(); 274 } 275 276 /** 277 * Always throws {@link UnsupportedOperationException}. 278 * 279 * @throws UnsupportedOperationException Always thrown. 280 */ 281 @Override 282 public Collection<V> values() { 283 throw new UnsupportedOperationException(); 284 } 285 } 286 287 /** 288 * Gets the specified {@link Get} as an instance of {@link IterableMap}. 289 * If {@code get} implements {@link IterableMap} directly, no conversion will take place. 290 * If {@code get} implements {@link Map} but not {@link IterableMap} it will be decorated. 291 * Otherwise, an {@link Unmodifiable} {@link IterableMap} will be returned. 292 * 293 * @param <K> The key type 294 * @param <V> The value type 295 * @param get to wrap, must not be null 296 * @return {@link IterableMap} 297 * @throws NullPointerException if the argument is null 298 */ 299 @SuppressWarnings("unchecked") 300 public static <K, V> IterableMap<K, V> readableMap(final Get<K, V> get) { 301 Objects.requireNonNull(get, "get"); 302 if (get instanceof Map) { 303 return get instanceof IterableMap ? 304 (IterableMap<K, V>) get : 305 MapUtils.iterableMap((Map<K, V>) get); 306 } 307 return new WrappedGet<>(get); 308 } 309 310 /** 311 * Gets the specified {@link Put} as an instanceof {@link Map}. 312 * If {@code put} implements {@link Map} directly, no conversion will take place. 313 * Otherwise, a <em>write-only</em> {@link Map} will be returned. On such a {@link Map} 314 * it is recommended that the result of #put(K, V) be discarded as it likely will not 315 * match {@code V} at runtime. 316 * 317 * @param <K> The key type 318 * @param <V> The element type 319 * @param put to wrap, must not be null 320 * @return {@link Map} 321 * @throws NullPointerException if the argument is null 322 */ 323 @SuppressWarnings("unchecked") 324 public static <K, V> Map<K, V> writableMap(final Put<K, V> put) { 325 Objects.requireNonNull(put, "put"); 326 if (put instanceof Map) { 327 return (Map<K, V>) put; 328 } 329 return new WrappedPut<>(put); 330 } 331 332 /** 333 * Don't allow instances. 334 */ 335 private SplitMapUtils() { 336 // empty 337 } 338 339}