SplitMapUtils.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;

  18. import java.util.Collection;
  19. import java.util.Map;
  20. import java.util.Objects;
  21. import java.util.Set;

  22. import org.apache.commons.collections4.collection.UnmodifiableCollection;
  23. import org.apache.commons.collections4.iterators.UnmodifiableMapIterator;
  24. import org.apache.commons.collections4.map.EntrySetToMapIteratorAdapter;
  25. import org.apache.commons.collections4.map.UnmodifiableEntrySet;
  26. import org.apache.commons.collections4.set.UnmodifiableSet;

  27. /**
  28.  * Utilities for working with "split maps:" objects that implement {@link Put}
  29.  * and/or {@link Get} but not {@link Map}.
  30.  *
  31.  * @since 4.0
  32.  * @see Get
  33.  * @see Put
  34.  */
  35. public class SplitMapUtils {

  36.     private static final class WrappedGet<K, V> implements IterableMap<K, V>, Unmodifiable {
  37.         private final Get<K, V> get;

  38.         private WrappedGet(final Get<K, V> get) {
  39.             this.get = get;
  40.         }

  41.         @Override
  42.         public void clear() {
  43.             throw new UnsupportedOperationException();
  44.         }

  45.         @Override
  46.         public boolean containsKey(final Object key) {
  47.             return get.containsKey(key);
  48.         }

  49.         @Override
  50.         public boolean containsValue(final Object value) {
  51.             return get.containsValue(value);
  52.         }

  53.         @Override
  54.         public Set<Map.Entry<K, V>> entrySet() {
  55.             return UnmodifiableEntrySet.unmodifiableEntrySet(get.entrySet());
  56.         }

  57.         @Override
  58.         public boolean equals(final Object arg0) {
  59.             if (arg0 == this) {
  60.                 return true;
  61.             }
  62.             return arg0 instanceof WrappedGet && ((WrappedGet<?, ?>) arg0).get.equals(get);
  63.         }

  64.         @Override
  65.         public V get(final Object key) {
  66.             return get.get(key);
  67.         }

  68.         @Override
  69.         public int hashCode() {
  70.             return "WrappedGet".hashCode() << 4 | get.hashCode();
  71.         }

  72.         @Override
  73.         public boolean isEmpty() {
  74.             return get.isEmpty();
  75.         }

  76.         @Override
  77.         public Set<K> keySet() {
  78.             return UnmodifiableSet.unmodifiableSet(get.keySet());
  79.         }

  80.         @Override
  81.         public MapIterator<K, V> mapIterator() {
  82.             final MapIterator<K, V> it;
  83.             if (get instanceof IterableGet) {
  84.                 it = ((IterableGet<K, V>) get).mapIterator();
  85.             } else {
  86.                 it = new EntrySetToMapIteratorAdapter<>(get.entrySet());
  87.             }
  88.             return UnmodifiableMapIterator.unmodifiableMapIterator(it);
  89.         }

  90.         @Override
  91.         public V put(final K key, final V value) {
  92.             throw new UnsupportedOperationException();
  93.         }

  94.         @Override
  95.         public void putAll(final Map<? extends K, ? extends V> t) {
  96.             throw new UnsupportedOperationException();
  97.         }

  98.         @Override
  99.         public V remove(final Object key) {
  100.             return get.remove(key);
  101.         }

  102.         @Override
  103.         public int size() {
  104.             return get.size();
  105.         }

  106.         @Override
  107.         public Collection<V> values() {
  108.             return UnmodifiableCollection.unmodifiableCollection(get.values());
  109.         }
  110.     }

  111.     private static final class WrappedPut<K, V> implements Map<K, V>, Put<K, V> {
  112.         private final Put<K, V> put;

  113.         private WrappedPut(final Put<K, V> put) {
  114.             this.put = put;
  115.         }

  116.         @Override
  117.         public void clear() {
  118.             put.clear();
  119.         }

  120.         @Override
  121.         public boolean containsKey(final Object key) {
  122.             throw new UnsupportedOperationException();
  123.         }

  124.         @Override
  125.         public boolean containsValue(final Object value) {
  126.             throw new UnsupportedOperationException();
  127.         }

  128.         @Override
  129.         public Set<Map.Entry<K, V>> entrySet() {
  130.             throw new UnsupportedOperationException();
  131.         }

  132.         @Override
  133.         public boolean equals(final Object obj) {
  134.             if (obj == this) {
  135.                 return true;
  136.             }
  137.             return obj instanceof WrappedPut && ((WrappedPut<?, ?>) obj).put.equals(put);
  138.         }

  139.         @Override
  140.         public V get(final Object key) {
  141.             throw new UnsupportedOperationException();
  142.         }

  143.         @Override
  144.         public int hashCode() {
  145.             return "WrappedPut".hashCode() << 4 | put.hashCode();
  146.         }

  147.         @Override
  148.         public boolean isEmpty() {
  149.             throw new UnsupportedOperationException();
  150.         }

  151.         @Override
  152.         public Set<K> keySet() {
  153.             throw new UnsupportedOperationException();
  154.         }

  155.         @Override
  156.         @SuppressWarnings("unchecked")
  157.         public V put(final K key, final V value) {
  158.             return (V) put.put(key, value);
  159.         }

  160.         @Override
  161.         public void putAll(final Map<? extends K, ? extends V> t) {
  162.             put.putAll(t);
  163.         }

  164.         @Override
  165.         public V remove(final Object key) {
  166.             throw new UnsupportedOperationException();
  167.         }

  168.         @Override
  169.         public int size() {
  170.             throw new UnsupportedOperationException();
  171.         }

  172.         @Override
  173.         public Collection<V> values() {
  174.             throw new UnsupportedOperationException();
  175.         }
  176.     }

  177.     /**
  178.      * Gets the specified {@link Get} as an instance of {@link IterableMap}.
  179.      * If {@code get} implements {@link IterableMap} directly, no conversion will take place.
  180.      * If {@code get} implements {@link Map} but not {@link IterableMap} it will be decorated.
  181.      * Otherwise, an {@link Unmodifiable} {@link IterableMap} will be returned.
  182.      *
  183.      * @param <K> the key type
  184.      * @param <V> the value type
  185.      * @param get to wrap, must not be null
  186.      * @return {@link IterableMap}
  187.      * @throws NullPointerException if the argument is null
  188.      */
  189.     @SuppressWarnings("unchecked")
  190.     public static <K, V> IterableMap<K, V> readableMap(final Get<K, V> get) {
  191.         Objects.requireNonNull(get, "get");
  192.         if (get instanceof Map) {
  193.             return get instanceof IterableMap ?
  194.                     (IterableMap<K, V>) get :
  195.                     MapUtils.iterableMap((Map<K, V>) get);
  196.         }
  197.         return new WrappedGet<>(get);
  198.     }

  199.     /**
  200.      * Gets the specified {@link Put} as an instanceof {@link Map}.
  201.      * If {@code put} implements {@link Map} directly, no conversion will take place.
  202.      * Otherwise, a <em>write-only</em> {@link Map} will be returned.  On such a {@link Map}
  203.      * it is recommended that the result of #put(K, V) be discarded as it likely will not
  204.      * match {@code V} at runtime.
  205.      *
  206.      * @param <K> the key type
  207.      * @param <V> the element type
  208.      * @param put to wrap, must not be null
  209.      * @return {@link Map}
  210.      * @throws NullPointerException if the argument is null
  211.      */
  212.     @SuppressWarnings("unchecked")
  213.     public static <K, V> Map<K, V> writableMap(final Put<K, V> put) {
  214.         Objects.requireNonNull(put, "put");
  215.         if (put instanceof Map) {
  216.             return (Map<K, V>) put;
  217.         }
  218.         return new WrappedPut<>(put);
  219.     }

  220.     /**
  221.      * Don't allow instances.
  222.      */
  223.     private SplitMapUtils() {
  224.         // empty
  225.     }

  226. }