TransformedList.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.list;

  18. import java.util.Collection;
  19. import java.util.List;
  20. import java.util.ListIterator;

  21. import org.apache.commons.collections4.Transformer;
  22. import org.apache.commons.collections4.collection.TransformedCollection;
  23. import org.apache.commons.collections4.iterators.AbstractListIteratorDecorator;

  24. /**
  25.  * Decorates another {@code List} to transform objects that are added.
  26.  * <p>
  27.  * The add and set methods are affected by this class.
  28.  * Thus objects must be removed or searched for using their transformed form.
  29.  * For example, if the transformation converts Strings to Integers, you must
  30.  * use the Integer form to remove objects.
  31.  * </p>
  32.  * <p>
  33.  * This class is Serializable from Commons Collections 3.1.
  34.  * </p>
  35.  *
  36.  * @param <E> the type of the elements in the list.
  37.  * @since 3.0
  38.  */
  39. public class TransformedList<E> extends TransformedCollection<E> implements List<E> {

  40.     /**
  41.      * Inner class Iterator for the TransformedList
  42.      */
  43.     protected class TransformedListIterator extends AbstractListIteratorDecorator<E> {

  44.         /**
  45.          * Create a new transformed list iterator.
  46.          *
  47.          * @param iterator  the list iterator to decorate
  48.          */
  49.         protected TransformedListIterator(final ListIterator<E> iterator) {
  50.             super(iterator);
  51.         }

  52.         @Override
  53.         public void add(E object) {
  54.             object = transform(object);
  55.             getListIterator().add(object);
  56.         }

  57.         @Override
  58.         public void set(final E object) {
  59.             getListIterator().set(transform(object));
  60.         }
  61.     }

  62.     /** Serialization version */
  63.     private static final long serialVersionUID = 1077193035000013141L;

  64.     /**
  65.      * Factory method to create a transforming list that will transform
  66.      * existing contents of the specified list.
  67.      * <p>
  68.      * If there are any elements already in the list being decorated, they
  69.      * will be transformed by this method.
  70.      * Contrast this with {@link #transformingList(List, Transformer)}.
  71.      *
  72.      * @param <E> the type of the elements in the list
  73.      * @param list  the list to decorate, must not be null
  74.      * @param transformer  the transformer to use for conversion, must not be null
  75.      * @return a new transformed List
  76.      * @throws NullPointerException if list or transformer is null
  77.      * @since 4.0
  78.      */
  79.     public static <E> TransformedList<E> transformedList(final List<E> list,
  80.                                                          final Transformer<? super E, ? extends E> transformer) {
  81.         final TransformedList<E> decorated = new TransformedList<>(list, transformer);
  82.         if (!list.isEmpty()) {
  83.             @SuppressWarnings("unchecked") // list is of type E
  84.             final E[] values = (E[]) list.toArray(); // NOPMD - false positive for generics
  85.             list.clear();
  86.             for (final E value : values) {
  87.                 decorated.decorated().add(transformer.apply(value));
  88.             }
  89.         }
  90.         return decorated;
  91.     }

  92.     /**
  93.      * Factory method to create a transforming list.
  94.      * <p>
  95.      * If there are any elements already in the list being decorated, they
  96.      * are NOT transformed.
  97.      * Contrast this with {@link #transformedList(List, Transformer)}.
  98.      *
  99.      * @param <E> the type of the elements in the list
  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.      * @return a new transformed list
  103.      * @throws NullPointerException if list or transformer is null
  104.      * @since 4.0
  105.      */
  106.     public static <E> TransformedList<E> transformingList(final List<E> list,
  107.                                                           final Transformer<? super E, ? extends E> transformer) {
  108.         return new TransformedList<>(list, transformer);
  109.     }

  110.     /**
  111.      * Constructor that wraps (not copies).
  112.      * <p>
  113.      * If there are any elements already in the list being decorated, they
  114.      * are NOT transformed.
  115.      *
  116.      * @param list  the list to decorate, must not be null
  117.      * @param transformer  the transformer to use for conversion, must not be null
  118.      * @throws NullPointerException if list or transformer is null
  119.      */
  120.     protected TransformedList(final List<E> list, final Transformer<? super E, ? extends E> transformer) {
  121.         super(list, transformer);
  122.     }

  123.     @Override
  124.     public void add(final int index, E object) {
  125.         object = transform(object);
  126.         getList().add(index, object);
  127.     }

  128.     @Override
  129.     public boolean addAll(final int index, Collection<? extends E> coll) {
  130.         coll = transform(coll);
  131.         return getList().addAll(index, coll);
  132.     }

  133.     @Override
  134.     public boolean equals(final Object object) {
  135.         return object == this || decorated().equals(object);
  136.     }

  137.     @Override
  138.     public E get(final int index) {
  139.         return getList().get(index);
  140.     }

  141.     /**
  142.      * Gets the decorated list.
  143.      *
  144.      * @return the decorated list
  145.      */
  146.     protected List<E> getList() {
  147.         return (List<E>) decorated();
  148.     }

  149.     @Override
  150.     public int hashCode() {
  151.         return decorated().hashCode();
  152.     }

  153.     @Override
  154.     public int indexOf(final Object object) {
  155.         return getList().indexOf(object);
  156.     }

  157.     @Override
  158.     public int lastIndexOf(final Object object) {
  159.         return getList().lastIndexOf(object);
  160.     }

  161.     @Override
  162.     public ListIterator<E> listIterator() {
  163.         return listIterator(0);
  164.     }

  165.     @Override
  166.     public ListIterator<E> listIterator(final int i) {
  167.         return new TransformedListIterator(getList().listIterator(i));
  168.     }

  169.     @Override
  170.     public E remove(final int index) {
  171.         return getList().remove(index);
  172.     }

  173.     @Override
  174.     public E set(final int index, E object) {
  175.         object = transform(object);
  176.         return getList().set(index, object);
  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. }