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 * https://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.multiset;
18
19 import java.util.Set;
20
21 import org.apache.commons.collections4.MultiSet;
22 import org.apache.commons.collections4.Transformer;
23 import org.apache.commons.collections4.collection.TransformedCollection;
24 import org.apache.commons.collections4.set.TransformedSet;
25
26 /**
27 * Decorates another {@link MultiSet} to transform objects that are added.
28 * <p>
29 * The add and setCount methods are affected by this class.
30 * Thus objects must be removed or searched for using their transformed form.
31 * For example, if the transformation converts Strings to Integers, you must
32 * use the Integer form to remove objects.
33 * </p>
34 *
35 * @param <E> The type held in the multiset
36 * @since 4.6.0
37 */
38 public class TransformedMultiSet<E> extends TransformedCollection<E> implements MultiSet<E> {
39
40 /** Serialization version */
41 private static final long serialVersionUID = 20260710L;
42
43 /**
44 * Factory method to create a transforming multiset that will transform
45 * existing contents of the specified multiset.
46 * <p>
47 * If there are any elements already in the multiset being decorated, they
48 * will be transformed by this method.
49 * Contrast this with {@link #transformingMultiSet(MultiSet, Transformer)}.
50 * </p>
51 *
52 * @param <E> The type of the elements in the multiset.
53 * @param multiset The multiset to decorate, must not be null.
54 * @param transformer The transformer to use for conversion, must not be null.
55 * @return A new transformed MultiSet.
56 * @throws NullPointerException if multiset or transformer is null.
57 */
58 public static <E> TransformedMultiSet<E> transformedMultiSet(final MultiSet<E> multiset,
59 final Transformer<? super E, ? extends E> transformer) {
60 final TransformedMultiSet<E> decorated = new TransformedMultiSet<>(multiset, transformer);
61 if (!multiset.isEmpty()) {
62 @SuppressWarnings("unchecked") // multiset is of type E
63 final E[] values = (E[]) multiset.toArray(); // NOPMD - false positive for generics
64 multiset.clear();
65 for (final E value : values) {
66 decorated.decorated().add(transformer.apply(value));
67 }
68 }
69 return decorated;
70 }
71
72 /**
73 * Factory method to create a transforming multiset.
74 * <p>
75 * If there are any elements already in the multiset being decorated, they
76 * are NOT transformed. Contrast this with {@link #transformedMultiSet(MultiSet, Transformer)}.
77 * </p>
78 *
79 *
80 * @param <E> The type of the elements in the multiset.
81 * @param multiset The multiset to decorate, must not be null.
82 * @param transformer The transformer to use for conversion, must not be null.
83 * @return A new transformed MultiSet.
84 * @throws NullPointerException if multiset or transformer is null.
85 */
86 public static <E> TransformedMultiSet<E> transformingMultiSet(final MultiSet<E> multiset,
87 final Transformer<? super E, ? extends E> transformer) {
88 return new TransformedMultiSet<>(multiset, transformer);
89 }
90
91 /**
92 * Constructor that wraps (not copies).
93 * <p>
94 * If there are any elements already in the multiset being decorated, they
95 * are NOT transformed.
96 * </p>
97 *
98 * @param multiset The multiset to decorate, must not be null.
99 * @param transformer The transformer to use for conversion, must not be null.
100 * @throws NullPointerException if multiset or transformer is null.
101 */
102 protected TransformedMultiSet(final MultiSet<E> multiset, final Transformer<? super E, ? extends E> transformer) {
103 super(multiset, transformer);
104 }
105
106 @Override
107 public int add(final E object, final int occurrences) {
108 return getMultiSet().add(transform(object), occurrences);
109 }
110
111 @Override
112 public Set<MultiSet.Entry<E>> entrySet() {
113 return getMultiSet().entrySet();
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 getCount(final Object object) {
123 return getMultiSet().getCount(object);
124 }
125
126 /**
127 * Gets the decorated multiset.
128 *
129 * @return The decorated multiset.
130 */
131 protected MultiSet<E> getMultiSet() {
132 return (MultiSet<E>) decorated();
133 }
134
135 @Override
136 public int hashCode() {
137 return decorated().hashCode();
138 }
139
140 @Override
141 public int remove(final Object object, final int occurrences) {
142 return getMultiSet().remove(object, occurrences);
143 }
144
145 @Override
146 public int setCount(final E object, final int count) {
147 return getMultiSet().setCount(transform(object), count);
148 }
149
150 @Override
151 public Set<E> uniqueSet() {
152 return TransformedSet.<E>transformingSet(getMultiSet().uniqueSet(), transformer);
153 }
154
155 }