    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 */
    039public class TransformedList<E> extends TransformedCollection<E> implements List<E> {
    040
    041    /** Serialization version */
    042    private static final long serialVersionUID = 1077193035000013141L;
    043
    044    /**
    045     * Factory method to create a transforming list.
    046     * <p>
    047     * If there are any elements already in the list being decorated, they
    048     * are NOT transformed.
    049     * Contrast this with {@link #transformedList(List, Transformer)}.
    050     *
    051     * @param <E> the type of the elements in the list
    052     * @param list  the list to decorate, must not be null
    053     * @param transformer  the transformer to use for conversion, must not be null
    054     * @return a new transformed list
    055     * @throws NullPointerException if list or transformer is null
    056     * @since 4.0
    057     */
    058    public static <E> TransformedList<E> transformingList(final List<E> list,
    059                                                          final Transformer<? super E, ? extends E> transformer) {
    060        return new TransformedList<>(list, transformer);
    061    }
    062
    063    /**
    064     * Factory method to create a transforming list that will transform
    065     * existing contents of the specified list.
    066     * <p>
    067     * If there are any elements already in the list being decorated, they
    068     * will be transformed by this method.
    069     * Contrast this with {@link #transformingList(List, Transformer)}.
    070     *
    071     * @param <E> the type of the elements in the list
    072     * @param list  the list to decorate, must not be null
    073     * @param transformer  the transformer to use for conversion, must not be null
    074     * @return a new transformed List
    075     * @throws NullPointerException if list or transformer is null
    076     * @since 4.0
    077     */
    078    public static <E> TransformedList<E> transformedList(final List<E> list,
    079                                                         final Transformer<? super E, ? extends E> transformer) {
    080        final TransformedList<E> decorated = new TransformedList<>(list, transformer);
    081        if (list.size() > 0) {
    082            @SuppressWarnings("unchecked") // list is of type E
    083            final E[] values = (E[]) list.toArray(); // NOPMD - false positive for generics
    084            list.clear();
    085            for (final E value : values) {
    086                decorated.decorated().add(transformer.transform(value));
    087            }
    088        }
    089        return decorated;
    090    }
    091
    092    //-----------------------------------------------------------------------
    093    /**
    094     * Constructor that wraps (not copies).
    095     * <p>
    096     * If there are any elements already in the list being decorated, they
    097     * are NOT transformed.
    098     *
    099     * @param list  the list to decorate, must not be null
    100     * @param transformer  the transformer to use for conversion, must not be null
    101     * @throws NullPointerException if list or transformer is null
    102     */
    103    protected TransformedList(final List<E> list, final Transformer<? super E, ? extends E> transformer) {
    104        super(list, transformer);
    105    }
    106
    107    /**
    108     * Gets the decorated list.
    109     *
    110     * @return the decorated list
    111     */
    112    protected List<E> getList() {
    113        return (List<E>) decorated();
    114    }
    115
    116    @Override
    117    public boolean equals(final Object object) {
    118        return object == this || decorated().equals(object);
    119    }
    120
    121    @Override
    122    public int hashCode() {
    123        return decorated().hashCode();
    124    }
    125
    126    //-----------------------------------------------------------------------
    127
    128    @Override
    129    public E get(final int index) {
    130        return getList().get(index);
    131    }
    132
    133    @Override
    134    public int indexOf(final Object object) {
    135        return getList().indexOf(object);
    136    }
    137
    138    @Override
    139    public int lastIndexOf(final Object object) {
    140        return getList().lastIndexOf(object);
    141    }
    142
    143    @Override
    144    public E remove(final int index) {
    145        return getList().remove(index);
    146    }
    147
    148    //-----------------------------------------------------------------------
    149
    150    @Override
    151    public void add(final int index, E object) {
    152        object = transform(object);
    153        getList().add(index, object);
    154    }
    155
    156    @Override
    157    public boolean addAll(final int index, Collection<? extends E> coll) {
    158        coll = transform(coll);
    159        return getList().addAll(index, coll);
    160    }
    161
    162    @Override
    163    public ListIterator<E> listIterator() {
    164        return listIterator(0);
    165    }
    166
    167    @Override
    168    public ListIterator<E> listIterator(final int i) {
    169        return new TransformedListIterator(getList().listIterator(i));
    170    }
    171
    172    @Override
    173    public E set(final int index, E object) {
    174        object = transform(object);
    175        return getList().set(index, object);
    176    }
    177
    178    @Override
    179    public List<E> subList(final int fromIndex, final int toIndex) {
    180        final List<E> sub = getList().subList(fromIndex, toIndex);
    181        return new TransformedList<>(sub, transformer);
    182    }
    183
    184    /**
    185     * Inner class Iterator for the TransformedList
    186     */
    187    protected class TransformedListIterator extends AbstractListIteratorDecorator<E> {
    188
    189        /**
    190         * Create a new transformed list iterator.
    191         *
    192         * @param iterator  the list iterator to decorate
    193         */
    194        protected TransformedListIterator(final ListIterator<E> iterator) {
    195            super(iterator);
    196        }
    197
    198        @Override
    199        public void add(E object) {
    200            object = transform(object);
    201            getListIterator().add(object);
    202        }
    203
    204        @Override
    205        public void set(E object) {
    206            object = transform(object);
    207            getListIterator().set(object);
    208        }
    209    }
    210
    211}