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.list;
018
019import java.util.Collection;
020import java.util.List;
021import java.util.ListIterator;
022
023import org.apache.commons.collections4.Transformer;
024import org.apache.commons.collections4.collection.TransformedCollection;
025import org.apache.commons.collections4.iterators.AbstractListIteratorDecorator;
026
027/**
028 * Decorates another <code>List</code> to transform objects that are added.
029 * <p>
030 * The add and set methods are affected by this class.
031 * Thus objects must be removed or searched for using their transformed form.
032 * For example, if the transformation converts Strings to Integers, you must
033 * use the Integer form to remove objects.
034 * <p>
035 * This class is Serializable from Commons Collections 3.1.
036 *
037 * @since 3.0
038 * @version $Id: TransformedList.html 972421 2015-11-14 20:00:04Z tn $
039 */
040public class TransformedList<E> extends TransformedCollection<E> implements List<E> {
041
042    /** Serialization version */
043    private static final long serialVersionUID = 1077193035000013141L;
044
045    /**
046     * Factory method to create a transforming list.
047     * <p>
048     * If there are any elements already in the list being decorated, they
049     * are NOT transformed.
050     * Contrast this with {@link #transformedList(List, Transformer)}.
051     *
052     * @param <E> the type of the elements in the list
053     * @param list  the list to decorate, must not be null
054     * @param transformer  the transformer to use for conversion, must not be null
055     * @return a new transformed list
056     * @throws IllegalArgumentException if list or transformer is null
057     * @since 4.0
058     */
059    public static <E> TransformedList<E> transformingList(final List<E> list,
060                                                          final Transformer<? super E, ? extends E> transformer) {
061        return new TransformedList<E>(list, transformer);
062    }
063
064    /**
065     * Factory method to create a transforming list that will transform
066     * existing contents of the specified list.
067     * <p>
068     * If there are any elements already in the list being decorated, they
069     * will be transformed by this method.
070     * Contrast this with {@link #transformingList(List, Transformer)}.
071     *
072     * @param <E> the type of the elements in the list
073     * @param list  the list to decorate, must not be null
074     * @param transformer  the transformer to use for conversion, must not be null
075     * @return a new transformed List
076     * @throws IllegalArgumentException if list or transformer is null
077     * @since 4.0
078     */
079    public static <E> TransformedList<E> transformedList(final List<E> list,
080                                                         final Transformer<? super E, ? extends E> transformer) {
081        final TransformedList<E> decorated = new TransformedList<E>(list, transformer);
082        if (transformer != null && list != null && list.size() > 0) {
083            @SuppressWarnings("unchecked") // list is of type E
084            final E[] values = (E[]) list.toArray(); // NOPMD - false positive for generics
085            list.clear();
086            for (final E value : values) {
087                decorated.decorated().add(transformer.transform(value));
088            }
089        }
090        return decorated;
091    }
092
093    //-----------------------------------------------------------------------
094    /**
095     * Constructor that wraps (not copies).
096     * <p>
097     * If there are any elements already in the list being decorated, they
098     * are NOT transformed.
099     *
100     * @param list  the list to decorate, must not be null
101     * @param transformer  the transformer to use for conversion, must not be null
102     * @throws IllegalArgumentException if list or transformer is null
103     */
104    protected TransformedList(final List<E> list, final Transformer<? super E, ? extends E> transformer) {
105        super(list, transformer);
106    }
107
108    /**
109     * Gets the decorated list.
110     *
111     * @return the decorated list
112     */
113    protected List<E> getList() {
114        return (List<E>) decorated();
115    }
116
117    //-----------------------------------------------------------------------
118
119    public E get(final int index) {
120        return getList().get(index);
121    }
122
123    public int indexOf(final Object object) {
124        return getList().indexOf(object);
125    }
126
127    public int lastIndexOf(final Object object) {
128        return getList().lastIndexOf(object);
129    }
130
131    public E remove(final int index) {
132        return getList().remove(index);
133    }
134
135    //-----------------------------------------------------------------------
136
137    public void add(final int index, E object) {
138        object = transform(object);
139        getList().add(index, object);
140    }
141
142    public boolean addAll(final int index, Collection<? extends E> coll) {
143        coll = transform(coll);
144        return getList().addAll(index, coll);
145    }
146
147    public ListIterator<E> listIterator() {
148        return listIterator(0);
149    }
150
151    public ListIterator<E> listIterator(final int i) {
152        return new TransformedListIterator(getList().listIterator(i));
153    }
154
155    public E set(final int index, E object) {
156        object = transform(object);
157        return getList().set(index, object);
158    }
159
160    public List<E> subList(final int fromIndex, final int toIndex) {
161        final List<E> sub = getList().subList(fromIndex, toIndex);
162        return new TransformedList<E>(sub, transformer);
163    }
164
165    /**
166     * Inner class Iterator for the TransformedList
167     */
168    protected class TransformedListIterator extends AbstractListIteratorDecorator<E> {
169
170        /**
171         * Create a new transformed list iterator.
172         *
173         * @param iterator  the list iterator to decorate
174         */
175        protected TransformedListIterator(final ListIterator<E> iterator) {
176            super(iterator);
177        }
178
179        @Override
180        public void add(E object) {
181            object = transform(object);
182            getListIterator().add(object);
183        }
184
185        @Override
186        public void set(E object) {
187            object = transform(object);
188            getListIterator().set(object);
189        }
190    }
191
192}