UnmodifiableEntrySet.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.collections4.map;

  18. import java.lang.reflect.Array;
  19. import java.util.Collection;
  20. import java.util.Iterator;
  21. import java.util.Map;
  22. import java.util.Set;
  23. import java.util.function.Predicate;

  24. import org.apache.commons.collections4.Unmodifiable;
  25. import org.apache.commons.collections4.iterators.AbstractIteratorDecorator;
  26. import org.apache.commons.collections4.keyvalue.AbstractMapEntryDecorator;
  27. import org.apache.commons.collections4.set.AbstractSetDecorator;

  28. /**
  29.  * Decorates a map entry {@code Set} to ensure it can't be altered.
  30.  * <p>
  31.  * Attempts to modify it will result in an UnsupportedOperationException.
  32.  * </p>
  33.  *
  34.  * @param <K> the type of the keys in the map
  35.  * @param <V> the type of the values in the map
  36.  * @since 3.0
  37.  */
  38. public final class UnmodifiableEntrySet<K, V>
  39.         extends AbstractSetDecorator<Map.Entry<K, V>> implements Unmodifiable {

  40.     /**
  41.      * Implements a map entry that is unmodifiable.
  42.      */
  43.     private final class UnmodifiableEntry extends AbstractMapEntryDecorator<K, V> {

  44.         protected UnmodifiableEntry(final Map.Entry<K, V> entry) {
  45.             super(entry);
  46.         }

  47.         @Override
  48.         public V setValue(final V value) {
  49.             throw new UnsupportedOperationException();
  50.         }
  51.     }

  52.     /**
  53.      * Implements an entry set iterator.
  54.      */
  55.     private final class UnmodifiableEntrySetIterator extends AbstractIteratorDecorator<Map.Entry<K, V>> {

  56.         protected UnmodifiableEntrySetIterator(final Iterator<Map.Entry<K, V>> iterator) {
  57.             super(iterator);
  58.         }

  59.         @Override
  60.         public Map.Entry<K, V> next() {
  61.             return new UnmodifiableEntry(getIterator().next());
  62.         }

  63.         @Override
  64.         public void remove() {
  65.             throw new UnsupportedOperationException();
  66.         }
  67.     }

  68.     /** Serialization version */
  69.     private static final long serialVersionUID = 1678353579659253473L;

  70.     /**
  71.      * Factory method to create an unmodifiable set of Map Entry objects.
  72.      *
  73.      * @param <K>  the key type
  74.      * @param <V>  the value type
  75.      * @param set  the set to decorate, must not be null
  76.      * @return a new unmodifiable entry set
  77.      * @throws NullPointerException if set is null
  78.      * @since 4.0
  79.      */
  80.     public static <K, V> Set<Map.Entry<K, V>> unmodifiableEntrySet(final Set<Map.Entry<K, V>> set) {
  81.         if (set instanceof Unmodifiable) {
  82.             return set;
  83.         }
  84.         return new UnmodifiableEntrySet<>(set);
  85.     }

  86.     /**
  87.      * Constructor that wraps (not copies).
  88.      *
  89.      * @param set  the set to decorate, must not be null
  90.      * @throws NullPointerException if set is null
  91.      */
  92.     private UnmodifiableEntrySet(final Set<Map.Entry<K, V>> set) {
  93.         super(set);
  94.     }

  95.     @Override
  96.     public boolean add(final Map.Entry<K, V> object) {
  97.         throw new UnsupportedOperationException();
  98.     }

  99.     @Override
  100.     public boolean addAll(final Collection<? extends Map.Entry<K, V>> coll) {
  101.         throw new UnsupportedOperationException();
  102.     }

  103.     @Override
  104.     public void clear() {
  105.         throw new UnsupportedOperationException();
  106.     }

  107.     @Override
  108.     public Iterator<Map.Entry<K, V>> iterator() {
  109.         return new UnmodifiableEntrySetIterator(decorated().iterator());
  110.     }

  111.     @Override
  112.     public boolean remove(final Object object) {
  113.         throw new UnsupportedOperationException();
  114.     }

  115.     @Override
  116.     public boolean removeAll(final Collection<?> coll) {
  117.         throw new UnsupportedOperationException();
  118.     }

  119.     /**
  120.      * @since 4.4
  121.      */
  122.     @Override
  123.     public boolean removeIf(final Predicate<? super Map.Entry<K, V>> filter) {
  124.         throw new UnsupportedOperationException();
  125.     }

  126.     @Override
  127.     public boolean retainAll(final Collection<?> coll) {
  128.         throw new UnsupportedOperationException();
  129.     }

  130.     @Override
  131.     @SuppressWarnings("unchecked")
  132.     public Object[] toArray() {
  133.         final Object[] array = decorated().toArray();
  134.         for (int i = 0; i < array.length; i++) {
  135.             array[i] = new UnmodifiableEntry((Map.Entry<K, V>) array[i]);
  136.         }
  137.         return array;
  138.     }

  139.     @Override
  140.     @SuppressWarnings("unchecked")
  141.     public <T> T[] toArray(final T[] array) {
  142.         Object[] result = array;
  143.         if (array.length > 0) {
  144.             // we must create a new array to handle multithreaded situations
  145.             // where another thread could access data before we decorate it
  146.             result = (Object[]) Array.newInstance(array.getClass().getComponentType(), 0);
  147.         }
  148.         result = decorated().toArray(result);
  149.         for (int i = 0; i < result.length; i++) {
  150.             result[i] = new UnmodifiableEntry((Map.Entry<K, V>) result[i]);
  151.         }

  152.         // check to see if result should be returned straight
  153.         if (result.length > array.length) {
  154.             return (T[]) result;
  155.         }

  156.         // copy back into input array to fulfill the method contract
  157.         System.arraycopy(result, 0, array, 0, result.length);
  158.         if (array.length > result.length) {
  159.             array[result.length] = null;
  160.         }
  161.         return array;
  162.     }

  163. }