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 * http://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.Set; 022 023import org.apache.commons.collections4.set.UnmodifiableSet; 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; 028 029/** 030 * Utilities for working with "split maps:" objects that implement {@link Put} 031 * and/or {@link Get} but not {@link Map}. 032 * 033 * @since 4.0 034 * @version $Id: SplitMapUtils.html 972421 2015-11-14 20:00:04Z tn $ 035 * 036 * @see Get 037 * @see Put 038 */ 039public class SplitMapUtils { 040 041 /** 042 * <code>SplitMapUtils</code> should not normally be instantiated. 043 */ 044 private SplitMapUtils() {} 045 046 //----------------------------------------------------------------------- 047 048 private static class WrappedGet<K, V> implements IterableMap<K, V>, Unmodifiable { 049 private final Get<K, V> get; 050 051 private WrappedGet(final Get<K, V> get) { 052 this.get = get; 053 } 054 055 public void clear() { 056 throw new UnsupportedOperationException(); 057 } 058 059 public boolean containsKey(final Object key) { 060 return get.containsKey(key); 061 } 062 063 public boolean containsValue(final Object value) { 064 return get.containsValue(value); 065 } 066 067 public Set<Map.Entry<K, V>> entrySet() { 068 return UnmodifiableEntrySet.unmodifiableEntrySet(get.entrySet()); 069 } 070 071 @Override 072 public boolean equals(final Object arg0) { 073 if (arg0 == this) { 074 return true; 075 } 076 return arg0 instanceof WrappedGet && ((WrappedGet<?, ?>) arg0).get.equals(this.get); 077 } 078 079 public V get(final Object key) { 080 return get.get(key); 081 } 082 083 @Override 084 public int hashCode() { 085 return ("WrappedGet".hashCode() << 4) | get.hashCode(); 086 } 087 088 public boolean isEmpty() { 089 return get.isEmpty(); 090 } 091 092 public Set<K> keySet() { 093 return UnmodifiableSet.unmodifiableSet(get.keySet()); 094 } 095 096 public V put(final K key, final V value) { 097 throw new UnsupportedOperationException(); 098 } 099 100 public void putAll(final Map<? extends K, ? extends V> t) { 101 throw new UnsupportedOperationException(); 102 } 103 104 public V remove(final Object key) { 105 return get.remove(key); 106 } 107 108 public int size() { 109 return get.size(); 110 } 111 112 public Collection<V> values() { 113 return UnmodifiableCollection.unmodifiableCollection(get.values()); 114 } 115 116 public MapIterator<K, V> mapIterator() { 117 MapIterator<K, V> it; 118 if (get instanceof IterableGet) { 119 it = ((IterableGet<K, V>) get).mapIterator(); 120 } else { 121 it = new EntrySetToMapIteratorAdapter<K, V>(get.entrySet()); 122 } 123 return UnmodifiableMapIterator.unmodifiableMapIterator(it); 124 } 125 } 126 127 private static class WrappedPut<K, V> implements Map<K, V>, Put<K, V> { 128 private final Put<K, V> put; 129 130 private WrappedPut(final Put<K, V> put) { 131 this.put = put; 132 } 133 134 public void clear() { 135 put.clear(); 136 } 137 138 public boolean containsKey(final Object key) { 139 throw new UnsupportedOperationException(); 140 } 141 142 public boolean containsValue(final Object value) { 143 throw new UnsupportedOperationException(); 144 } 145 146 public Set<Map.Entry<K, V>> entrySet() { 147 throw new UnsupportedOperationException(); 148 } 149 150 @Override 151 public boolean equals(final Object obj) { 152 if (obj == this) { 153 return true; 154 } 155 return obj instanceof WrappedPut && ((WrappedPut<?, ?>) obj).put.equals(this.put); 156 } 157 158 public V get(final Object key) { 159 throw new UnsupportedOperationException(); 160 } 161 162 @Override 163 public int hashCode() { 164 return ("WrappedPut".hashCode() << 4) | put.hashCode(); 165 } 166 167 public boolean isEmpty() { 168 throw new UnsupportedOperationException(); 169 } 170 171 public Set<K> keySet() { 172 throw new UnsupportedOperationException(); 173 } 174 175 @SuppressWarnings("unchecked") 176 public V put(final K key, final V value) { 177 return (V) put.put(key, value); 178 } 179 180 public void putAll(final Map<? extends K, ? extends V> t) { 181 put.putAll(t); 182 } 183 184 public V remove(final Object key) { 185 throw new UnsupportedOperationException(); 186 } 187 188 public int size() { 189 throw new UnsupportedOperationException(); 190 } 191 192 public Collection<V> values() { 193 throw new UnsupportedOperationException(); 194 } 195 } 196 197 //----------------------------------------------------------------------- 198 199 /** 200 * Get the specified {@link Get} as an instance of {@link IterableMap}. 201 * If <code>get</code> implements {@link IterableMap} directly, no conversion will take place. 202 * If <code>get</code> implements {@link Map} but not {@link IterableMap} it will be decorated. 203 * Otherwise an {@link Unmodifiable} {@link IterableMap} will be returned. 204 * @param <K> the key type 205 * @param <V> the value type 206 * @param get to wrap, must not be null 207 * @return {@link IterableMap} 208 */ 209 @SuppressWarnings("unchecked") 210 public static <K, V> IterableMap<K, V> readableMap(final Get<K, V> get) { 211 if (get == null) { 212 throw new IllegalArgumentException("Get must not be null"); 213 } 214 if (get instanceof Map) { 215 return get instanceof IterableMap ? ((IterableMap<K, V>) get) : MapUtils 216 .iterableMap((Map<K, V>) get); 217 } 218 return new WrappedGet<K, V>(get); 219 } 220 221 /** 222 * Get the specified {@link Put} as an instanceof {@link Map}. 223 * If <code>put</code> implements {@link Map} directly, no conversion will take place. 224 * Otherwise a <em>write-only</em> {@link Map} will be returned. On such a {@link Map} 225 * it is recommended that the result of #put(K, V) be discarded as it likely will not 226 * match <code>V</code> at runtime. 227 * 228 * @param <K> the key type 229 * @param <V> the element type 230 * @param put to wrap, must not be null 231 * @return {@link Map} 232 */ 233 @SuppressWarnings("unchecked") 234 public static <K, V> Map<K, V> writableMap(final Put<K, V> put) { 235 if (put == null) { 236 throw new IllegalArgumentException("Put must not be null"); 237 } 238 if (put instanceof Map) { 239 return (Map<K, V>) put; 240 } 241 return new WrappedPut<K, V>(put); 242 } 243 244}