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.juneau.commons.utils;
018
019import static java.util.stream.Collectors.*;
020
021import java.util.*;
022import java.util.function.*;
023
024/**
025 * Utility methods for making copies and clones of collections, maps, arrays, and cloneable objects.
026 *
027 * <p>
028 * This class is the canonical home for the {@code copyOf(...)} family (collection/map/array defensive copies)
029 * and {@link #cloneOf(Object)} (reflective null-safe clone).  It is intentionally <b>subclassable</b> (via a
030 * <jk>protected</jk> constructor) so that per-module utility classes can add domain-specific
031 * <c>copyOf(&lt;BeanType&gt;)</c> overloads that coexist with the inherited collection overloads via ordinary Java
032 * overload resolution.  A single static-import-on-demand of such a subclass brings in <b>both</b> the inherited
033 * collection overloads and the module's bean overloads.
034 *
035 * <h5 class='section'>See Also:</h5><ul>
036 *    <li class='jc'>{@link CollectionUtils}
037 * </ul>
038 */
039@SuppressWarnings({
040   "java:S1118" // Utility class with static methods only — intentionally subclassable via a protected constructor.
041})
042public class CopyUtils {
043
044   /** Constructor — this class is meant to be subclassed. */
045   protected CopyUtils() {}
046
047   /**
048    * Creates a new collection from the specified collection.
049    *
050    * @param <E> The element type.
051    * @param val The value to copy from.
052    * @return A new {@link LinkedHashSet}, or <jk>null</jk> if the input was null.
053    */
054   public static <E> Collection<E> copyOf(Collection<E> val) {
055      return val == null ? null : new LinkedHashSet<>(val);
056   }
057
058   /**
059    * Convenience method for copying a list.
060    *
061    * @param <E> The element type.
062    * @param value The list to copy.
063    * @return A new modifiable list.
064    */
065   public static <E> List<E> copyOf(List<E> value) {
066      return value == null ? null : new ArrayList<>(value);
067   }
068
069   /**
070    * Makes a deep copy of the specified list.
071    *
072    * @param l The list to copy.
073    * @param valueMapper The function to apply to each value in the list.
074    * @param <E> The entry type.
075    * @return A new list with the same values as the specified list, but with values transformed by the specified function.  Null if the list being copied was null.
076    */
077   public static <E> List<E> copyOf(List<E> l, Function<? super E,? extends E> valueMapper) {
078      return copyOf(l, valueMapper, LinkedList::new);
079   }
080
081   /**
082    * Makes a deep copy of the specified list.
083    *
084    * @param l The list to copy.
085    * @param valueMapper The function to apply to each value in the list.
086    * @param <E> The entry type.
087    * @param listFactory The factory for creating the list.
088    * @return A new list with the same values as the specified list, but with values transformed by the specified function.  Null if the list being copied was null.
089    */
090   public static <E> List<E> copyOf(List<E> l, Function<? super E,? extends E> valueMapper, Supplier<List<E>> listFactory) {
091      return l == null ? null : l.stream().map(valueMapper).collect(toCollection(listFactory));
092   }
093
094   /**
095    * Creates a new map from the specified map.
096    *
097    * @param <K> The key type.
098    * @param <V> The value type.
099    * @param val The value to copy from.
100    * @return A new {@link LinkedHashMap}, or <jk>null</jk> if the input was null.
101    */
102   public static <K,V> Map<K,V> copyOf(Map<K,V> val) {
103      return val == null ? null : new LinkedHashMap<>(val);
104   }
105
106   /**
107    * Makes a deep copy of the specified map.
108    *
109    * @param <K> The key type.
110    * @param <V> The value type.
111    * @param m The map to copy.
112    * @param valueMapper The function to apply to each value in the map.
113    * @return A new map with the same keys as the specified map, but with values transformed by the specified function.  Null if the map being copied was null.
114    */
115   public static <K,V> Map<K,V> copyOf(Map<K,V> m, Function<? super V,? extends V> valueMapper) {
116      return copyOf(m, valueMapper, LinkedHashMap::new);
117   }
118
119   /**
120    * Makes a deep copy of the specified map.
121    *
122    * @param <K> The key type.
123    * @param <V> The value type.
124    * @param m The map to copy.
125    * @param valueMapper The function to apply to each value in the map.
126    * @param mapFactory The factory for creating the map.
127    * @return A new map with the same keys as the specified map, but with values transformed by the specified function.  Null if the map being copied was null.
128    */
129   public static <K,V> Map<K,V> copyOf(Map<K,V> m, Function<? super V,? extends V> valueMapper, Supplier<Map<K,V>> mapFactory) {
130      return m == null ? null : m.entrySet().stream().collect(toMap(Map.Entry::getKey, e -> valueMapper.apply(e.getValue()), (a, b) -> b, mapFactory));
131   }
132
133   /**
134    * Creates a new set from the specified collection.
135    *
136    * @param <E> The element type.
137    * @param val The value to copy from.
138    * @return A new {@link LinkedHashSet}, or <jk>null</jk> if the input was null.
139    */
140   public static <E> Set<E> copyOf(Set<E> val) {
141      return val == null ? null : new LinkedHashSet<>(val);
142   }
143
144   /**
145    * Makes a deep copy of the specified list.
146    *
147    * @param l The list to copy.
148    * @param valueMapper The function to apply to each value in the list.
149    * @param <E> The entry type.
150    * @return A new list with the same values as the specified list, but with values transformed by the specified function.  Null if the list being copied was null.
151    */
152   public static <E> Set<E> copyOf(Set<E> l, Function<? super E,? extends E> valueMapper) {
153      return copyOf(l, valueMapper, LinkedHashSet::new);
154   }
155
156   /**
157    * Makes a deep copy of the specified list.
158    *
159    * @param l The list to copy.
160    * @param valueMapper The function to apply to each value in the list.
161    * @param <E> The entry type.
162    * @param setFactory The factory for creating sets.
163    * @return A new list with the same values as the specified list, but with values transformed by the specified function.  Null if the list being copied was null.
164    */
165   public static <E> Set<E> copyOf(Set<E> l, Function<? super E,? extends E> valueMapper, Supplier<Set<E>> setFactory) {
166      return l == null ? null : l.stream().map(valueMapper).collect(toCollection(setFactory));
167   }
168
169   /**
170    * Makes a copy of the specified array.
171    *
172    * @param array The array to copy.
173    * @param <T> The element type.
174    * @return A new copy of the array, or <jk>null</jk> if the array was <jk>null</jk>.s
175    */
176   public static <T> T[] copyOf(T[] array) {
177      return array == null ? null : Arrays.copyOf(array, array.length);
178   }
179
180   /**
181    * Makes a copy of the specified array.
182    *
183    * @param array The array to copy.
184    * @return A new copy of the array, or <jk>null</jk> if the array was <jk>null</jk>.
185    */
186   public static byte[] copyOf(byte[] array) {
187      return array == null ? null : Arrays.copyOf(array, array.length);
188   }
189
190   /**
191    * Makes a copy of the specified array.
192    *
193    * @param array The array to copy.
194    * @return A new copy of the array, or <jk>null</jk> if the array was <jk>null</jk>.
195    */
196   public static char[] copyOf(char[] array) {
197      return array == null ? null : Arrays.copyOf(array, array.length);
198   }
199
200   /**
201    * Makes a copy of the specified array.
202    *
203    * @param array The array to copy.
204    * @return A new copy of the array, or <jk>null</jk> if the array was <jk>null</jk>.
205    */
206   public static int[] copyOf(int[] array) {
207      return array == null ? null : Arrays.copyOf(array, array.length);
208   }
209
210   /**
211    * Makes a copy of the specified array.
212    *
213    * @param array The array to copy.
214    * @return A new copy of the array, or <jk>null</jk> if the array was <jk>null</jk>.
215    */
216   public static long[] copyOf(long[] array) {
217      return array == null ? null : Arrays.copyOf(array, array.length);
218   }
219
220   /**
221    * Makes a copy of the specified array.
222    *
223    * @param array The array to copy.
224    * @return A new copy of the array, or <jk>null</jk> if the array was <jk>null</jk>.
225    */
226   public static short[] copyOf(short[] array) {
227      return array == null ? null : Arrays.copyOf(array, array.length);
228   }
229
230   /**
231    * Makes a copy of the specified array.
232    *
233    * @param array The array to copy.
234    * @return A new copy of the array, or <jk>null</jk> if the array was <jk>null</jk>.
235    */
236   public static boolean[] copyOf(boolean[] array) {
237      return array == null ? null : Arrays.copyOf(array, array.length);
238   }
239
240   /**
241    * Makes a copy of the specified array.
242    *
243    * @param array The array to copy.
244    * @return A new copy of the array, or <jk>null</jk> if the array was <jk>null</jk>.
245    */
246   public static double[] copyOf(double[] array) {
247      return array == null ? null : Arrays.copyOf(array, array.length);
248   }
249
250   /**
251    * Makes a copy of the specified array.
252    *
253    * @param array The array to copy.
254    * @return A new copy of the array, or <jk>null</jk> if the array was <jk>null</jk>.
255    */
256   public static float[] copyOf(float[] array) {
257      return array == null ? null : Arrays.copyOf(array, array.length);
258   }
259
260   /**
261    * Null-safe clone of an object via its public {@code clone()} method.
262    *
263    * <p>
264    * Invokes the object's {@code clone()} method reflectively (since {@link Object#clone()} is <jk>protected</jk> and
265    * {@link Cloneable} declares no {@code clone()} method, a generic caller cannot invoke it directly), returning the
266    * result typed as the input.
267    *
268    * @param <T> The object type.
269    * @param value The value to clone.  Can be <jk>null</jk>.
270    * @return A clone of the value, or <jk>null</jk> if the value was <jk>null</jk>.
271    * @throws IllegalArgumentException if the value's runtime type does not expose a public {@code clone()} method, or the clone failed.
272    */
273   @SuppressWarnings({
274      "unchecked" // Reflective clone() returns Object; the cast to the input type T is safe.
275   })
276   public static <T> T cloneOf(T value) {
277      if (value == null)
278         return null;
279      try {
280         return (T) value.getClass().getMethod("clone").invoke(value);
281      } catch (ReflectiveOperationException e) {
282         throw new IllegalArgumentException("Value of type " + value.getClass().getName() + " is not cloneable via a public clone() method.", e);
283      }
284   }
285}