View Javadoc
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  
19  import java.util.Comparator;
20  import java.util.Map;
21  import java.util.SortedMap;
22  
23  import org.apache.commons.collections4.Transformer;
24  
25  /**
26   * Decorates another {@code SortedMap } to transform objects that are added.
27   * <p>
28   * The Map put methods and Map.Entry setValue method are affected by this class.
29   * Thus objects must be removed or searched for using their transformed form.
30   * For example, if the transformation converts Strings to Integers, you must
31   * use the Integer form to remove objects.
32   * </p>
33   * <p>
34   * <strong>Note that TransformedSortedMap is not synchronized and is not thread-safe.</strong>
35   * If you wish to use this map from multiple threads concurrently, you must use
36   * appropriate synchronization. The simplest approach is to wrap this map
37   * using {@link java.util.Collections#synchronizedSortedMap}. This class may throw
38   * exceptions when accessed by concurrent threads without synchronization.
39   * </p>
40   * <p>
41   * This class is Serializable from Commons Collections 3.1.
42   * </p>
43   *
44   * @param <K> the type of the keys in this map
45   * @param <V> the type of the values in this map
46   * @since 3.0
47   */
48  public class TransformedSortedMap<K, V>
49          extends TransformedMap<K, V>
50          implements SortedMap<K, V> {
51  
52      /** Serialization version */
53      private static final long serialVersionUID = -8751771676410385778L;
54  
55      /**
56       * Factory method to create a transforming sorted map that will transform
57       * existing contents of the specified map.
58       * <p>
59       * If there are any elements already in the map being decorated, they
60       * will be transformed by this method.
61       * Contrast this with {@link #transformingSortedMap(SortedMap, Transformer, Transformer)}.
62       *
63       * @param <K>  the key type
64       * @param <V>  the value type
65       * @param map  the map to decorate, must not be null
66       * @param keyTransformer  the transformer to use for key conversion, null means no transformation
67       * @param valueTransformer  the transformer to use for value conversion, null means no transformation
68       * @return a new transformed sorted map
69       * @throws NullPointerException if map is null
70       * @since 4.0
71       */
72      public static <K, V> TransformedSortedMap<K, V> transformedSortedMap(final SortedMap<K, V> map,
73              final Transformer<? super K, ? extends K> keyTransformer,
74              final Transformer<? super V, ? extends V> valueTransformer) {
75  
76          final TransformedSortedMap<K, V> decorated =
77                  new TransformedSortedMap<>(map, keyTransformer, valueTransformer);
78          if (!map.isEmpty()) {
79              final Map<K, V> transformed = decorated.transformMap(map);
80              decorated.clear();
81              decorated.decorated().putAll(transformed);  // avoids double transformation
82          }
83          return decorated;
84      }
85  
86      /**
87       * Factory method to create a transforming sorted map.
88       * <p>
89       * If there are any elements already in the map being decorated, they are NOT transformed.
90       * Contrast this with {@link #transformedSortedMap(SortedMap, Transformer, Transformer)}.
91       *
92       * @param <K>  the key type
93       * @param <V>  the value type
94       * @param map  the map to decorate, must not be null
95       * @param keyTransformer  the predicate to validate the keys, null means no transformation
96       * @param valueTransformer  the predicate to validate to values, null means no transformation
97       * @return a new transformed sorted map
98       * @throws NullPointerException if the map is null
99       * @since 4.0
100      */
101     public static <K, V> TransformedSortedMap<K, V> transformingSortedMap(final SortedMap<K, V> map,
102             final Transformer<? super K, ? extends K> keyTransformer,
103             final Transformer<? super V, ? extends V> valueTransformer) {
104         return new TransformedSortedMap<>(map, keyTransformer, valueTransformer);
105     }
106 
107     /**
108      * Constructor that wraps (not copies).
109      * <p>
110      * If there are any elements already in the collection being decorated, they
111      * are NOT transformed.</p>
112      *
113      * @param map  the map to decorate, must not be null
114      * @param keyTransformer  the predicate to validate the keys, null means no transformation
115      * @param valueTransformer  the predicate to validate to values, null means no transformation
116      * @throws NullPointerException if the map is null
117      */
118     protected TransformedSortedMap(final SortedMap<K, V> map,
119             final Transformer<? super K, ? extends K> keyTransformer,
120             final Transformer<? super V, ? extends V> valueTransformer) {
121         super(map, keyTransformer, valueTransformer);
122     }
123 
124     @Override
125     public Comparator<? super K> comparator() {
126         return getSortedMap().comparator();
127     }
128 
129     @Override
130     public K firstKey() {
131         return getSortedMap().firstKey();
132     }
133 
134     /**
135      * Gets the map being decorated.
136      *
137      * @return the decorated map
138      */
139     protected SortedMap<K, V> getSortedMap() {
140         return (SortedMap<K, V>) map;
141     }
142 
143     @Override
144     public SortedMap<K, V> headMap(final K toKey) {
145         final SortedMap<K, V> map = getSortedMap().headMap(toKey);
146         return new TransformedSortedMap<>(map, keyTransformer, valueTransformer);
147     }
148 
149     @Override
150     public K lastKey() {
151         return getSortedMap().lastKey();
152     }
153 
154     @Override
155     public SortedMap<K, V> subMap(final K fromKey, final K toKey) {
156         final SortedMap<K, V> map = getSortedMap().subMap(fromKey, toKey);
157         return new TransformedSortedMap<>(map, keyTransformer, valueTransformer);
158     }
159 
160     @Override
161     public SortedMap<K, V> tailMap(final K fromKey) {
162         final SortedMap<K, V> map = getSortedMap().tailMap(fromKey);
163         return new TransformedSortedMap<>(map, keyTransformer, valueTransformer);
164     }
165 
166 }