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(<BeanType>)</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}