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.map;
018
019import java.io.IOException;
020import java.io.ObjectInputStream;
021import java.io.ObjectOutputStream;
022import java.io.Serializable;
023import java.util.Collection;
024import java.util.Map;
025import java.util.Set;
026
027import org.apache.commons.collections4.set.UnmodifiableSet;
028import org.apache.commons.collections4.IterableMap;
029import org.apache.commons.collections4.MapIterator;
030import org.apache.commons.collections4.Unmodifiable;
031import org.apache.commons.collections4.collection.UnmodifiableCollection;
032import org.apache.commons.collections4.iterators.EntrySetMapIterator;
033import org.apache.commons.collections4.iterators.UnmodifiableMapIterator;
034
035/**
036 * Decorates another <code>Map</code> to ensure it can't be altered.
037 * <p>
038 * This class is Serializable from Commons Collections 3.1.
039 * <p>
040 * Attempts to modify it will result in an UnsupportedOperationException.
041 *
042 * @since 3.0
043 * @version $Id: UnmodifiableMap.html 972421 2015-11-14 20:00:04Z tn $
044 */
045public final class UnmodifiableMap<K, V>
046        extends AbstractMapDecorator<K, V>
047        implements Unmodifiable, Serializable {
048
049    /** Serialization version */
050    private static final long serialVersionUID = 2737023427269031941L;
051
052    /**
053     * Factory method to create an unmodifiable map.
054     *
055     * @param <K>  the key type
056     * @param <V>  the value type
057     * @param map  the map to decorate, must not be null
058     * @return a new unmodifiable map
059     * @throws IllegalArgumentException if map is null
060     * @since 4.0
061     */
062    public static <K, V> Map<K, V> unmodifiableMap(final Map<? extends K, ? extends V> map) {
063        if (map instanceof Unmodifiable) {
064            @SuppressWarnings("unchecked") // safe to upcast
065            final Map<K, V> tmpMap = (Map<K, V>) map;
066            return tmpMap;
067        }
068        return new UnmodifiableMap<K, V>(map);
069    }
070
071    //-----------------------------------------------------------------------
072    /**
073     * Constructor that wraps (not copies).
074     *
075     * @param map  the map to decorate, must not be null
076     * @throws IllegalArgumentException if map is null
077     */
078    @SuppressWarnings("unchecked") // safe to upcast
079    private UnmodifiableMap(final Map<? extends K, ? extends V> map) {
080        super((Map<K, V>) map);
081    }
082
083    //-----------------------------------------------------------------------
084    /**
085     * Write the map out using a custom routine.
086     *
087     * @param out  the output stream
088     * @throws IOException
089     * @since 3.1
090     */
091    private void writeObject(final ObjectOutputStream out) throws IOException {
092        out.defaultWriteObject();
093        out.writeObject(map);
094    }
095
096    /**
097     * Read the map in using a custom routine.
098     *
099     * @param in  the input stream
100     * @throws IOException
101     * @throws ClassNotFoundException
102     * @since 3.1
103     */
104    @SuppressWarnings("unchecked")
105    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
106        in.defaultReadObject();
107        map = (Map<K, V>) in.readObject();
108    }
109
110    //-----------------------------------------------------------------------
111    @Override
112    public void clear() {
113        throw new UnsupportedOperationException();
114    }
115
116    @Override
117    public V put(final K key, final V value) {
118        throw new UnsupportedOperationException();
119    }
120
121    @Override
122    public void putAll(final Map<? extends K, ? extends V> mapToCopy) {
123        throw new UnsupportedOperationException();
124    }
125
126    @Override
127    public V remove(final Object key) {
128        throw new UnsupportedOperationException();
129    }
130
131    @Override
132    public MapIterator<K, V> mapIterator() {
133        if (map instanceof IterableMap) {
134            final MapIterator<K, V> it = ((IterableMap<K, V>) map).mapIterator();
135            return UnmodifiableMapIterator.unmodifiableMapIterator(it);
136        }
137        final MapIterator<K, V> it = new EntrySetMapIterator<K, V>(map);
138        return UnmodifiableMapIterator.unmodifiableMapIterator(it);
139    }
140
141    @Override
142    public Set<Map.Entry<K, V>> entrySet() {
143        final Set<Map.Entry<K, V>> set = super.entrySet();
144        return UnmodifiableEntrySet.unmodifiableEntrySet(set);
145    }
146
147    @Override
148    public Set<K> keySet() {
149        final Set<K> set = super.keySet();
150        return UnmodifiableSet.unmodifiableSet(set);
151    }
152
153    @Override
154    public Collection<V> values() {
155        final Collection<V> coll = super.values();
156        return UnmodifiableCollection.unmodifiableCollection(coll);
157    }
158
159}