1 package net.sumaris.core.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import com.google.common.base.Preconditions;
28 import com.google.common.collect.*;
29 import net.sumaris.core.dao.technical.SortDirection;
30 import net.sumaris.core.dao.technical.model.IEntity;
31 import net.sumaris.core.exception.SumarisTechnicalException;
32 import org.apache.commons.beanutils.PropertyUtils;
33 import org.apache.commons.collections4.CollectionUtils;
34 import org.apache.commons.collections4.ComparatorUtils;
35 import org.apache.commons.collections4.MapUtils;
36 import org.apache.commons.lang3.ArrayUtils;
37 import org.apache.commons.lang3.StringUtils;
38 import org.springframework.beans.BeanUtils;
39
40 import java.beans.PropertyDescriptor;
41 import java.io.Serializable;
42 import java.lang.reflect.InvocationTargetException;
43 import java.util.*;
44 import java.util.function.Function;
45 import java.util.function.Predicate;
46 import java.util.stream.Collectors;
47 import java.util.stream.Stream;
48
49
50
51
52
53 public class Beans {
54
55 protected Beans() {
56
57 }
58
59
60
61
62
63
64
65
66 public static <E> List<E> getList(Collection<E> list) {
67 if (CollectionUtils.isEmpty(list)) {
68 return Lists.newArrayList();
69 } else if (list instanceof List<?>){
70 return (List<E>) list;
71 } else {
72 return Lists.newArrayList(list);
73 }
74 }
75
76
77
78
79
80
81
82
83 public static <E> Stream<E> getStream(Collection<E> list) {
84 if (list == null) {
85 return Stream.empty();
86 }
87 return list.stream();
88 }
89
90
91
92
93
94
95
96
97 public static <E> List<E> getListWithoutNull(Collection<E> list) {
98 List<E> result = getList(list);
99 result.removeAll(Collections.singleton((E) null));
100 return result;
101 }
102
103
104
105
106
107
108
109
110 public static <E> Set<E> getSet(Collection<E> list) {
111 if (CollectionUtils.isEmpty(list)) {
112 return Sets.newHashSet();
113 } else {
114 return Sets.newHashSet(list);
115 }
116 }
117
118
119
120
121
122
123
124
125 public static <E> Set<E> getSetWithoutNull(Collection<E> list) {
126 Set<E> result = getSet(list);
127 result.removeAll(Collections.singleton((E) null));
128 return result;
129 }
130
131
132
133
134
135
136
137
138
139 public static <K, V> Map<K, V> getMap(Map<K, V> map) {
140 if (MapUtils.isEmpty(map)) {
141 return Maps.newHashMap();
142 } else {
143 return Maps.newHashMap(map);
144 }
145 }
146
147
148
149
150
151
152
153
154
155
156 public static <K, V> Map<K, V> splitByProperty(Iterable<V> list, String propertyName) {
157 Preconditions.checkArgument(StringUtils.isNotBlank(propertyName));
158 return getMap(Maps.uniqueIndex(list, input -> getProperty(input, propertyName)));
159 }
160
161
162
163
164
165
166
167
168
169
170 public static <K, V> Multimap<K, V> splitByNotUniqueProperty(Iterable<V> list, String propertyName) {
171 Preconditions.checkArgument(StringUtils.isNotBlank(propertyName));
172 return Multimaps.index(list, input -> getProperty(input, propertyName));
173 }
174
175
176
177
178
179
180
181
182 public static <V> Multimap<Integer, V> splitByNotUniqueHashcode(Iterable<V> list) {
183 return Multimaps.index(list, Object::hashCode);
184 }
185
186
187
188
189
190
191
192
193
194 public static <K extends Serializable, V extends IEntity<K>> Map<K, V> splitById(Iterable<V> list) {
195 return getMap(Maps.uniqueIndex(list, IEntity::getId));
196 }
197
198
199
200
201
202
203
204
205
206 public static <K extends Serializable, V extends IEntity<K>> List<K> collectIds(Collection<V> list) {
207 return transformCollection(list, IEntity::getId);
208 }
209
210
211
212
213
214
215
216
217
218
219 public static <K, V> List<K> collectProperties(Collection<V> collection, String propertyName) {
220 if (CollectionUtils.isEmpty(collection)) return new ArrayList<>();
221 Preconditions.checkArgument(StringUtils.isNotBlank(propertyName));
222 return collection.stream().map((Function<V, K>) v -> getProperty(v, propertyName)).collect(Collectors.toList());
223
224 }
225
226 private static <K, V> Function<V, K> newPropertyFunction(final String propertyName) {
227 return input -> getProperty(input, propertyName);
228 }
229
230
231
232
233
234
235
236
237
238
239 @SuppressWarnings("unchecked")
240 public static <K, V> V getProperty(K object, String propertyName) {
241 try {
242 return (V) PropertyUtils.getProperty(object, propertyName);
243 } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
244 throw new SumarisTechnicalException( String.format("Could not get property %1s on object of type %2s", propertyName, object.getClass().getName()), e);
245 }
246 }
247
248
249
250
251
252
253
254
255
256
257 public static <K, V> void setProperty(K object, String propertyName, V value) {
258 try {
259 PropertyUtils.setProperty(object, propertyName, value);
260 } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
261 throw new SumarisTechnicalException( String.format("Could not set property %1s not found on object of type %2s", propertyName, object.getClass().getName()), e);
262 }
263 }
264
265 public static Integer[] asIntegerArray(Collection<Integer> values) {
266 if (CollectionUtils.isEmpty(values)) {
267 return null;
268 }
269 return values.toArray(new Integer[0]);
270 }
271
272 public static String[] asStringArray(Collection<String> values) {
273 if (CollectionUtils.isEmpty(values)) {
274 return null;
275 }
276 return values.toArray(new String[0]);
277 }
278
279 public static String[] asStringArray(String value, String delimiter) {
280 if (StringUtils.isBlank(value)) return new String[0];
281 StringTokenizer tokenizer = new StringTokenizer(value, delimiter);
282 String[] values = new String[tokenizer.countTokens()];
283 int i=0;
284 while (tokenizer.hasMoreTokens()) {
285 values[i] = tokenizer.nextToken();
286 i++;
287 }
288 return values;
289 }
290
291 public static <E> List<E> filterCollection(Collection<E> collection, Predicate<E> predicate) {
292 return collection.stream().filter(predicate).collect(Collectors.toList());
293 }
294
295 public static <O, E> List<O> transformCollection(Collection<? extends E> collection, Function<E, O> funtion) {
296 return collection.stream().map(funtion).collect(Collectors.toList());
297 }
298
299 public static <T> Comparator<T> naturalComparator(final String sortAttribute, final SortDirection sortDirection) {
300 if (sortAttribute == null) {
301 return naturalComparator("id", sortDirection);
302 }
303
304 final Comparator<String> propertyComparator = ComparatorUtils.naturalComparator();
305
306 if (SortDirection.ASC.equals(sortDirection)) {
307 return (o1, o2) -> propertyComparator.compare(
308 getProperty(o1, sortAttribute),
309 getProperty(o2, sortAttribute)
310 );
311 }
312 else {
313 return (o1, o2) -> propertyComparator.compare(
314 getProperty(o2, sortAttribute),
315 getProperty(o1, sortAttribute)
316 );
317 }
318 }
319
320
321 public static Map<Class<?>, Map<Class<?>, String[]>> cacheCopyPropertiesIgnored = Maps.newConcurrentMap();
322
323
324
325
326
327
328 public static <S, T> void copyProperties(S source, T target) {
329 copyProperties(source, target, (String) null);
330 }
331
332
333
334
335
336
337 public static <S, T> void copyProperties(S source, T target, String... exceptProperties) {
338
339 Map<Class<?>, String[]> cache = cacheCopyPropertiesIgnored.computeIfAbsent(source.getClass(), k -> Maps.newConcurrentMap());
340 String[] ignoredProperties = cache.get(target.getClass());
341
342
343 if (ignoredProperties == null) {
344
345 PropertyDescriptor[] targetDescriptors = BeanUtils.getPropertyDescriptors(target.getClass());
346 Map<String, PropertyDescriptor> targetProperties = Maps.uniqueIndex(ImmutableList.copyOf(targetDescriptors), PropertyDescriptor::getName);
347
348 ignoredProperties = Stream.of(BeanUtils.getPropertyDescriptors(source.getClass()))
349
350 .filter(pd -> {
351 PropertyDescriptor targetDescriptor = targetProperties.get(pd.getName());
352 return targetDescriptor == null
353 || !targetDescriptor.getPropertyType().isAssignableFrom(pd.getPropertyType())
354 || Collection.class.isAssignableFrom(pd.getPropertyType())
355 || targetDescriptor.getWriteMethod() == null;
356 })
357 .map(PropertyDescriptor::getName)
358 .toArray(String[]::new);
359
360
361 cache.put(target.getClass(), ignoredProperties);
362 }
363
364 BeanUtils.copyProperties(source, target, ArrayUtils.addAll(ignoredProperties, exceptProperties));
365 }
366 }