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 java.lang.reflect.*;
016import java.util.*;
017
018import org.apache.juneau.*;
019import org.apache.juneau.parser.*;
020import org.apache.juneau.transform.*;
021
022/**
023 * Utility class for efficiently converting objects between types.
024 *
025 * <p>
026 * If the value isn't an instance of the specified type, then converts the value if possible.
027 *
028 * <p>
029 * The following conversions are valid:
030 * <table class='styled'>
031 *    <tr><th>Convert to type</th><th>Valid input value types</th><th>Notes</th></tr>
032 *    <tr>
033 *       <td>
034 *          A class that is the normal type of a registered {@link PojoSwap}.
035 *       </td>
036 *       <td>
037 *          A value whose class matches the transformed type of that registered {@link PojoSwap}.
038 *       </td>
039 *       <td>&nbsp;</td>
040 *    </tr>
041 *    <tr>
042 *       <td>
043 *          A class that is the transformed type of a registered {@link PojoSwap}.
044 *       </td>
045 *       <td>
046 *          A value whose class matches the normal type of that registered {@link PojoSwap}.
047 *       </td>
048 *       <td>&nbsp;</td>
049 *    </tr>
050 *    <tr>
051 *       <td>
052 *          {@code Number} (e.g. {@code Integer}, {@code Short}, {@code Float},...)
053 *          <br><code>Number.<jsf>TYPE</jsf></code> (e.g. <code>Integer.<jsf>TYPE</jsf></code>,
054 *          <code>Short.<jsf>TYPE</jsf></code>, <code>Float.<jsf>TYPE</jsf></code>,...)
055 *       </td>
056 *       <td>
057 *          {@code Number}, {@code String}, <jk>null</jk>
058 *       </td>
059 *       <td>
060 *          For primitive {@code TYPES}, <jk>null</jk> returns the JVM default value for that type.
061 *       </td>
062 *    </tr>
063 *    <tr>
064 *       <td>
065 *          {@code Map} (e.g. {@code Map}, {@code HashMap}, {@code TreeMap}, {@code ObjectMap})
066 *       </td>
067 *       <td>
068 *          {@code Map}
069 *       </td>
070 *       <td>
071 *          If {@code Map} is not constructible, a {@code ObjectMap} is created.
072 *       </td>
073 *    </tr>
074 *    <tr>
075 *       <td>
076 *          <c>Collection</c> (e.g. <c>List</c>, <c>LinkedList</c>, <c>HashSet</c>, <c>ObjectList</c>)
077 *       </td>
078 *       <td>
079 *          <c>Collection&lt;Object&gt;</c>
080 *          <br><c>Object[]</c>
081 *       </td>
082 *       <td>
083 *          If <c>Collection</c> is not constructible, a <c>ObjectList</c> is created.
084 *       </td>
085 *    </tr>
086 *    <tr>
087 *       <td>
088 *          <c>X[]</c> (array of any type X)
089 *       </td>
090 *       <td>
091 *          <c>List&lt;X&gt;</c>
092 *       </td>
093 *       <td>&nbsp;</td>
094 *    </tr>
095 *    <tr>
096 *       <td>
097 *          <c>X[][]</c> (multi-dimensional arrays)
098 *       </td>
099 *       <td>
100 *          <c>List&lt;List&lt;X&gt;&gt;</c>
101 *          <br><c>List&lt;X[]&gt;</c>
102 *          <br><c> List[]&lt;X&gt;</c>
103 *       </td>
104 *       <td>&nbsp;</td>
105 *    </tr>
106 *    <tr>
107 *       <td>
108 *          <c>Enum</c>
109 *       </td>
110 *       <td>
111 *          <c>String</c>
112 *       </td>
113 *       <td>&nbsp;</td>
114 *    </tr>
115 *    <tr>
116 *       <td>
117 *          Bean
118 *       </td>
119 *       <td>
120 *          <c>Map</c>
121 *       </td>
122 *       <td>&nbsp;</td>
123 *    </tr>
124 *    <tr>
125 *       <td>
126 *          <c>String</c>
127 *       </td>
128 *       <td>
129 *          Anything
130 *       </td>
131 *       <td>
132 *          Arrays are converted to JSON arrays
133 *       </td>
134 *    </tr>
135 *    <tr>
136 *       <td>
137 *          Anything with one of the following methods:
138 *          <br><code><jk>public static</jk> T fromString(String)</code>
139 *          <br><code><jk>public static</jk> T valueOf(String)</code>
140 *          <br><code><jk>public</jk> T(String)</code>
141 *       </td>
142 *       <td>
143 *          <c>String</c>
144 *       </td>
145 *       <td>
146 *          <br>
147 *       </td>
148 *    </tr>
149 * </table>
150 */
151public final class ObjectUtils {
152
153   // Session objects are usually not thread safe, but we're not using any feature
154   // of bean sessions that would cause thread safety issues.
155   private static final BeanSession session = BeanContext.DEFAULT.createSession();
156
157   /**
158    * Converts the specified object to the specified type.
159    *
160    * @param <T> The class type to convert the value to.
161    * @param value The value to convert.
162    * @param type The class type to convert the value to.
163    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
164    * @return The converted value.
165    */
166   public static <T> T toType(Object value, Class<T> type) {
167      return session.convertToType(value, type);
168   }
169
170
171   /**
172    * Converts the specified object to the specified type.
173    *
174    * @param <T> The class type to convert the value to.
175    * @param value The value to convert.
176    * @param type The class type to convert the value to.
177    * @param args The type arguments.
178    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
179    * @return The converted value.
180    */
181   public static <T> T toType(Object value, Class<T> type, Type...args) {
182      return session.convertToType(value, type, args);
183   }
184
185   /**
186    * Returns <jk>true</jk> if the specified objects are equal.
187    *
188    * <p>
189    * Gracefully handles <jk>null</jk>s.
190    *
191    * @param o1 Object #1
192    * @param o2 Object #2
193    * @return <jk>true</jk> if the objects are equal or both <jk>null</jk>.
194    */
195   public static boolean equals(Object o1, Object o2) {
196      if (o1 == null && o2 == null)
197         return true;
198      if (o1 == null || o2 == null)
199         return false;
200      return o1.equals(o2);
201   }
202
203   /**
204    * Returns <jk>true</jk> if the specified object is empty.
205    *
206    * <p>
207    * Return <jk>true</jk> if the value is any of the following:
208    * <ul>
209    *    <li><jk>null</jk>
210    *    <li>An empty Collection
211    *    <li>An empty Map
212    *    <li>An empty array
213    *    <li>An empty CharSequence
214    *    <li>An empty String when serialized to a string using {@link Object#toString()}.
215    * </ul>
216    *
217    * @param o The object to test.
218    * @return <jk>true</jk> if the specified object is empty.
219    */
220   @SuppressWarnings("rawtypes")
221   public static boolean isEmpty(Object o) {
222      if (o == null)
223         return true;
224      if (o instanceof Collection)
225         return ((Collection)o).isEmpty();
226      if (o instanceof Map)
227         return ((Map)o).isEmpty();
228      if (o.getClass().isArray())
229         return (Array.getLength(o) == 0);
230      return o.toString().isEmpty();
231   }
232
233   /**
234    * Returns the first non-null value in the specified array
235    *
236    * @param t The values to check.
237    * @return The first non-null value, or <jk>null</jk> if the array is null or empty or contains only <jk>null</jk> values.
238    */
239   @SafeVarargs
240   public static <T> T firstNonNull(T... t) {
241      if (t != null)
242         for (T tt : t)
243            if (tt != null)
244               return tt;
245      return null;
246   }
247
248   /**
249    * Converts an object to a Boolean.
250    *
251    * @param o The object to convert.
252    * @return The converted object.
253    */
254   public static Boolean toBoolean(Object o) {
255      return toType(o, Boolean.class);
256   }
257
258   /**
259    * Converts an object to an Integer.
260    *
261    * @param o The object to convert.
262    * @return The converted object.
263    */
264   public static Integer toInteger(Object o) {
265      return toType(o, Integer.class);
266   }
267
268   /**
269    * Converts an object to a Number.
270    *
271    * @param o The object to convert.
272    * @return The converted object.
273    */
274   public static Number toNumber(Object o) {
275      if (o == null)
276         return null;
277      if (o instanceof Number)
278         return (Number)o;
279      try {
280         return StringUtils.parseNumber(o.toString(), null);
281      } catch (ParseException e) {
282         throw new RuntimeException(e);
283      }
284   }
285
286   /**
287    * Returns the enum names for the specified enum class.
288    *
289    * @param c The enum class.
290    * @return A modifiable list of all names for that class.
291    */
292   @SuppressWarnings("unchecked")
293   public static Enum<?>[] getEnumConstants(Class<?> c) {
294      return ((Class<Enum<?>>)c).getEnumConstants();
295   }
296
297   /**
298    * If the specified object is an instance of the specified class, casts it to that type.
299    *
300    * @param o The object to cast.
301    * @param c The class to cast to.
302    * @return The cast object, or <jk>null</jk> if the object wasn't an instance of the specified class.
303    */
304   @SuppressWarnings("unchecked")
305   public static <T> T castOrNull(Object o, Class<T> c) {
306      if (c.isInstance(o))
307         return (T)o;
308      return null;
309   }
310
311   /**
312    * Returns the first non-zero value in the list of ints.
313    *
314    * @param ints The ints to check.
315    * @return The first non-zero value, or <c>0</c> if they were all zero.
316    */
317   public static int firstNonZero(int...ints) {
318      for (int i : ints)
319         if (i != 0)
320            return i;
321      return 0;
322   }
323
324   /**
325    * Returns the first non-empty value in the list of objects.
326    *
327    * @param o The objects to check.
328    * @return The first object whose call to {@link #isEmpty(Object)} returns <jk>false</jk>, otherwise <jk>null</jk>.
329    */
330   @SafeVarargs
331   public static <T> T firstNonEmpty(T...o) {
332      for (T oo : o)
333         if (! isEmpty(oo))
334            return oo;
335      return null;
336   }
337
338   /**
339    * Compares two objects for equality.
340    *
341    * <p>
342    * Nulls are always considered less-than unless both are null.
343    *
344    * @param o1 Object 1.
345    * @param o2 Object 2.
346    * @return
347    *    <c>-1</c>, <c>0</c>, or <c>1</c> if <c>o1</c> is less-than, equal, or greater-than <c>o2</c>.
348    * <br><c>0</c> if objects are not of the same type or do not implement the {@link Comparable} interface.
349    */
350   @SuppressWarnings({ "rawtypes", "unchecked" })
351   public static int compare(Object o1, Object o2) {
352      if (o1 == null) {
353         if (o2 == null)
354            return 0;
355         return -1;
356      } else if (o2 == null) {
357         return 1;
358      }
359
360      if (o1.getClass() == o2.getClass() && o1 instanceof Comparable)
361         return ((Comparable)o1).compareTo(o2);
362
363      return 0;
364   }
365
366   /**
367    * Compare two integers numerically.
368    *
369    * @param i1 Integer #1
370    * @param i2 Integer #2
371    * @return
372    *    The value <c>0</c> if Integer #1 is equal to Integer #2; a value less than <c>0</c> if
373    *    Integer #1 numerically less than Integer #2; and a value greater than <c>0</c> if Integer #1 is
374    *    numerically greater than Integer #2 (signed comparison).
375    */
376   public static final int compare(int i1, int i2) {
377      return (i1<i2 ? -1 : (i1==i2 ? 0 : 1));
378   }
379}