TransformedCollection.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.collection;

  18. import java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.List;
  21. import java.util.Objects;

  22. import org.apache.commons.collections4.Transformer;

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

  39.     /** Serialization version */
  40.     private static final long serialVersionUID = 8692300188161871514L;

  41.     /**
  42.      * Factory method to create a transforming collection that will transform
  43.      * existing contents of the specified collection.
  44.      * <p>
  45.      * If there are any elements already in the collection being decorated, they
  46.      * will be transformed by this method.
  47.      * Contrast this with {@link #transformingCollection(Collection, Transformer)}.
  48.      *
  49.      * @param <E> the type of the elements in the collection
  50.      * @param collection  the collection to decorate, must not be null
  51.      * @param transformer  the transformer to use for conversion, must not be null
  52.      * @return a new transformed Collection
  53.      * @throws NullPointerException if collection or transformer is null
  54.      * @since 4.0
  55.      */
  56.     public static <E> TransformedCollection<E> transformedCollection(final Collection<E> collection,
  57.             final Transformer<? super E, ? extends E> transformer) {

  58.         final TransformedCollection<E> decorated = new TransformedCollection<>(collection, transformer);
  59.         // null collection & transformer are disallowed by the constructor call above
  60.         if (!collection.isEmpty()) {
  61.             @SuppressWarnings("unchecked") // collection is of type E
  62.             final E[] values = (E[]) collection.toArray(); // NOPMD - false positive for generics
  63.             collection.clear();
  64.             for (final E value : values) {
  65.                 decorated.decorated().add(transformer.apply(value));
  66.             }
  67.         }
  68.         return decorated;
  69.     }

  70.     /**
  71.      * Factory method to create a transforming collection.
  72.      * <p>
  73.      * If there are any elements already in the collection being decorated, they
  74.      * are NOT transformed.
  75.      * Contrast this with {@link #transformedCollection(Collection, Transformer)}.
  76.      *
  77.      * @param <E> the type of the elements in the collection
  78.      * @param coll  the collection to decorate, must not be null
  79.      * @param transformer  the transformer to use for conversion, must not be null
  80.      * @return a new transformed collection
  81.      * @throws NullPointerException if collection or transformer is null
  82.      * @since 4.0
  83.      */
  84.     public static <E> TransformedCollection<E> transformingCollection(final Collection<E> coll,
  85.             final Transformer<? super E, ? extends E> transformer) {
  86.         return new TransformedCollection<>(coll, transformer);
  87.     }

  88.     /** The transformer to use */
  89.     protected final Transformer<? super E, ? extends E> transformer;

  90.     /**
  91.      * Constructor that wraps (not copies).
  92.      * <p>
  93.      * If there are any elements already in the collection being decorated, they
  94.      * are NOT transformed.
  95.      *
  96.      * @param collection  the collection to decorate, must not be null
  97.      * @param transformer  the transformer to use for conversion, must not be null
  98.      * @throws NullPointerException if collection or transformer is null
  99.      */
  100.     protected TransformedCollection(final Collection<E> collection, final Transformer<? super E, ? extends E> transformer) {
  101.         super(collection);
  102.         this.transformer = Objects.requireNonNull(transformer, "transformer");
  103.     }

  104.     @Override
  105.     public boolean add(final E object) {
  106.         return decorated().add(transform(object));
  107.     }

  108.     @Override
  109.     public boolean addAll(final Collection<? extends E> coll) {
  110.         return decorated().addAll(transform(coll));
  111.     }

  112.     /**
  113.      * Transforms a collection.
  114.      * <p>
  115.      * The transformer itself may throw an exception if necessary.
  116.      *
  117.      * @param coll  the collection to transform
  118.      * @return a transformed object
  119.      */
  120.     protected Collection<E> transform(final Collection<? extends E> coll) {
  121.         final List<E> list = new ArrayList<>(coll.size());
  122.         for (final E item : coll) {
  123.             list.add(transform(item));
  124.         }
  125.         return list;
  126.     }

  127.     /**
  128.      * Transforms an object.
  129.      * <p>
  130.      * The transformer itself may throw an exception if necessary.
  131.      *
  132.      * @param object  the object to transform
  133.      * @return a transformed object
  134.      */
  135.     protected E transform(final E object) {
  136.         return transformer.apply(object);
  137.     }

  138. }