View Javadoc
1   package fr.ifremer.quadrige3.core.dao.technical;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 Core Shared
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   *
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   *
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import com.google.common.collect.Multimap;
27  import com.google.common.collect.Multimaps;
28  import fr.ifremer.quadrige3.core.exception.QuadrigeTechnicalException;
29  import org.apache.commons.beanutils.PropertyUtils;
30  import org.apache.commons.collections4.CollectionUtils;
31  import org.apache.commons.lang3.StringUtils;
32  
33  import java.lang.reflect.InvocationTargetException;
34  import java.util.*;
35  import java.util.function.Function;
36  import java.util.function.Predicate;
37  import java.util.regex.Pattern;
38  import java.util.stream.Collectors;
39  
40  /**
41   * helper class for beans (split by property, make sure list exists, ...)
42   * Created by blavenie on 13/10/15.
43   */
44  public class Beans {
45  
46      /**
47       * <p>mapByProperty.</p>
48       *
49       * @param collection         a {@link Collection} object.
50       * @param propertyName a {@link java.lang.String} object.
51       * @param <K>          a K object.
52       * @param <V>          a V object.
53       * @return a {@link java.util.Map} object.
54       */
55      public static <K, V> Map<K, V> mapByProperty(Collection<V> collection, String propertyName) {
56          if (CollectionUtils.isEmpty(collection)) return new HashMap<>();
57          Assert.notBlank(propertyName);
58          return collection.stream().collect(Collectors.toMap(
59                  o -> getProperty(o, propertyName),
60                  o -> o,
61                  (k1, k2) -> { // if duplicates found
62                      throw new IllegalStateException(String.format("Duplicate key %s", k1));
63                  },
64                  HashMap::new)
65          );
66  //        return collection != null
67  //                ? new HashMap<>(Maps.uniqueIndex(collection, input -> getProperty(input, propertyName)))
68  //                : new HashMap<>();
69      }
70  
71      /**
72       * <p>collectProperties.</p>
73       *
74       * @param collection   a {@link java.util.Collection} object.
75       * @param propertyName a {@link java.lang.String} object.
76       * @param <K>          a K object.
77       * @param <V>          a V object.
78       * @return a {@link java.util.List} object.
79       */
80      public static <K, V> List<K> collectProperties(Collection<V> collection, String propertyName) {
81          if (CollectionUtils.isEmpty(collection)) return new ArrayList<>();
82          Assert.notBlank(propertyName);
83  //        return collection.stream().map((Function<V, K>) v -> getProperty(v, propertyName)).collect(Collectors.toList());
84          return collection.stream().map((Function<V, K>) v -> getProperty(v, propertyName)).collect(Collectors.toList());
85  
86      }
87  
88      /**
89       * <p>populateByProperty.</p>
90       *
91       * @param list         a {@link Iterable} object.
92       * @param propertyName a {@link String} object.
93       * @param <K>          a K object.
94       * @param <V>          a V object.
95       * @return a {@link Multimap} object.
96       */
97      public static <K, V> Multimap<K, V> populateByProperty(Iterable<V> list, String propertyName) {
98          Assert.notBlank(propertyName);
99          return Multimaps.index(list, input -> getProperty(input, propertyName));
100     }
101 
102     /**
103      * <p>findByProperty.</p>
104      *
105      * @param collection     a {@link Collection} object.
106      * @param propertyName a {@link String} object.
107      * @param value        a {@link Object} object.
108      * @param <B>          a B object.
109      * @return a B object.
110      */
111     public static <B> B findByProperty(Collection<B> collection, String propertyName, Object value) {
112         if (collection == null) return null;
113         Assert.notBlank(propertyName);
114         return collection.stream().filter(object -> Objects.equals(value, getProperty(object, propertyName))).findFirst().orElse(null);
115     }
116 
117     /**
118      * <p>getProperty.</p>
119      *
120      * @param object       a K object.
121      * @param propertyName a {@link java.lang.String} object.
122      * @param <K>          a K object.
123      * @param <V>          a V object.
124      * @return a V object.
125      */
126     @SuppressWarnings("unchecked")
127     public static <K, V> V getProperty(K object, String propertyName) {
128         try {
129             return (V) PropertyUtils.getProperty(object, propertyName);
130         } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
131             throw new QuadrigeTechnicalException(String.format("Could not get property %1s on object of type %2s", propertyName, object.getClass().getName()), e);
132         }
133     }
134 
135     /**
136      * <p>setProperty.</p>
137      *
138      * @param object       a K object.
139      * @param propertyName a {@link java.lang.String} object.
140      * @param value        a V object.
141      * @param <K>          a K object.
142      * @param <V>          a V object.
143      */
144     public static <K, V> void setProperty(K object, String propertyName, V value) {
145         try {
146             PropertyUtils.setProperty(object, propertyName, value);
147         } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
148             throw new QuadrigeTechnicalException(String.format("Could not set property %1s not found on object of type %2s", propertyName, object.getClass().getName()), e);
149         }
150     }
151 
152     public static List<String> split(String string, String separator) {
153         if (StringUtils.isBlank(string)) return new ArrayList<>();
154         Assert.notBlank(separator);
155         String[] items = string.split(Pattern.quote(separator));
156         return Arrays.stream(items).filter(Objects::nonNull).map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList());
157     }
158 
159     public static Map<String, String> splitAndMap(String string, String separator, String keyValueSeparator) {
160         if (StringUtils.isBlank(string)) return new HashMap<>();
161         Assert.notBlank(separator);
162         Assert.notBlank(keyValueSeparator);
163         List<String> items = split(string, separator);
164         return items.stream().map(s -> s.split(Pattern.quote(keyValueSeparator)))
165                 .collect(Collectors.toMap(a -> a[0].trim(), a -> a.length > 1 ? a[1].trim() : "",
166                         (u, v) -> {
167                             throw new IllegalStateException(String.format("Duplicate key %s", u));
168                         }, LinkedHashMap::new));
169     }
170 
171     public static Integer[] asIntegerArray(Collection<Integer> values) {
172         if (CollectionUtils.isEmpty(values)) return null;
173         return values.toArray(new Integer[0]);
174     }
175 
176     public static String[] asStringArray(Collection<String> values) {
177         if (CollectionUtils.isEmpty(values)) return null;
178         return values.toArray(new String[0]);
179     }
180 
181     public static Set<Integer> getIntegerSetFromString(String string, String separator) {
182         List<String> list = split(string, separator);
183         Set<Integer> ints = new HashSet<>();
184         for (String s : list) {
185             try {
186                 ints.add(Integer.valueOf(s));
187             } catch (NumberFormatException ignored) {
188             }
189         }
190         return ints;
191     }
192 
193     public static <E> List<E> filterCollection(Collection<E> collection, Predicate<E> predicate) {
194         return collection.stream().filter(predicate).collect(Collectors.toList());
195     }
196 
197     public static <O, E> List<O> transformCollection(Collection<? extends E> collection, Function<E, O> function) {
198         return collection.stream().map(function).collect(Collectors.toList());
199     }
200 
201     /**
202      * Fill both list with absent elements from each other. Keep insertion order safe.
203      *
204      * @param list1 a {@link List} object.
205      * @param list2 a {@link List} object.
206      */
207     public static <O> void fillListsEachOther(List<O> list1, List<O> list2) {
208 
209         if (list1 == null || list2 == null) {
210             return;
211         }
212 
213         for (O bean : list1) {
214             if (!list2.contains(bean)) {
215                 list2.add(bean);
216             }
217         }
218 
219         for (O bean : list2) {
220             if (!list1.contains(bean)) {
221                 list1.add(bean);
222             }
223         }
224     }
225 
226     /**
227      * <p>roundDouble.</p>
228      *
229      * @param number a {@link Double} object.
230      * @return a {@link Double} object.
231      */
232     public static Double roundDouble(Double number) {
233         return roundDouble(number, 2);
234     }
235 
236     /**
237      * <p>roundDouble.</p>
238      *
239      * @param number    a {@link Double} object.
240      * @param nbDecimal a int.
241      * @return a {@link Double} object.
242      */
243     public static Double roundDouble(Double number, int nbDecimal) {
244         if (number == null) {
245             return null;
246         }
247         if (nbDecimal == 0) {
248             return (double) Math.round(number);
249         }
250         double oper = Math.pow(10, nbDecimal);
251         return Math.round(number * oper) / oper;
252     }
253 
254 }