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.bag; 018 019import java.util.Set; 020 021import org.apache.commons.collections4.Bag; 022import org.apache.commons.collections4.Transformer; 023import org.apache.commons.collections4.collection.TransformedCollection; 024import org.apache.commons.collections4.set.TransformedSet; 025 026/** 027 * Decorates another {@link Bag} to transform objects that are added. 028 * <p> 029 * The add methods are affected by this class. 030 * Thus objects must be removed or searched for using their transformed form. 031 * For example, if the transformation converts Strings to Integers, you must 032 * use the Integer form to remove objects. 033 * </p> 034 * <p> 035 * This class is Serializable from Commons Collections 3.1. 036 * </p> 037 * 038 * @param <E> the type of elements in this bag 039 * @since 3.0 040 */ 041public class TransformedBag<E> extends TransformedCollection<E> implements Bag<E> { 042 043 /** Serialization version */ 044 private static final long serialVersionUID = 5421170911299074185L; 045 046 /** 047 * Factory method to create a transforming bag that will transform 048 * existing contents of the specified bag. 049 * <p> 050 * If there are any elements already in the bag being decorated, they 051 * will be transformed by this method. 052 * Contrast this with {@link #transformingBag(Bag, Transformer)}. 053 * 054 * @param <E> the type of the elements in the bag 055 * @param bag the bag to decorate, must not be null 056 * @param transformer the transformer to use for conversion, must not be null 057 * @return a new transformed Bag 058 * @throws NullPointerException if bag or transformer is null 059 * @since 4.0 060 */ 061 public static <E> Bag<E> transformedBag(final Bag<E> bag, final Transformer<? super E, ? extends E> transformer) { 062 final TransformedBag<E> decorated = new TransformedBag<>(bag, transformer); 063 if (!bag.isEmpty()) { 064 @SuppressWarnings("unchecked") // Bag is of type E 065 final E[] values = (E[]) bag.toArray(); // NOPMD - false positive for generics 066 bag.clear(); 067 for (final E value : values) { 068 decorated.decorated().add(transformer.apply(value)); 069 } 070 } 071 return decorated; 072 } 073 074 /** 075 * Factory method to create a transforming bag. 076 * <p> 077 * If there are any elements already in the bag being decorated, they 078 * are NOT transformed. Contrast this with {@link #transformedBag(Bag, Transformer)}. 079 * 080 * @param <E> the type of the elements in the bag 081 * @param bag the bag to decorate, must not be null 082 * @param transformer the transformer to use for conversion, must not be null 083 * @return a new transformed Bag 084 * @throws NullPointerException if bag or transformer is null 085 * @since 4.0 086 */ 087 public static <E> Bag<E> transformingBag(final Bag<E> bag, final Transformer<? super E, ? extends E> transformer) { 088 return new TransformedBag<>(bag, transformer); 089 } 090 091 /** 092 * Constructor that wraps (not copies). 093 * <p> 094 * If there are any elements already in the bag being decorated, they 095 * are NOT transformed. 096 * 097 * @param bag the bag to decorate, must not be null 098 * @param transformer the transformer to use for conversion, must not be null 099 * @throws NullPointerException if bag or transformer is null 100 */ 101 protected TransformedBag(final Bag<E> bag, final Transformer<? super E, ? extends E> transformer) { 102 super(bag, transformer); 103 } 104 105 @Override 106 public boolean add(final E object, final int nCopies) { 107 return getBag().add(transform(object), nCopies); 108 } 109 110 @Override 111 public boolean equals(final Object object) { 112 return object == this || decorated().equals(object); 113 } 114 115 /** 116 * Gets the decorated bag. 117 * 118 * @return the decorated bag 119 */ 120 protected Bag<E> getBag() { 121 return (Bag<E>) decorated(); 122 } 123 124 @Override 125 public int getCount(final Object object) { 126 return getBag().getCount(object); 127 } 128 129 @Override 130 public int hashCode() { 131 return decorated().hashCode(); 132 } 133 134 @Override 135 public boolean remove(final Object object, final int nCopies) { 136 return getBag().remove(object, nCopies); 137 } 138 139 @Override 140 public Set<E> uniqueSet() { 141 final Set<E> set = getBag().uniqueSet(); 142 return TransformedSet.<E>transformingSet(set, transformer); 143 } 144 145}