001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.internal;
014
015import static org.apache.juneau.internal.StringUtils.*;
016
017import java.lang.reflect.*;
018import java.util.*;
019
020import org.apache.juneau.*;
021import org.apache.juneau.parser.*;
022
023/**
024 * Utility methods when working with setting of bean properties.
025 */
026public final class BeanPropertyUtils {
027
028   /**
029    * Converts a value to a String.
030    *
031    * @param o The value to convert.
032    * @return The converted value, or <jk>null</jk> if the input was null.
033    */
034   public static String toStringVal(Object o) {
035      return StringUtils.asString(o);
036   }
037
038   /**
039    * Converts a value to a Boolean.
040    *
041    * @param o The value to convert.
042    * @return The converted value, or <jk>null</jk> if the input was null.
043    */
044   public static Boolean toBoolean(Object o) {
045      return ObjectUtils.toBoolean(o);
046   }
047
048   /**
049    * Converts a value to a Number.
050    *
051    * @param o The value to convert.
052    * @return The converted value, or <jk>null</jk> if the input was null.
053    */
054   public static Number toNumber(Object o) {
055      return ObjectUtils.toNumber(o);
056   }
057
058   /**
059    * Converts a value to an Integer.
060    *
061    * @param o The value to convert.
062    * @return The converted value, or <jk>null</jk> if the input was null.
063    */
064   public static Integer toInteger(Object o) {
065      return ObjectUtils.toInteger(o);
066   }
067
068   /**
069    * Converts a value to a URI.
070    *
071    * @param o The value to convert.
072    * @return The converted value, or <jk>null</jk> if the input was null.
073    */
074   public static java.net.URI toURI(Object o) {
075      return StringUtils.toURI(o);
076   }
077
078   /**
079    * Adds a set of values to an existing list.
080    *
081    * @param appendTo
082    *    The list to append to.
083    *    <br>If <jk>null</jk>, a new {@link ArrayList} will be created.
084    * @param values The values to add.
085    * @param type The data type of the elements.
086    * @param args The generic type arguments of the data type.
087    * @return The converted value, or <jk>null</jk> if the input was null.
088    */
089   public static <T> List<T> addToList(List<T> appendTo, Object[] values, Class<T> type, Type...args) {
090      if (values == null)
091         return appendTo;
092      try {
093         List<T> l = appendTo;
094         if (appendTo == null)
095            l = new ArrayList<>();
096         for (Object o : values) {
097            if (o != null) {
098               if (isObjectList(o, false)) {
099                  for (Object o2 : new ObjectList(o.toString()))
100                     l.add(toType(o2, type, args));
101               } else if (o instanceof Collection) {
102                  for (Object o2 : (Collection<?>)o)
103                     l.add(toType(o2, type, args));
104               } else if (o.getClass().isArray()) {
105                  for (int i = 0; i < Array.getLength(o); i++)
106                     l.add(toType(Array.get(o, i), type, args));
107               } else {
108                  l.add(toType(o, type, args));
109               }
110            }
111         }
112         return l.isEmpty() ? null : l;
113      } catch (ParseException e) {
114         throw new RuntimeException(e);
115      }
116   }
117
118   /**
119    * Adds a set of values to an existing map.
120    *
121    * @param appendTo
122    *    The map to append to.
123    *    <br>If <jk>null</jk>, a new {@link LinkedHashMap} will be created.
124    * @param values The values to add.
125    * @param keyType The data type of the keys.
126    * @param valueType The data type of the values.
127    * @param valueTypeArgs The generic type arguments of the data type of the values.
128    * @return The converted value, or <jk>null</jk> if the input was null.
129    */
130   @SuppressWarnings("unchecked")
131   public static <K,V> Map<K,V> addToMap(Map<K,V> appendTo, Object[] values, Class<K> keyType, Class<V> valueType, Type...valueTypeArgs) {
132      if (values == null)
133         return appendTo;
134      try {
135         Map<K,V> m = appendTo;
136         if (m == null)
137            m = new LinkedHashMap<>();
138         for (Object o : values) {
139            if (o != null) {
140               if (isObjectMap(o, false)) {
141                  for (Map.Entry<String,Object> e : new ObjectMap(o.toString()).entrySet())
142                     m.put(toType(e.getKey(), keyType), toType(e.getValue(), valueType, valueTypeArgs));
143               } else if (o instanceof Map) {
144                  for (Map.Entry<Object,Object> e : ((Map<Object,Object>)o).entrySet())
145                     m.put(toType(e.getKey(), keyType), toType(e.getValue(), valueType, valueTypeArgs));
146               } else {
147                  throw new FormattedRuntimeException("Invalid object type {0} passed to addToMap()", o.getClass().getName());
148               }
149            }
150         }
151         return m.isEmpty() ? null : m;
152      } catch (ParseException e) {
153         throw new RuntimeException(e);
154      }
155   }
156
157   /**
158    * Converts an object to the specified type.
159    *
160    * @param o The object to convert.
161    * @param type The type to covert to.
162    * @param args The type arguments for types of map or collection.
163    * @return The converted object.
164    */
165   public static <T> T toType(Object o, Class<T> type, Type...args) {
166      return ObjectUtils.toType(o, type, args);
167   }
168
169   /**
170    * Creates a new list from the specified collection.
171    *
172    * @param val The value to copy from.
173    * @return A new {@link ArrayList}, or <jk>null</jk> if the input was null.
174    */
175   public static <T> List<T> newList(Collection<T> val) {
176      if (val == null)
177         return null;
178      return new ArrayList<>(val);
179   }
180
181   /**
182    * Copies the specified values into an existing list.
183    *
184    * @param l
185    *    The list to add to.
186    *    <br>If <jk>null</jk>, a new {@link ArrayList} will be created.
187    * @param val The values to add.
188    * @return The list with values copied into it.
189    */
190   public static <T> List<T> addToList(List<T> l, Collection<T> val) {
191      if (val != null) {
192         if (l == null)
193            l = new ArrayList<>(val);
194         else
195            l.addAll(val);
196      }
197      return l;
198   }
199
200   /**
201    * Creates a new map from the specified map.
202    *
203    * @param val The value to copy from.
204    * @return A new {@link LinkedHashMap}, or <jk>null</jk> if the input was null.
205    */
206   public static <K,V> Map<K,V> newMap(Map<K,V> val) {
207      if (val == null)
208         return null;
209      return new LinkedHashMap<>(val);
210   }
211
212   /**
213    * Copies the specified values into an existing map.
214    *
215    * @param m
216    *    The map to add to.
217    *    <br>If <jk>null</jk>, a new {@link LinkedHashMap} will be created.
218    * @param val The values to add.
219    * @return The list with values copied into it.
220    */
221   public static <K,V> Map<K,V> addToMap(Map<K,V> m, Map<K,V> val) {
222      if (val != null) {
223         if (m == null)
224            m = new LinkedHashMap<>(val);
225         else
226            m.putAll(val);
227      }
228      return m;
229   }
230
231   /**
232    * Adds a single entry into an existing map.
233    *
234    * @param m
235    *    The map to add to.
236    *    <br>If <jk>null</jk>, a new {@link LinkedHashMap} will be created.
237    * @param key The entry key.
238    * @param value The entry value.
239    * @return The list with values copied into it.
240    */
241   public static <K,V> Map<K,V> addToMap(Map<K,V> m, K key, V value) {
242      if (m == null)
243         m = new LinkedHashMap<>();
244      m.put(key, value);
245      return m;
246   }
247
248   /**
249    * Creates a new map from the specified map.
250    *
251    * @param val The value to copy from.
252    * @param comparator The key comparator to use, or <jk>null</jk> to use natural ordering.
253    * @return A new {@link LinkedHashMap}, or <jk>null</jk> if the input was null.
254    */
255   public static <K,V> Map<K,V> newSortedMap(Map<K,V> val, Comparator<K> comparator) {
256      if (val == null)
257         return null;
258      Map<K,V> m = new TreeMap<>(comparator);
259      m.putAll(val);
260      return m;
261   }
262
263   /**
264    * Copies the specified values into an existing map.
265    *
266    * @param m
267    *    The map to add to.
268    *    <br>If <jk>null</jk>, a new {@link LinkedHashMap} will be created.
269    * @param val The values to add.
270    * @param comparator The key comparator to use, or <jk>null</jk> to use natural ordering.
271    * @return The list with values copied into it.
272    */
273   public static <K,V> Map<K,V> addToSortedMap(Map<K,V> m, Map<K,V> val, Comparator<K> comparator) {
274      if (val != null) {
275         if (m == null) {
276            m = new TreeMap<>(comparator);
277            m.putAll(val);
278         } else {
279            m.putAll(val);
280         }
281      }
282      return m;
283   }
284
285   /**
286    * Adds a single entry into an existing map.
287    *
288    * @param m
289    *    The map to add to.
290    *    <br>If <jk>null</jk>, a new {@link LinkedHashMap} will be created.
291    * @param key The entry key.
292    * @param value The entry value.
293    * @param comparator The key comparator to use, or <jk>null</jk> to use natural ordering.
294    * @return The list with values copied into it.
295    */
296   public static <K,V> Map<K,V> addToSortedMap(Map<K,V> m, K key, V value, Comparator<K> comparator) {
297      if (m == null)
298         m = new TreeMap<>(comparator);
299      m.put(key, value);
300      return m;
301   }
302}