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.list;
18
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.ListIterator;
22
23 import org.apache.commons.collections4.Transformer;
24 import org.apache.commons.collections4.collection.TransformedCollection;
25 import org.apache.commons.collections4.iterators.AbstractListIteratorDecorator;
26
27 /**
28 * Decorates another {@code List} to transform objects that are added.
29 * <p>
30 * The add and set methods are affected by this class.
31 * Thus objects must be removed or searched for using their transformed form.
32 * For example, if the transformation converts Strings to Integers, you must
33 * use the Integer form to remove objects.
34 * </p>
35 * <p>
36 * This class is Serializable from Commons Collections 3.1.
37 * </p>
38 *
39 * @param <E> the type of the elements in the list.
40 * @since 3.0
41 */
42 public class TransformedList<E> extends TransformedCollection<E> implements List<E> {
43
44 /**
45 * Inner class Iterator for the TransformedList
46 */
47 protected class TransformedListIterator extends AbstractListIteratorDecorator<E> {
48
49 /**
50 * Create a new transformed list iterator.
51 *
52 * @param iterator the list iterator to decorate
53 */
54 protected TransformedListIterator(final ListIterator<E> iterator) {
55 super(iterator);
56 }
57
58 @Override
59 public void add(E object) {
60 object = transform(object);
61 getListIterator().add(object);
62 }
63
64 @Override
65 public void set(final E object) {
66 getListIterator().set(transform(object));
67 }
68 }
69
70 /** Serialization version */
71 private static final long serialVersionUID = 1077193035000013141L;
72
73 /**
74 * Factory method to create a transforming list that will transform
75 * existing contents of the specified list.
76 * <p>
77 * If there are any elements already in the list being decorated, they
78 * will be transformed by this method.
79 * Contrast this with {@link #transformingList(List, Transformer)}.
80 *
81 * @param <E> the type of the elements in the list
82 * @param list the list to decorate, must not be null
83 * @param transformer the transformer to use for conversion, must not be null
84 * @return a new transformed List
85 * @throws NullPointerException if list or transformer is null
86 * @since 4.0
87 */
88 public static <E> TransformedList<E> transformedList(final List<E> list,
89 final Transformer<? super E, ? extends E> transformer) {
90 final TransformedList<E> decorated = new TransformedList<>(list, transformer);
91 if (!list.isEmpty()) {
92 @SuppressWarnings("unchecked") // list is of type E
93 final E[] values = (E[]) list.toArray(); // NOPMD - false positive for generics
94 list.clear();
95 for (final E value : values) {
96 decorated.decorated().add(transformer.apply(value));
97 }
98 }
99 return decorated;
100 }
101
102 /**
103 * Factory method to create a transforming list.
104 * <p>
105 * If there are any elements already in the list being decorated, they
106 * are NOT transformed.
107 * Contrast this with {@link #transformedList(List, Transformer)}.
108 *
109 * @param <E> the type of the elements in the list
110 * @param list the list to decorate, must not be null
111 * @param transformer the transformer to use for conversion, must not be null
112 * @return a new transformed list
113 * @throws NullPointerException if list or transformer is null
114 * @since 4.0
115 */
116 public static <E> TransformedList<E> transformingList(final List<E> list,
117 final Transformer<? super E, ? extends E> transformer) {
118 return new TransformedList<>(list, transformer);
119 }
120
121 /**
122 * Constructor that wraps (not copies).
123 * <p>
124 * If there are any elements already in the list being decorated, they
125 * are NOT transformed.
126 *
127 * @param list the list to decorate, must not be null
128 * @param transformer the transformer to use for conversion, must not be null
129 * @throws NullPointerException if list or transformer is null
130 */
131 protected TransformedList(final List<E> list, final Transformer<? super E, ? extends E> transformer) {
132 super(list, transformer);
133 }
134
135 @Override
136 public void add(final int index, E object) {
137 object = transform(object);
138 getList().add(index, object);
139 }
140
141 @Override
142 public boolean addAll(final int index, Collection<? extends E> coll) {
143 coll = transform(coll);
144 return getList().addAll(index, coll);
145 }
146
147 @Override
148 public boolean equals(final Object object) {
149 return object == this || decorated().equals(object);
150 }
151
152 @Override
153 public E get(final int index) {
154 return getList().get(index);
155 }
156
157 /**
158 * Gets the decorated list.
159 *
160 * @return the decorated list
161 */
162 protected List<E> getList() {
163 return (List<E>) decorated();
164 }
165
166 @Override
167 public int hashCode() {
168 return decorated().hashCode();
169 }
170
171 @Override
172 public int indexOf(final Object object) {
173 return getList().indexOf(object);
174 }
175
176 @Override
177 public int lastIndexOf(final Object object) {
178 return getList().lastIndexOf(object);
179 }
180
181 @Override
182 public ListIterator<E> listIterator() {
183 return listIterator(0);
184 }
185
186 @Override
187 public ListIterator<E> listIterator(final int i) {
188 return new TransformedListIterator(getList().listIterator(i));
189 }
190
191 @Override
192 public E remove(final int index) {
193 return getList().remove(index);
194 }
195
196 @Override
197 public E set(final int index, E object) {
198 object = transform(object);
199 return getList().set(index, object);
200 }
201
202 @Override
203 public List<E> subList(final int fromIndex, final int toIndex) {
204 final List<E> sub = getList().subList(fromIndex, toIndex);
205 return new TransformedList<>(sub, transformer);
206 }
207
208 }