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 == null ? new ArrayList<T>() : appendTo;
094         for (Object o : values) {
095            if (o != null) {
096               if (isObjectList(o, false)) {
097                  for (Object o2 : new ObjectList(o.toString()))
098                     l.add(toType(o2, type, args));
099               } else if (o instanceof Collection) {
100                  for (Object o2 : (Collection<?>)o)
101                     l.add(toType(o2, type, args));
102               } else if (o.getClass().isArray()) {
103                  for (int i = 0; i < Array.getLength(o); i++)
104                     l.add(toType(Array.get(o, i), type, args));
105               } else {
106                  l.add(toType(o, type, args));
107               }
108            }
109         }
110         return l.isEmpty() ? null : l;
111      } catch (ParseException e) {
112         throw new RuntimeException(e);
113      }
114   }
115
116   /**
117    * Adds a set of values to an existing map.
118    *
119    * @param appendTo
120    *    The map to append to.
121    *    <br>If <jk>null</jk>, a new {@link LinkedHashMap} will be created.
122    * @param values The values to add.
123    * @param keyType The data type of the keys.
124    * @param valueType The data type of the values.
125    * @param valueTypeArgs The generic type arguments of the data type of the values.
126    * @return The converted value, or <jk>null</jk> if the input was null.
127    */
128   @SuppressWarnings("unchecked")
129   public static <K,V> Map<K,V> addToMap(Map<K,V> appendTo, Object[] values, Class<K> keyType, Class<V> valueType, Type...valueTypeArgs) {
130      if (values == null)
131         return appendTo;
132      try {
133         Map<K,V> m = appendTo == null ? new LinkedHashMap<K,V>() : appendTo;
134         for (Object o : values) {
135            if (o != null) {
136               if (isObjectMap(o, false)) {
137                  for (Map.Entry<String,Object> e : new ObjectMap(o.toString()).entrySet())
138                     m.put(toType(e.getKey(), keyType), toType(e.getValue(), valueType, valueTypeArgs));
139               } else if (o instanceof Map) {
140                  for (Map.Entry<Object,Object> e : ((Map<Object,Object>)o).entrySet())
141                     m.put(toType(e.getKey(), keyType), toType(e.getValue(), valueType, valueTypeArgs));
142               } else {
143                  throw new FormattedRuntimeException("Invalid object type {0} passed to addToMap()", o.getClass().getName());
144               }
145            }
146         }
147         return m.isEmpty() ? null : m;
148      } catch (ParseException e) {
149         throw new RuntimeException(e);
150      }
151   }
152
153   /**
154    * Converts an object to the specified type.
155    *
156    * @param o The object to convert.
157    * @param type The type to covert to.
158    * @param args The type arguments for types of map or collection.
159    * @return The converted object.
160    */
161   public static <T> T toType(Object o, Class<T> type, Type...args) {
162      return ObjectUtils.toType(o, type, args);
163   }
164
165   /**
166    * Creates a new list from the specified collection.
167    *
168    * @param val The value to copy from.
169    * @return A new {@link ArrayList}, or <jk>null</jk> if the input was null.
170    */
171   public static <T> List<T> newList(Collection<T> val) {
172      if (val == null)
173         return null;
174      return new ArrayList<>(val);
175   }
176
177   /**
178    * Copies the specified values into an existing list.
179    *
180    * @param l
181    *    The list to add to.
182    *    <br>If <jk>null</jk>, a new {@link ArrayList} will be created.
183    * @param val The values to add.
184    * @return The list with values copied into it.
185    */
186   public static <T> List<T> addToList(List<T> l, Collection<T> val) {
187      if (val != null) {
188         if (l == null)
189            l = new ArrayList<>(val);
190         else
191            l.addAll(val);
192      }
193      return l;
194   }
195
196   /**
197    * Creates a new map from the specified map.
198    *
199    * @param val The value to copy from.
200    * @return A new {@link LinkedHashMap}, or <jk>null</jk> if the input was null.
201    */
202   public static <K,V> Map<K,V> newMap(Map<K,V> val) {
203      if (val == null)
204         return null;
205      return new LinkedHashMap<>(val);
206   }
207
208   /**
209    * Copies the specified values into an existing map.
210    *
211    * @param m
212    *    The map to add to.
213    *    <br>If <jk>null</jk>, a new {@link LinkedHashMap} will be created.
214    * @param val The values to add.
215    * @return The list with values copied into it.
216    */
217   public static <K,V> Map<K,V> addToMap(Map<K,V> m, Map<K,V> val) {
218      if (val != null) {
219         if (m == null)
220            m = new LinkedHashMap<>(val);
221         else
222            m.putAll(val);
223      }
224      return m;
225   }
226
227   /**
228    * Adds a single entry into an existing map.
229    *
230    * @param m
231    *    The map to add to.
232    *    <br>If <jk>null</jk>, a new {@link LinkedHashMap} will be created.
233    * @param key The entry key.
234    * @param value The entry value.
235    * @return The list with values copied into it.
236    */
237   public static <K,V> Map<K,V> addToMap(Map<K,V> m, K key, V value) {
238      if (m == null)
239         m = new LinkedHashMap<>();
240      m.put(key, value);
241      return m;
242   }
243
244   /**
245    * Creates a new map from the specified map.
246    *
247    * @param val The value to copy from.
248    * @param comparator The key comparator to use, or <jk>null</jk> to use natural ordering.
249    * @return A new {@link LinkedHashMap}, or <jk>null</jk> if the input was null.
250    */
251   public static <K,V> Map<K,V> newSortedMap(Map<K,V> val, Comparator<K> comparator) {
252      if (val == null)
253         return null;
254      Map<K,V> m = new TreeMap<>(comparator);
255      m.putAll(val);
256      return m;
257   }
258
259   /**
260    * Copies the specified values into an existing map.
261    *
262    * @param m
263    *    The map to add to.
264    *    <br>If <jk>null</jk>, a new {@link LinkedHashMap} will be created.
265    * @param val The values to add.
266    * @param comparator The key comparator to use, or <jk>null</jk> to use natural ordering.
267    * @return The list with values copied into it.
268    */
269   public static <K,V> Map<K,V> addToSortedMap(Map<K,V> m, Map<K,V> val, Comparator<K> comparator) {
270      if (val != null) {
271         if (m == null) {
272            m = new TreeMap<>(comparator);
273            m.putAll(val);
274         } else {
275            m.putAll(val);
276         }
277      }
278      return m;
279   }
280
281   /**
282    * Adds a single entry into an existing map.
283    *
284    * @param m
285    *    The map to add to.
286    *    <br>If <jk>null</jk>, a new {@link LinkedHashMap} will be created.
287    * @param key The entry key.
288    * @param value The entry value.
289    * @param comparator The key comparator to use, or <jk>null</jk> to use natural ordering.
290    * @return The list with values copied into it.
291    */
292   public static <K,V> Map<K,V> addToSortedMap(Map<K,V> m, K key, V value, Comparator<K> comparator) {
293      if (m == null)
294         m = new TreeMap<>(comparator);
295      m.put(key, value);
296      return m;
297   }
298}